天天看點

Spring AOP 切換接口實作類

此執行個體為,使用Spring切面,将接口的部分方法替換為其他執行個體的同名同參方法

每一個接口類建立對應一個RPC Client的使用,業務場景為對特定辨別使用者,使用新的RPC Client的部分方法。

AOP 代理

Spring AOP 預設将标準

JDK動态代理

用于 AOP 代理。這使得可以代理任何接口(或一組接口)。

Spring AOP 也可以使用

CGLIB

代理。這對于代理類而不是接口是必需的。如果業務對象未實作接口,則預設情況下使用

CGLIB

。最好的做法是對接口進行程式設計,而不是對類進行程式設計。業務類通常将實作一個或多個業務接口。在某些情況下(可能極少發生),您需要建議未在接口上聲明的方法,或者需要将代理對象作為具體類型傳遞給方法,則可以使用強制使用CGLIB。

重要的是要掌握 Spring AOP 是基于“代理”的事實。有關此實作細節實際含義的徹底檢查,請參見了解AOP代理。

設計思路

  1. 使用Spring Aspcct Around切面,切點為原接口的所有方法
  2. 在對應配置的方法,對特定辨別使用者替換為新接口
  3. 通過新接口的執行個體及方法,動态代理生成結果

代碼實作

ShareService

batchGetShare()

listShare()

,對特定辨別使用者替換為

ShareProxyService

的實作

@Aspect
@Component
public class ShareProxyAspect {

    private static Logger logger = LoggerFactory.getLogger(ShareProxyAspect.class);

    @Autowired
    private ShareProxyService shareProxyService;

    @Autowired
    private IdentityService identityService;

    private static List<String> proxyMethodName = Lists.newArrayList(
            "batchGetShare",
            "listShare"
    );

    /**
     * 攔截ShareService
     */
    @Around(value = "execution(* com.example.api.ShareService.*(..))")
    public Object shareProxy(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        try {
            Object[] args = proceedingJoinPoint.getArgs();
            MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
            Method method = signature.getMethod();

            String methodName = method.getName();
            if (proxyMethodName.contains(methodName)) {
                String uid = UserContext.getLoginUid();
                if (identityService.getIdentityFlag(uid)) {
                    Method[] methods = shareProxyService.getClass().getMethods();
                    Method proxyMethod = getMethodByName(methods, methodName);
                    logger.info("ShareProxyAspect invoke,uid={} method={} args={}", uid, methodName, args);
                    return proxyMethod.invoke(moneyShareProxyService, args);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
    }

    private Method getMethodByName(Method[] methods, String methodName) {
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                return method;
            }
        }
        // ShareProxyService拓展方法保證不會出現空
        return null;
    }
}