Spring 引介增強IntroductionAdvisor使用

環境:Spring5。2。14

在不修改業務程式碼的情況下如何讓某個類具有某項功能呢,比如具有XXXDAO介面的能力?

55。1 IntroductionAdvisor介紹

IntroductionAdvisor與PointcutAdvisor區別

IntroductionAdvisor只能應用於類級別

IntroductionAdvisor只能應用於Introduction型別的通知,而PointcutAdvisor可以應用於所有型別的通知

IntroductionAdvisor的Advice需要實現目標的介面,而pintcutAdvisor中的Advice沒有改要求

55。2 IntroductionAdvisor使用流程

假定我們的業務類CustomDAO希望具有DesignDAO(介面)的能力

55。2。1 目標介面

public interface DesignDAO { public void design() ; }

55。2。2 Introduction攔截器

public class CustomIntroductionInterceptor implements IntroductionInterceptor, DesignDAO { // 判斷當前的攔截器是否實現了目標介面(DesignDAO,我們需要某個類具有指定介面的功能) @Override public boolean implementsInterface(Class<?> intf) { return intf。isAssignableFrom(this。getClass()) ; } @Override public Object invoke(MethodInvocation invocation) throws Throwable { System。out。println(“我是通知類:IntroductionInterceptor”) ; // 判斷當前執行的方法所屬類是否實現了目標介面 // 這裡必須要進行相應的判斷攔截,否則會在沒有被攔截的類方法執行的時候報錯我 // 因為你的其它類所對應的介面並沒有在該攔截器中被實現。 if (implementsInterface(invocation。getMethod()。getDeclaringClass())) { return invocation。getMethod()。invoke(this, invocation。getArguments()) ; } return invocation。proceed() ; } @Override public void design() { System。out。println(“介面實現了”) ; } }

55。2。3 IntroductionAdvisor定義

@Componentpublic class CustomIntroductionAdvisor implements IntroductionAdvisor { // 定義Advice通知 @Override public Advice getAdvice() { return new CustomIntroductionInterceptor() ; } // 該方法沒有被使用,建議直接返回true @Override public boolean isPerInstance() { return true ; } // 定義了所要實現的所有介面 @Override public Class<?>[] getInterfaces() { return new Class<?>[] {DesignDAO。class} ; } // 過濾類,返回true就會被匹配 @Override public ClassFilter getClassFilter() { return new ClassFilter() { @Override public boolean matches(Class<?> clazz) { return CustomDAO。class。isAssignableFrom(clazz) ; } } ; } // 在這裡我們可以校驗我們的Advice類是否實現了執行的介面getInterfaces中定義的介面 @Override public void validateInterfaces() throws IllegalArgumentException { // 這裡可以參考DefaultIntroductionAdvisor的實現 }}

這裡可以檢視

示例文件37示例

原始碼是如何執行的

55。2。4 驗證

@Componentpublic class CustomerDAOImpl implements CustomDAO { public void update() { System。out。println(“更新資料。。。” + this。getClass()) ; } public void save() { System。out。println(“儲存方法。。。” + this。getClass()) ; } }

業務類並沒有實現DesignDAO介面。接下來看看透過上面定義IntroductionAdvisor是否可以讓我們的業務類具有目標類的功能

public class LauncherMain { public static void main(String[] args) { System。getProperties()。put(“sun。misc。ProxyGenerator。saveGeneratedFiles”,“true”) ; AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(“com。pack”) ; CustomDAO dao = ctx。getBean(CustomDAO。class) ; System。out。println(dao。getClass()) ; System。out。println(Arrays。toString(dao。getClass()。getInterfaces())) ; dao。save() ; dao。update() ; if (DesignDAO。class。isAssignableFrom(dao。getClass())) { DesignDAO ddao = (DesignDAO) dao ; System。out。println(“IntroductionAdvisor start。。。”) ; ddao。design() ; System。out。println(“IntroductionAdvisor end。。。”) ; } ctx。close() ; } }

執行結果:

class com。sun。proxy。$Proxy14[interface com。pack。dao。CustomDAO, interface com。pack。interfaces。DesignDAO, interface org。springframework。aop。SpringProxy, interface org。springframework。aop。framework。Advised, interface org。springframework。core。DecoratingProxy]我是通知類:IntroductionInterceptor, interface com。pack。dao。CustomDAOintf: interface com。pack。dao。CustomDAO我被呼叫了。。。儲存方法。。。class com。pack。dao。CustomerDAOImpl我是通知類:IntroductionInterceptor, interface com。pack。dao。CustomDAOintf: interface com。pack。dao。CustomDAO更新資料。。。class com。pack。dao。CustomerDAOImplIntroductionAdvisor start。。。我是通知類:IntroductionInterceptor, interface com。pack。interfaces。DesignDAOintf: interface com。pack。interfaces。DesignDAO介面實現了IntroductionAdvisor end。。。

示例37.5

瞭解原始碼

完畢!!!

公眾:Springboot實戰案例錦集

Spring 引介增強IntroductionAdvisor使用

Spring 引介增強IntroductionAdvisor使用

Spring 引介增強IntroductionAdvisor使用

Spring 引介增強IntroductionAdvisor使用