使用jdk动态代理之后,不能获取目标方法上的注解
问题描述
在使用jdk动态代理之后,竟然获取不到目标方法上的注解?举个例子,有一个接口HelloService
,它的一个实现类HelloServiceImpl
,在方法service
上有一个自定义的注解MyAnnotation
,通过jdk动态代理,获取不到这个MyAnnotation
这个注解
场景还原
1.定义接口HelloServie
:
public interface HelloService {
public void service();
}
2.实现类HelloServiceImpl
:
public class HelloServiceImpl implements HelloService{
@MyAnnotation
@Override
public void service() {
System.out.println("hello");
}
}
3.定义注解MyAnnotation
:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
}
4.jdk动态代理工厂MyProxyFactory
:
public class MyProxyFactory implements InvocationHandler {
private Object target;
public Object createProxy(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
boolean hasProxyMyAnnotation = method.isAnnotationPresent(MyAnnotation.class);
System.out.println("find myAnnotation from proxy : " + hasProxyMyAnnotation );
Method targetMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes());
boolean hasTargetMyAnnotation = false;
// targetMyAnnotation = targetMethod.isAnnotationPresent(MyAnnotation.class);
// hasTargetMyAnnotation = DynamicProxyAnnotationUtil.findAnnotationFromProxy(MyAnnotation.class, target, method);
// System.out.println("find myAnnotation from targetMethod : " + hasTargetMyAnnotation );
System.out.println("do something before....");
Object result = method.invoke(target, args);
System.out.println("do something after ....");
return result;
}
}
6.测试:
public static void main(String[] args) {
HelloService service = (HelloService) new MyProxyFactory().createProxy(new HelloServiceImpl());
service.service();
}
7.运行结果:
find myAnnotation from proxy : false
do something before....
hello
do something after ....
可以发现,虽然在实现类中加了自定义注解,但通过jdk动态代理并不能获取实现类方法上的注解
但是,如果将自定义注解MyAnnotation
放在接口定义HelloServie
上:
运行结果:
find myAnnotation from proxy : true
do something before....
hello
do something after ....
神奇,意外呀,这样竟然获取到了!!
解决方案
那我非要实现类的方法上获取到MyAnnotation
注解呢,也是有办法的。打开注释:
// hasTargetMyAnnotation = DynamicProxyAnnotationUtil.findAnnotationFromProxy(MyAnnotation.class, target, method);
// System.out.println("find myAnnotation from targetMethod : " + hasTargetMyAnnotation );
DynamicProxyAnnotationUtil
工具:
public class DynamicProxyAnnotationUtil {
public static boolean findAnnotationFromProxy(Class<?> cusAnnotation, Object target, Method method) throws NoSuchMethodException {
Annotation[] annotations = target.getClass().getMethod(method.getName(), method.getParameterTypes()).getAnnotations();
boolean hasAnnotation = Arrays.stream(annotations).filter(annotation -> {
return annotation.annotationType().isAssignableFrom(cusAnnotation);
}).count() > 0;
return hasAnnotation;
}
}
再次运行:
find myAnnotation from proxy : false
find myAnnotation from targetMethod : true
do something before....
hello
do something after ....
Process finished with exit code 0
扩展
如果jdk动态代理会出现这种情况,那cglib类代理呢?
cglig代理
1.创建类HomeService
:
public class HomeService {
@MyAnnotation
public void index(){
System.out.println("index...");
}
}
2.cglib代理工厂ClzProxyFactory
:
public class ClzProxyFactory implements MethodInterceptor {
private Object target;
public ClzProxyFactory(Object target) {
this.target = target;
}
public Object createProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("has annotation: " + method.isAnnotationPresent(MyAnnotation.class));
System.out.println("do something before..");
Object result = methodProxy.invoke(target, args);
System.out.println("do something after..");
return result;
}
}
3.测试:
public static void main(String[] args) {
HomeService homeService = new HomeService();
HomeService proxy = (HomeService) new ClzProxyFactory(homeService).createProxy();
proxy.index();
}
4.运行结果:
has annotation: true
do something before..
index...
do something after..
可以发现通过cglib方式实现的代理,可以正常的获取到目标方法上的注解