同事设置了个注解,想用Spring获取的Bean来找到Class获取注解
但是发现是空的,在查看的Spring返回Bean之后,发现这个Bean对象并不是原生的实例
而是被Spring代理增强的代理对象
为了复现这个问题,这里我写了个样例:
首先有两个样例注解(一个叫A 一个叫B,B也是一样的就不写了):
package cn.cloud9.test.reflect.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface AnnoA { String value() default ""; }
再写一个A类,里面就是一个方法没别的
打上A和B注解
package cn.cloud9.test.reflect.sample; import cn.cloud9.test.reflect.annotation.AnnoA; import cn.cloud9.test.reflect.annotation.AnnoB; @AnnoA @AnnoB public class A { public void fun() { System.out.println("A.fun executed... "); } }
为了模拟Spring代理的场景,这里要引入CGLIB组件
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency>
编写样例代码:
package cn.cloud9.test.reflect; import cn.cloud9.test.reflect.sample.A; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import org.junit.Test; import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class ReflectAndAnnotation { @Test public void simpleGet() throws Exception { Class<?> aClass = Class.forName("cn.cloud9.test.reflect.sample.A"); Annotation[] annotations = aClass.getAnnotations(); Class<?> superclass = aClass.getSuperclass(); System.out.println(superclass); for (Annotation annotation : annotations) { System.out.println(annotation.toString()); } } }
执行之后,自然而然的就能得到我们设置的注解:
"C:Program FilesJavajdk1.8.0_301injava.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2021.2.2libidea_rt.jar=57548:C:Program FilesJetBrainsIntelliJ IDEA 2021.2.2in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJetBrainsIntelliJ IDEA 2021.2.2libidea_rt.jar;C:Program FilesJetBrainsIntelliJ IDEA 2021.2.2pluginsjunitlibjunit5-rt.jar;C:Program FilesJetBrainsIntelliJ IDEA 2021.2.2pluginsjunitlibjunit-rt.jar;C:Program FilesJavajdk1.8.0_301jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_301jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_301jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_301jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_301jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_301jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_301jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_301jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_301jrelibext ashorn.jar;C:Program FilesJavajdk1.8.0_301jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_301jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_301jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_301jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_301jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_301jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_301jrelibjce.jar;C:Program FilesJavajdk1.8.0_301jrelibjfr.jar;C:Program FilesJavajdk1.8.0_301jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_301jrelibjsse.jar;C:Program FilesJavajdk1.8.0_301jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_301jrelibplugin.jar;C:Program FilesJavajdk1.8.0_301jrelib esources.jar;C:Program FilesJavajdk1.8.0_301jrelib t.jar;C:UsersCloud9IdeaProjectsEveryThing-Framework arget est-classes;C:UsersCloud9IdeaProjectsEveryThing-Framework argetclasses;D:Maven Local Repositoryorgapachecuratorcurator-framework5.2.0curator-framework-5.2.0.jar;D:Maven Local Repositoryorgapachecuratorcurator-client5.2.0curator-client-5.2.0.jar;D:Maven Local Repositoryorgapachezookeeperzookeeper3.6.3zookeeper-3.6.3.jar;D:Maven Local Repositoryorgapachezookeeperzookeeper-jute3.6.3zookeeper-jute-3.6.3.jar;D:Maven Local Repositoryorgapacheyetusaudience-annotations .5.0audience-annotations-0.5.0.jar;D:Maven Local Repositoryio etty etty-handler4.1.63.Final etty-handler-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-common4.1.63.Final etty-common-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-resolver4.1.63.Final etty-resolver-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-buffer4.1.63.Final etty-buffer-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-transport4.1.63.Final etty-transport-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-codec4.1.63.Final etty-codec-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-transport-native-epoll4.1.63.Final etty-transport-native-epoll-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-transport-native-unix-common4.1.63.Final etty-transport-native-unix-common-4.1.63.Final.jar;D:Maven Local Repositoryorgapachecuratorcurator-recipes5.2.0curator-recipes-5.2.0.jar;D:Maven Local Repositorycommons-iocommons-io2.11.0commons-io-2.11.0.jar;D:Maven Local Repositorycommons-beanutilscommons-beanutils1.7.0commons-beanutils-1.7.0.jar;D:Maven Local Repositorycommons-loggingcommons-logging1.0.3commons-logging-1.0.3.jar;D:Maven Local Repositoryorgjavassistjavassist3.26.0-GAjavassist-3.26.0-GA.jar;D:Maven Local Repositorycomalibabafastjson1.2.78fastjson-1.2.78.jar;D:Maven Local Repositoryjavaxservletjavax.servlet-api4.0.1javax.servlet-api-4.0.1.jar;D:Maven Local Repositoryjavaxservletjstl1.2jstl-1.2.jar;D:Maven Local Repositoryjavaxservletjspjavax.servlet.jsp-api2.3.3javax.servlet.jsp-api-2.3.3.jar;D:Maven Local Repositoryorg eflections eflections .9.11 eflections-0.9.11.jar;D:Maven Local Repositorycomgoogleguavaguava20.0guava-20.0.jar;D:Maven Local Repositorymysqlmysql-connector-java8.0.25mysql-connector-java-8.0.25.jar;D:Maven Local Repositorycomgoogleprotobufprotobuf-java3.11.4protobuf-java-3.11.4.jar;D:Maven Local Repositoryiojsonwebtokenjjwt .9.1jjwt-0.9.1.jar;D:Maven Local Repositorycomfasterxmljacksoncorejackson-databind2.9.6jackson-databind-2.9.6.jar;D:Maven Local Repositorycomfasterxmljacksoncorejackson-annotations2.9.0jackson-annotations-2.9.0.jar;D:Maven Local Repositorycomfasterxmljacksoncorejackson-core2.9.6jackson-core-2.9.6.jar;D:Maven Local Repositoryorgapachehttpcomponentshttpclient4.5.13httpclient-4.5.13.jar;D:Maven Local Repositoryorgapachehttpcomponentshttpcore4.4.13httpcore-4.4.13.jar;D:Maven Local Repositorycommons-codeccommons-codec1.11commons-codec-1.11.jar;D:Maven Local Repositoryorgapachehttpcomponentshttpmime4.5.13httpmime-4.5.13.jar;D:Maven Local Repositoryjunitjunit4.12junit-4.12.jar;D:Maven Local Repositoryorghamcresthamcrest-core1.3hamcrest-core-1.3.jar;D:Maven Local Repositoryorgslf4jslf4j-api1.7.32slf4j-api-1.7.32.jar;D:Maven Local Repositoryorgslf4jslf4j-log4j121.7.32slf4j-log4j12-1.7.32.jar;D:Maven Local Repositorylog4jlog4j1.2.17log4j-1.2.17.jar;D:Maven Local Repositorycglibcglib2.2.2cglib-2.2.2.jar;D:Maven Local Repositoryasmasm3.3.1asm-3.3.1.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 cn.cloud9.test.reflect.ReflectAndAnnotation,simpleGet class java.lang.Object @cn.cloud9.test.reflect.annotation.AnnoA(value=) @cn.cloud9.test.reflect.annotation.AnnoB(value=) Process finished with exit code 0
那么在调用CGLIB的增强代理之后:
package cn.cloud9.test.reflect; import cn.cloud9.test.reflect.sample.A; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import org.junit.Test; import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class ReflectAndAnnotation { @Test public void simpleGet() throws Exception { Class<?> aClass = Class.forName("cn.cloud9.test.reflect.sample.A"); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(aClass); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before method run..."); Object result = proxy.invokeSuper(obj, args); System.out.println("after method run..."); return result; } }); A proxyA = (A) enhancer.create(); proxyA.fun(); Class<? extends A> proxyAClass = proxyA.getClass(); System.out.println(proxyAClass); for (Annotation annotation : proxyAClass.getAnnotations()) { System.out.println(annotation); } } }
执行发现,我们注解获取不到了
"C:Program FilesJavajdk1.8.0_301injava.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2021.2.2libidea_rt.jar=57581:C:Program FilesJetBrainsIntelliJ IDEA 2021.2.2in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJetBrainsIntelliJ IDEA 2021.2.2libidea_rt.jar;C:Program FilesJetBrainsIntelliJ IDEA 2021.2.2pluginsjunitlibjunit5-rt.jar;C:Program FilesJetBrainsIntelliJ IDEA 2021.2.2pluginsjunitlibjunit-rt.jar;C:Program FilesJavajdk1.8.0_301jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_301jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_301jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_301jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_301jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_301jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_301jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_301jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_301jrelibext ashorn.jar;C:Program FilesJavajdk1.8.0_301jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_301jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_301jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_301jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_301jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_301jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_301jrelibjce.jar;C:Program FilesJavajdk1.8.0_301jrelibjfr.jar;C:Program FilesJavajdk1.8.0_301jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_301jrelibjsse.jar;C:Program FilesJavajdk1.8.0_301jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_301jrelibplugin.jar;C:Program FilesJavajdk1.8.0_301jrelib esources.jar;C:Program FilesJavajdk1.8.0_301jrelib t.jar;C:UsersCloud9IdeaProjectsEveryThing-Framework arget est-classes;C:UsersCloud9IdeaProjectsEveryThing-Framework argetclasses;D:Maven Local Repositoryorgapachecuratorcurator-framework5.2.0curator-framework-5.2.0.jar;D:Maven Local Repositoryorgapachecuratorcurator-client5.2.0curator-client-5.2.0.jar;D:Maven Local Repositoryorgapachezookeeperzookeeper3.6.3zookeeper-3.6.3.jar;D:Maven Local Repositoryorgapachezookeeperzookeeper-jute3.6.3zookeeper-jute-3.6.3.jar;D:Maven Local Repositoryorgapacheyetusaudience-annotations .5.0audience-annotations-0.5.0.jar;D:Maven Local Repositoryio etty etty-handler4.1.63.Final etty-handler-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-common4.1.63.Final etty-common-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-resolver4.1.63.Final etty-resolver-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-buffer4.1.63.Final etty-buffer-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-transport4.1.63.Final etty-transport-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-codec4.1.63.Final etty-codec-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-transport-native-epoll4.1.63.Final etty-transport-native-epoll-4.1.63.Final.jar;D:Maven Local Repositoryio etty etty-transport-native-unix-common4.1.63.Final etty-transport-native-unix-common-4.1.63.Final.jar;D:Maven Local Repositoryorgapachecuratorcurator-recipes5.2.0curator-recipes-5.2.0.jar;D:Maven Local Repositorycommons-iocommons-io2.11.0commons-io-2.11.0.jar;D:Maven Local Repositorycommons-beanutilscommons-beanutils1.7.0commons-beanutils-1.7.0.jar;D:Maven Local Repositorycommons-loggingcommons-logging1.0.3commons-logging-1.0.3.jar;D:Maven Local Repositoryorgjavassistjavassist3.26.0-GAjavassist-3.26.0-GA.jar;D:Maven Local Repositorycomalibabafastjson1.2.78fastjson-1.2.78.jar;D:Maven Local Repositoryjavaxservletjavax.servlet-api4.0.1javax.servlet-api-4.0.1.jar;D:Maven Local Repositoryjavaxservletjstl1.2jstl-1.2.jar;D:Maven Local Repositoryjavaxservletjspjavax.servlet.jsp-api2.3.3javax.servlet.jsp-api-2.3.3.jar;D:Maven Local Repositoryorg eflections eflections .9.11 eflections-0.9.11.jar;D:Maven Local Repositorycomgoogleguavaguava20.0guava-20.0.jar;D:Maven Local Repositorymysqlmysql-connector-java8.0.25mysql-connector-java-8.0.25.jar;D:Maven Local Repositorycomgoogleprotobufprotobuf-java3.11.4protobuf-java-3.11.4.jar;D:Maven Local Repositoryiojsonwebtokenjjwt .9.1jjwt-0.9.1.jar;D:Maven Local Repositorycomfasterxmljacksoncorejackson-databind2.9.6jackson-databind-2.9.6.jar;D:Maven Local Repositorycomfasterxmljacksoncorejackson-annotations2.9.0jackson-annotations-2.9.0.jar;D:Maven Local Repositorycomfasterxmljacksoncorejackson-core2.9.6jackson-core-2.9.6.jar;D:Maven Local Repositoryorgapachehttpcomponentshttpclient4.5.13httpclient-4.5.13.jar;D:Maven Local Repositoryorgapachehttpcomponentshttpcore4.4.13httpcore-4.4.13.jar;D:Maven Local Repositorycommons-codeccommons-codec1.11commons-codec-1.11.jar;D:Maven Local Repositoryorgapachehttpcomponentshttpmime4.5.13httpmime-4.5.13.jar;D:Maven Local Repositoryjunitjunit4.12junit-4.12.jar;D:Maven Local Repositoryorghamcresthamcrest-core1.3hamcrest-core-1.3.jar;D:Maven Local Repositoryorgslf4jslf4j-api1.7.32slf4j-api-1.7.32.jar;D:Maven Local Repositoryorgslf4jslf4j-log4j121.7.32slf4j-log4j12-1.7.32.jar;D:Maven Local Repositorylog4jlog4j1.2.17log4j-1.2.17.jar;D:Maven Local Repositorycglibcglib2.2.2cglib-2.2.2.jar;D:Maven Local Repositoryasmasm3.3.1asm-3.3.1.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 cn.cloud9.test.reflect.ReflectAndAnnotation,simpleGet before method run... A.fun executed... after method run... class cn.cloud9.test.reflect.sample.A$$EnhancerByCGLIB$$fe34985a Process finished with exit code 0
为什么获取不到?
因为 这个是代理的对象,那么代理对象也应该由一个类来创建
这个类是代理对象类 class cn.cloud9.test.reflect.sample.A$$EnhancerByCGLIB$$fe34985a ,那么代理对象类会有我们设置的注解吗?
结果是没有的,但是根据CGLIB代理的实现原理,CGLIB代理原理是通过继承实现的,所以我们是不是可以通过代理类向上找父类来获取?
下面就是对猜想的测试:
package cn.cloud9.test.reflect; import cn.cloud9.test.reflect.sample.A; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import org.junit.Test; import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class ReflectAndAnnotation { @Test public void simpleGet() throws Exception { Class<?> aClass = Class.forName("cn.cloud9.test.reflect.sample.A"); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(aClass); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before method run..."); Object result = proxy.invokeSuper(obj, args); System.out.println("after method run..."); return result; } }); A proxyA = (A) enhancer.create(); proxyA.fun(); Class<? extends A> proxyAClass = proxyA.getClass(); System.out.println(proxyAClass); for (Annotation annotation : proxyAClass.getAnnotations()) { System.out.println(annotation); } // 获取父类 Class<?> superclass1 = proxyAClass.getSuperclass(); System.out.println(superclass1); for (Annotation annotation : superclass1.getAnnotations()) { System.out.println(annotation); } } }
执行结果发现,代理对象的父类就是我们原来的类
从原类再次获取注解,结果是可以的
before method run... A.fun executed... after method run... class cn.cloud9.test.reflect.sample.A$$EnhancerByCGLIB$$fe34985a class cn.cloud9.test.reflect.sample.A @cn.cloud9.test.reflect.annotation.AnnoA(value=) @cn.cloud9.test.reflect.annotation.AnnoB(value=)
由此可以推断JDK的接口实现代理的方式
对象要增强就需要通过接口实现处理,也就是说实际的接口对象,是实现类的对象
注解在接口上,要通过实现类找到对应的接口,通过接口实例,再找到标注的注解
注解在实现类上,就可以直接通过实现类,获取标注的注解