首先註解在類上是能夠被繼承的 在註解上用@Inheritedjava
/** * Created by laizhenwei on 17:49 2017-10-14 */ @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface Mark { String desc() default ""; }
註解在方法中,沒有所謂繼承問題,只有重寫問題(何時會被重寫,除了人爲重寫,還有產生代理對象的時候會被重寫)
若是註解在父類方法中,若是方法沒有被子類重寫,那麼調用的是父類的方法,那麼註解是存在的,若是方法被子類重寫,子類方法沒有註解,那麼調用子類方法就獲取不了註解spring
測試前請確保開啓了(exposeProxy = true),此參數暴露代理對象,不然AopContext.currentProxy()會拋出如下異常ide
java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.
不過就算開啓了exposeProxy = true,在非代理對象中使用AopContext.currentProxy(),一樣會拋出測試
在SpringBoot中使用註解開啓ui
@SpringBootApplication @EnableAspectJAutoProxy(exposeProxy = true) public class AopApplication
繼承抽象類非代理對象spa
非代理對象測試代碼:3d
package com.example.aop.aopproxy.cglibproxy; import com.example.aop.annotation.aopproxy.Mark; /** * Created by laizhenwei on 17:56 2017-10-14 */ @Mark(desc = "我是被註解在抽象類中的Mark!") public abstract class AbstractClass { @Mark public abstract void sysout(); /** * 此方法繼承之後,子類沒有重寫,因此能夠獲取到註解(此結論僅針對非代理對象,以及jdk動態代理對象(不針對cglib代理對象)) */ @Mark public void sysout2(){ System.out.println("sysout2"); } public abstract boolean isAopProxy(); public abstract boolean isCglibProxy(); public abstract boolean isJdkDynamicProxy(); }
package com.example.aop.aopproxy.cglibproxy.impl; import com.example.aop.aopproxy.cglibproxy.AbstractClass; import org.springframework.aop.framework.AopContext; import org.springframework.aop.support.AopUtils; /** * Created by laizhenwei on 17:57 2017-10-14 */ public class ClassImplNoProxy extends AbstractClass { @Override public void sysout() { } @Override public boolean isAopProxy(){ return AopUtils.isAopProxy(AopContext.currentProxy()); } @Override public boolean isCglibProxy(){ return AopUtils.isCglibProxy(AopContext.currentProxy()); } @Override public boolean isJdkDynamicProxy(){ return AopUtils.isJdkDynamicProxy(AopContext.currentProxy()); } }
JunitTest代理
package com.example.aop.aopproxy.cglibproxy; import com.example.aop.AopApplication; import com.example.aop.annotation.aopproxy.Mark; import com.example.aop.aopproxy.cglibproxy.impl.ClassImplNoProxy; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; /** * Created by laizhenwei on 17:58 2017-10-14 * 非代理類測試,繼承抽象類 */ @RunWith(SpringRunner.class) @SpringBootTest(classes = AopApplication.class) public class AbstractClassTestsNoProxy { /** * 實現類接收 * 這裏直接new 出來一個非代理對象,不採用Spring 注入, */ private ClassImplNoProxy notProxyClassImpl = new ClassImplNoProxy(); /** * 抽象類接收 * 這裏直接new 出來一個非代理對象,不採用Spring 注入, */ private AbstractClass abstractClass = new ClassImplNoProxy(); /** * 測試是否代理對象,這裏採用new,這裏必然會拋出異常 */ @Test public void isProxy(){ try { System.out.println( notProxyClassImpl.isAopProxy()); }catch (Throwable throwable){ Assert.assertNotNull(throwable); return; } Assert.assertTrue(false);//若是代碼能執行到這裏,斷言失敗 } /** * 測試是否cglib代理對象,這裏採用new,這裏必然會拋出異常 */ @Test public void isCglibProxy(){ try { System.out.println(notProxyClassImpl.isCglibProxy()); }catch (Throwable throwable){ Assert.assertNotNull(throwable); return; } Assert.assertTrue(false);//若是代碼能執行到這裏,斷言失敗 } /** * 測試是否JDK動態代理對象,這裏採用new,這裏必然會拋出異常 */ @Test public void isJdkDynamicProxy(){ try { System.out.println(notProxyClassImpl.isJdkDynamicProxy());; }catch (Throwable throwable){ Assert.assertNotNull(throwable); return; } Assert.assertTrue(false);//若是代碼能執行到這裏,斷言失敗 } //方法被重寫,mark 爲null @Test public void getSysoutMark() throws NoSuchMethodException { Mark mark = notProxyClassImpl.getClass().getMethod("sysout",null).getAnnotation(Mark.class); Assert.assertNull(mark); } //方法被重寫,mark 爲null @Test public void getAbstractClassSysoutMark() throws NoSuchMethodException { Mark mark = abstractClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class); Assert.assertNull("方法被重寫,mark 爲null",mark); } //方法沒有重寫,測試經過 @Test public void getSysout2Mark() throws NoSuchMethodException { Mark mark = notProxyClassImpl.getClass().getMethod("sysout2",null).getAnnotation(Mark.class); Assert.assertNotNull(mark); } //方法沒有重寫,測試經過 @Test public void getAbstractClassSysout2Mark() throws NoSuchMethodException { Mark mark = abstractClass.getClass().getMethod("sysout2",null).getAnnotation(Mark.class); Assert.assertNotNull(mark); } //註解在類上是能夠繼承的 @Test public void getImplClassMark(){ Mark mark = notProxyClassImpl.getClass().getAnnotation(Mark.class); Assert.assertNotNull(mark); } }
結果code
代理對象(CGLIB):對象
咱們來修改子類改成Spring注入方式
package com.example.aop.aopproxy.cglibproxy.impl; import com.example.aop.aopproxy.cglibproxy.AbstractClass; import org.springframework.aop.framework.AopContext; import org.springframework.aop.support.AopUtils; import org.springframework.stereotype.Service; /** * Created by laizhenwei on 18:25 2017-10-14 */ @Service("cglibClassImplProxy") public class CglibClassImplProxy extends AbstractClass { @Override public void sysout() { } @Override public boolean isAopProxy(){ return AopUtils.isAopProxy(AopContext.currentProxy()); } @Override public boolean isCglibProxy(){ return AopUtils.isCglibProxy(AopContext.currentProxy()); } @Override public boolean isJdkDynamicProxy(){ return AopUtils.isJdkDynamicProxy(AopContext.currentProxy()); } }
junitTest 看看有沒有驚喜
package com.example.aop.aopproxy.cglibproxy; import com.example.aop.AopApplication; import com.example.aop.annotation.aopproxy.Mark; import com.example.aop.aopproxy.cglibproxy.impl.CglibClassImplProxy; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; /** * Created by laizhenwei on 18:24 2017-10-14 * 代理對象 */ @RunWith(SpringRunner.class) @SpringBootTest(classes = AopApplication.class) public class AbstractClassTestsProxy { @Resource(name = "cglibClassImplProxy") private CglibClassImplProxy cglibClassProxy; //抽象類接收 @Resource(name = "cglibClassImplProxy") private AbstractClass abstractClass; /** * 測試是否代理對象,這裏採用new,這裏必然會拋出異常 */ @Test public void isProxy(){ try { System.out.println( cglibClassProxy.isAopProxy()); }catch (Throwable throwable){ Assert.assertNotNull(throwable); return; } Assert.assertTrue(false);//若是代碼能執行到這裏,斷言失敗 } /** * 測試是否cglib代理對象,這裏採用new,這裏必然會拋出異常 */ @Test public void isCglibProxy(){ try { System.out.println(cglibClassProxy.isCglibProxy()); }catch (Throwable throwable){ Assert.assertNotNull(throwable); return; } Assert.assertTrue(false);//若是代碼能執行到這裏,斷言失敗 } /** * 測試是否JDK動態代理對象,這裏採用new,這裏必然會拋出異常 */ @Test public void isJdkDynamicProxy(){ try { System.out.println(cglibClassProxy.isJdkDynamicProxy());; }catch (Throwable throwable){ Assert.assertNotNull(throwable); return; } Assert.assertTrue(false);//若是代碼能執行到這裏,斷言失敗 } //方法被重寫,mark 爲null @Test public void getSysoutMark() throws NoSuchMethodException { Mark mark = cglibClassProxy.getClass().getMethod("sysout",null).getAnnotation(Mark.class); Assert.assertNull(mark); } //方法被重寫,mark 爲null @Test public void getAbstractClassSysoutMark() throws NoSuchMethodException { Mark mark = abstractClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class); Assert.assertNull("方法被重寫,mark 爲null",mark); } //方法沒有重寫,測試經過 @Test public void getSysout2Mark() throws NoSuchMethodException { Mark mark = cglibClassProxy.getClass().getMethod("sysout2",null).getAnnotation(Mark.class); Assert.assertNotNull(mark); } //方法沒有重寫,測試經過 @Test public void getAbstractClassSysout2Mark() throws NoSuchMethodException { Mark mark = abstractClass.getClass().getMethod("sysout2",null).getAnnotation(Mark.class); Assert.assertNotNull(mark); } //註解在類上是能夠繼承的 @Test public void getImplClassMark(){ Mark mark = cglibClassProxy.getClass().getAnnotation(Mark.class); Assert.assertNotNull(mark); } }
結果
依然所有經過,這不科學,使用了Spring bean 注入方式,依然獲取不到代理對象(由於isProxy ,isCglibProxy , isJdkDynamicProxy依然拋出了異常)
緣由是:spring會根據當前對象,判斷是否建立jdk動態代理的代理對象(針對接口代理),仍是cglib的代理對象(針對實現類代理),或者不建立代理對象,在上面的測試中
子類,以及父類都沒有須要使用Spring代理對象的必要(全部方法都沒有使用到SpringAop),因此沒有建立,這裏須要一個代理對象來測試,因此給方法加上事務註解就行了
OK,知道緣由那就好辦,咱們在子類或者父類隨便一個方法加上事務註解這裏在抽象類加上事務註解
package com.example.aop.aopproxy.cglibproxy; import com.example.aop.annotation.aopproxy.Mark; import org.springframework.transaction.annotation.Transactional; /** * Created by laizhenwei on 17:56 2017-10-14 */ @Mark(desc = "我是被註解在抽象類中的Mark!") public abstract class AbstractClass { @Mark @Transactional public abstract void sysout(); /** * 此方法繼承之後,子類沒有重寫,因此能夠獲取到註解(此結論僅針對非代理對象,以及jdk動態代理對象(不針對cglib代理對象)) */ @Mark public void sysout2(){ System.out.println("sysout2"); } public abstract boolean isAopProxy(); public abstract boolean isCglibProxy(); public abstract boolean isJdkDynamicProxy(); }
修改測試類
package com.example.aop.aopproxy.cglibproxy; import com.example.aop.AopApplication; import com.example.aop.annotation.aopproxy.Mark; import com.example.aop.aopproxy.cglibproxy.impl.CglibClassImplProxy; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; /** * Created by laizhenwei on 18:24 2017-10-14 * 代理對象 */ @RunWith(SpringRunner.class) @SpringBootTest(classes = AopApplication.class) public class AbstractClassTestsProxy { @Resource(name = "cglibClassImplProxy") private CglibClassImplProxy cglibClassProxy; //抽象類接收 @Resource(name = "cglibClassImplProxy") private AbstractClass abstractClass; /** * 測試是否代理對象 */ @Test public void isProxy(){ Assert.assertTrue(cglibClassProxy.isAopProxy()); } /** * 測試是否cglib代理對象 */ @Test public void isCglibProxy(){ Assert.assertTrue(cglibClassProxy.isCglibProxy()); } /** * 測試是否JDK動態代理對象 */ @Test public void isJdkDynamicProxy(){ Assert.assertFalse(cglibClassProxy.isJdkDynamicProxy()); } //方法被重寫,mark 爲null @Test public void getSysoutMark() throws NoSuchMethodException { Mark mark = cglibClassProxy.getClass().getMethod("sysout",null).getAnnotation(Mark.class); Assert.assertNull(mark); } //方法被重寫,mark 爲null @Test public void getAbstractClassSysoutMark() throws NoSuchMethodException { Mark mark = abstractClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class); Assert.assertNull("方法被重寫,mark 爲null",mark); } //方法沒有人爲重寫,測試不經過,由於 cglib代理對象已經被重寫 @Test public void getSysout2Mark() throws NoSuchMethodException { Mark mark = cglibClassProxy.getClass().getMethod("sysout2",null).getAnnotation(Mark.class); Assert.assertNotNull(mark); } //方法沒有人爲重寫,測試不經過,由於 cglib代理對象已經被重寫 @Test public void getAbstractClassSysout2Mark() throws NoSuchMethodException { Mark mark = abstractClass.getClass().getMethod("sysout2",null).getAnnotation(Mark.class); Assert.assertNotNull(mark); } //註解在類上是能夠繼承的 @Test public void getImplClassMark(){ Mark mark = cglibClassProxy.getClass().getAnnotation(Mark.class); Assert.assertNotNull(mark); } }
JunitTest結果,這下成功生成代理對象,可是出現了兩個預期外的結果.(測試代理對象三個方法的斷言已經被修改,因此測試經過)
咱們在子類中,並無人爲重寫這個方法,爲什麼註解就獲取不到了?不管用實現類接收,仍是抽象類接收.
緣由:繼承抽象類的bean,Spring注入,不管如何都是cglib代理,針對實現類代理,因此會把父類的方法在子類中重寫,這時並無帶上註解.因此代理類中不管如何都獲取不了註解
(這也就是爲何註解在抽象類的方法中,aop攔截註解會失效的緣由)
實現接口(非代理對象 new)
package com.example.aop.aopproxy.jdkproxy; import com.example.aop.annotation.aopproxy.Mark; /** * Created by laizhenwei on 17:43 2017-10-14 */ public interface IClass { @Mark void sysout(); boolean isAopProxy(); boolean isCglibProxy(); boolean isJdkDynamicProxy(); }
實現類
package com.example.aop.aopproxy.jdkproxy.impl; import com.example.aop.aopproxy.jdkproxy.IClass; import org.springframework.aop.framework.AopContext; import org.springframework.aop.support.AopUtils; /** * Created by laizhenwei on 17:44 2017-10-14 */ public class ClassImplNoProxy implements IClass { @Override public void sysout() { } @Override public boolean isAopProxy() { return AopUtils.isAopProxy(AopContext.currentProxy()); } @Override public boolean isCglibProxy() { return AopUtils.isCglibProxy(AopContext.currentProxy()); } @Override public boolean isJdkDynamicProxy() { return AopUtils.isJdkDynamicProxy(AopContext.currentProxy()); } }
junitTest
package com.example.aop.aopproxy.jdkproxy; import com.example.aop.AopApplication; import com.example.aop.annotation.aopproxy.Mark; import com.example.aop.aopproxy.jdkproxy.impl.ClassImplNoProxy; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; /** * Created by laizhenwei on 17:46 2017-10-14 */ @RunWith(SpringRunner.class) @SpringBootTest(classes = AopApplication.class) public class IClassTestsNoProxy { /** * 實現類接收 * 這裏直接new 出來一個非代理對象,不採用Spring 注入, */ private ClassImplNoProxy notProxyClassImpl = new ClassImplNoProxy(); /** * 接口類接收 * 這裏直接new 出來一個非代理對象,不採用Spring 注入, */ private IClass iClass = new ClassImplNoProxy(); /** * 測試是否代理對象,這裏採用new,這裏必然會拋出異常 */ @Test public void isProxy(){ try { System.out.println( notProxyClassImpl.isAopProxy()); }catch (Throwable throwable){ Assert.assertNotNull(throwable); return; } Assert.assertTrue(false);//若是代碼能執行到這裏,斷言失敗 } /** * 測試是否cglib代理對象,這裏採用new,這裏必然會拋出異常 */ @Test public void isCglibProxy(){ try { System.out.println(notProxyClassImpl.isCglibProxy()); }catch (Throwable throwable){ Assert.assertNotNull(throwable); return; } Assert.assertTrue(false);//若是代碼能執行到這裏,斷言失敗 } /** * 測試是否JDK動態代理對象,這裏採用new,這裏必然會拋出異常 */ @Test public void isJdkDynamicProxy(){ try { System.out.println(notProxyClassImpl.isJdkDynamicProxy());; }catch (Throwable throwable){ Assert.assertNotNull(throwable); return; } Assert.assertTrue(false);//若是代碼能執行到這裏,斷言失敗 } //方法被重寫,mark 爲null @Test public void getSysoutMark() throws NoSuchMethodException { Mark mark = notProxyClassImpl.getClass().getMethod("sysout",null).getAnnotation(Mark.class); Assert.assertNull(mark); } //方法被重寫,mark 爲null @Test public void getAbstractClassSysoutMark() throws NoSuchMethodException { Mark mark = iClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class); Assert.assertNull("方法被重寫,mark 爲null",mark); } //註解在接口上,並非繼承,因此獲取不了 @Test public void getImplClassMark(){ Mark mark = notProxyClassImpl.getClass().getAnnotation(Mark.class); Assert.assertNotNull(mark); } }
測試結果,其餘都跟預期同樣,可是獲取不了實現類的註解, 想固然這是現實接口,不是繼承.因此獲取不了也合理.
實現接口(非代理對象 Spring 注入 bean) 註解@Service 讓Spring容器管理,註釋掉事務註解
package com.example.aop.aopproxy.jdkproxy.impl; import com.example.aop.aopproxy.jdkproxy.IClass; import org.springframework.aop.framework.AopContext; import org.springframework.aop.support.AopUtils; import org.springframework.stereotype.Service; /** * Created by laizhenwei on 19:37 2017-10-14 */ @Service("classImplProxy") public class ClassImplProxy implements IClass { @Override // @Transactional public void sysout() { } @Override public boolean isAopProxy() { return AopUtils.isAopProxy(AopContext.currentProxy()); } @Override public boolean isCglibProxy() { return AopUtils.isCglibProxy(AopContext.currentProxy()); } @Override public boolean isJdkDynamicProxy() { return AopUtils.isJdkDynamicProxy(AopContext.currentProxy()); } }
JUNIT TEST 用註解獲取bean
package com.example.aop.aopproxy.jdkproxy; import com.example.aop.AopApplication; import com.example.aop.annotation.aopproxy.Mark; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; /** * Created by laizhenwei on 19:46 2017-10-14 */ @RunWith(SpringRunner.class) @SpringBootTest(classes = AopApplication.class) public class IClassTestsProxy { /** * 實現類接收 */ // @Resource //// @Autowired // private ClassImplProxy classImplProxy; /** * 接口類接收 */ // @Resource(name = "classImplProxy") @Resource(name = "classImplProxy") private IClass iClass; /** * 測試是否代理對象 */ @Test public void isProxy(){ Assert.assertTrue(iClass.isAopProxy()); } /** * 測試是否cglib代理對象 */ @Test public void isCglibProxy(){ Assert.assertTrue(iClass.isCglibProxy()); } /** * 測試是否JDK動態代理對象 */ @Test public void isJdkDynamicProxy(){ Assert.assertTrue(iClass.isJdkDynamicProxy()); } //方法被重寫,mark 爲null @Test public void getSysoutMark() throws NoSuchMethodException { Mark mark = iClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class); Assert.assertNull(mark); } //方法被重寫,mark 爲null @Test public void getAbstractClassSysoutMark() throws NoSuchMethodException { Mark mark = iClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class); Assert.assertNull("方法被重寫,mark 爲null",mark); } //註解在接口上,並非繼承,因此獲取不了 @Test public void getImplClassMark(){ Mark mark = iClass.getClass().getAnnotation(Mark.class); Assert.assertNotNull(mark); } //註解在接口上,並非繼承,因此獲取不了 @Test public void getClassMark(){ Mark mark = iClass.getClass().getAnnotation(Mark.class); Assert.assertNotNull(mark); } }
測試結果(這裏並無創代理對象,由於沒有方法中並無使用到Aop 的方法,Spring斷定沒有必要建立代理對象)
加上事務註解
package com.example.aop.aopproxy.jdkproxy.impl; import com.example.aop.aopproxy.jdkproxy.IClass; import org.springframework.aop.framework.AopContext; import org.springframework.aop.support.AopUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * Created by laizhenwei on 19:37 2017-10-14 */ @Service("classImplProxy") //@Scope(proxyMode = ScopedProxyMode.INTERFACES) public class ClassImplProxy implements IClass { @Override @Transactional public void sysout() { } @Override public boolean isAopProxy() { return AopUtils.isAopProxy(AopContext.currentProxy()); } @Override public boolean isCglibProxy() { return AopUtils.isCglibProxy(AopContext.currentProxy()); } @Override public boolean isJdkDynamicProxy() { return AopUtils.isJdkDynamicProxy(AopContext.currentProxy()); } }
測試結果(出乎意料,竟然是cglib代理,這裏我作過幾個測試,哪怕是實現了接口,依然是cglib代理,無解)
強制指定根據接口建立代理類,@Scope(proxyMode = ScopedProxyMode.INTERFACES)
package com.example.aop.aopproxy.jdkproxy.impl; import com.example.aop.aopproxy.jdkproxy.IClass; import org.springframework.aop.framework.AopContext; import org.springframework.aop.support.AopUtils; import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * Created by laizhenwei on 19:37 2017-10-14 */ @Service("classImplProxy") @Scope(proxyMode = ScopedProxyMode.INTERFACES) public class ClassImplProxy implements IClass { @Override @Transactional public void sysout() { } @Override public boolean isAopProxy() { return AopUtils.isAopProxy(AopContext.currentProxy()); } @Override public boolean isCglibProxy() { return AopUtils.isCglibProxy(AopContext.currentProxy()); } @Override public boolean isJdkDynamicProxy() { return AopUtils.isJdkDynamicProxy(AopContext.currentProxy()); } }
測試結果 (沒有變化)
可是就已經不能使用實現類接收
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.example.aop.aopproxy.jdkproxy.IClassTestsProxy': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'classImplProxy' is expected to be of type 'com.example.aop.aopproxy.jdkproxy.impl.ClassImplProxy' but was actually of type 'com.sun.proxy.$Proxy61'
基於全都是CGLIB 代理,可能有人懷疑我設置了強制走CGLIB 的代理參數,實際上並無
@SpringBootApplication @EnableAspectJAutoProxy(exposeProxy = true) public class AopApplication { @Bean @Primary @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource() { return DataSourceBuilder.create().build(); } public static void main(String[] args) { SpringApplication.run(AopApplication.class, args); } } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Import({AspectJAutoProxyRegistrar.class}) public @interface EnableAspectJAutoProxy { boolean proxyTargetClass() default false; boolean exposeProxy() default false; }
結論:
原本想測試針對接口現實的jdk動態代理的bean,是能夠註解在接口,注入對象可以獲取到註解.但由於全程了cglib那麼就沒辦法測了.
爲何建議註解都在實現類方法上, 是由於有那麼多不穩定的因素.
是否實現了接口就必定是jdk 代理, 不必定,還可能不建立
在一個類中,若是沒有涉及aop的方法操做,那麼Spring不會建立代理對象
若是繼承了一個類,又現實了接口是什麼狀況呢?我測試過,也是cglib,可是如今也不敢保證必定是.
註解在static 方法,以及final aop 也是獲取不了註解的.由於方法不能被代理對象重寫.