开发过程当中部分场景需要获取到方法或类上的注解,但是经常会有无法渠道注解的情况,这种情况很可能是该注解所在的类是一个代理类,比如被AOP动态代理【注意:通过】。本文以CGLIB为例,说明为什么无法取到方法或类上的注解,还有如何取到注解。
如果是增强的对象,比如JDK动态代理和CGLIB动态代理。因为CGLIB动态代理生成了一个新的继承了动态
原因是:
1.被增强的类
package com.changshin.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface WhiteList {
}
package com.changshin.component;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
@Slf4j
public class WhiteListAspect {
@Pointcut("@annotation(com.changshin.annotation.WhiteList)")
public void whiteList(){
log.info("空实现");
}
@Before("whiteList()")
public void start(){
log.info("对客户白名单进行校验1");
}
@AfterReturning("whiteList()")
public void end(){
log.info("对客户白名单进行校验2");
}
}
package com.changshin.web;
import com.changshin.annotation.WhiteList;
import com.changshin.entity.dto.request.UserInfoRequest;
import com.changshin.entity.dto.response.UserInfoResponse;
import com.changshin.lock.BsnService;
import com.changshin.lock.BusinessLockEnum;
import com.changshin.lock.BusinessLockVO;
import com.changshin.lock.LockService;
import com.changshin.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@RestController
public class UserApi {
private static final Logger log = LoggerFactory.getLogger(UserApi.class);
@Autowired
private UserService userService;
@Autowired
private LockService lockService;
@Autowired
private BsnService bsnService;
@Autowired
private ApplicationContext applicationContext;
@PostMapping(value = "user/queryUserName")
public UserInfoResponse queryUserNameById(@RequestBody UserInfoRequest request){
log.info("查询用户姓名请求参数",request);
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext,UserService.class);
Class<?> userServiceBean = applicationContext.getType(beanNames[0]);
Method[] method1s = userServiceBean.getMethods();
for (Method method:method1s) {
if (method.isAnnotationPresent(WhiteList.class)){
System.out.println("userServiceBean111");
}
}
Class<?> userServiceBeanTarget = null;
//获取代理类代理的目标类
if(!Proxy.isProxyClass(userServiceBean)){
userServiceBeanTarget = ClassUtils.getUserClass(userServiceBean);
}
Method[] method2s = userServiceBeanTarget.getMethods();
for (Method method:method2s) {
if (method.isAnnotationPresent(WhiteList.class)){
System.out.println("userServiceBeanTarget222");
}
}
return null;
}
}
发现:
1.userServiceBean是userService进行CGLIB增强后的实例,非userService类型的
2.userServiceBeanTarget是userService类型的实例。
执行API请求代码,发现打印了userServiceBeanTarget222没有打印userServiceBean111。说明
userServiceBean没有获取到注解信息,userServiceBeanTarget获取到了注解信息。
也就是说增强类方法列表中没有获取到注解信息,增强类的目标类的方法列表中得到了注解信息。
此时userServiceBean.getMethods()实际上调用的是增强类的getMethods方法。对于CGLIB增强的类,需要先获取获取到增强类的目标类,获取到目标类后就可以通过getMethods方法获取到方法,通过获取方法上的注解方法最终获取到方法上的注解。