從上述的實驗中能夠看出BeanNameAutoProxyCreator對於AOP的實現已經和完美了,可是還有兩點不足之處:程序員
1,對於切面的實現比較麻煩,既不一樣類型的通知切面要實現不一樣的接口,並且一個切面只有一個方法。spring
2,對於切入點的實現也不是很完美,既通知實現的切面對象的方法對於目標對象方法的精確織入要使用不一樣的顧問進行包裝實現。express
在以上的試驗中,咱們不難看出,其實對於切面的的實現就是切面方法向目標對象方法織入的過程。spring-mvc
那麼提出兩個問題:mvc
1,可不可讓一個類去實現不一樣類型通知的功能,既一個類中有多個方法,可讓咱們指定方法的的通知類型。框架
2,對於切入點的實現能不能規定一種切入點表達式,能夠對目標對象的方法進行切入點的指定,免去使用多個顧問對不一樣通知包裝的麻煩。ide
針對以上兩點,AspectJ框架這個框架給出了很好的解決方案,而AspectJ框架又是屬於spring框架的一部分。測試
咱們這裏依舊經過實驗來講明問題,仍是用以前實驗的例子。spa
用於建立目標對象的接口和實現類。code
public interface ICalculatorService { int add(int a,int b); int division(int a ,int b); }
public interface IComparatorService { void comparator(int a,int b); }
public class CalculatorServiceImpl implements ICalculatorService { @Override public int add(int a, int b) { return a+b; } @Override public int division(int a, int b) { return a/b; } }
public class ComparatorServiceImpl implements IComparatorService { @Override public void comparator(int a, int b) { if(a > b){ System.out.println(a+"比"+b+"大"); }else if(a < b){ System.out.println(a+"比"+b+"小"); }else{ System.out.println(a+"等於"+b); } } }
切面的實現類,AspectJ框架容許咱們的切面是一個POJO類,這樣就避免了spring框架Api的侵染,另外AspectJ框架比以前多出了一個最終通知,就是無論目標方法執行與否,最終通知的方法都會執行,有點相似finally語句快。
public class MyAspect { //前置通知方法 public void myBefore() { System.out.println("執行前置通知方法"); } // 後置通知方法 public void myAfterReturning() { System.out.println("執行後置通知方法"); } // 環繞通知方法 public Object myAround(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("執行環繞通知方法"); Object[] args = pjp.getArgs(); int a = (int)args[0]; int b = (int)args[1]; if(b == 0){ System.err.println("除數不能爲0"); return -1; } if(a == 0){ return 0; } return pjp.proceed(); } // 最終通知 public void myAfter() { System.out.println("執行最終通知"); } }
Xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 目標對象 --> <bean id="comparatorServiceTarget" class="com.opensource.service.impl.ComparatorServiceImpl"/> <bean id="calculatorServiceTarget" class="com.opensource.service.impl.CalculatorServiceImpl"/> <!-- 通知 --> <bean id="myAspect" class="com.opensource.service.MyAspect"/> <!-- AOP配置 --> <aop:config> <aop:pointcut expression="execution(* *..service.*.*(..))" id="pointcut1"/> <aop:pointcut expression="execution(* *..ICalculatorService.division(..))" id="pointcut2"/> <aop:aspect ref="myAspect"> <aop:before method="myBefore" pointcut-ref="pointcut1"/> <aop:after-returning method="myAfterReturning" pointcut-ref="pointcut1"/> <aop:around method="myAround" pointcut-ref="pointcut2"/> <aop:after method="myAfter" pointcut-ref="pointcut1"/> </aop:aspect> </aop:config> </beans>
AspectJ框架提供的標籤可讓咱們指定切面中不一樣的方法的通知類型,二切入點表達式則容許咱們對該切面方法要織入spring容器中的那些目標對象,及對象的那些方法(切入點)。對於切入點表達式的使用這裏介紹兩種最經常使用的:
//指定工程中全部包下子包爲service的接口和實現類爲切入點
<aop:pointcut expression="execution(* *..service.*.*(..))" id="pointcut1"/>
//指定工程中全部包下接口名爲ICalculatorService及其實現類的division方法爲切入點 <aop:pointcut expression="execution(* *..ICalculatorService.division(..))" id="pointcut2"/>
你如果想對工程中某個具體的接口或者實現類的方法進行指定就要採用以下作法
這裏注意*號後的空格不能少
<aop:pointcut expression="execution(* com.opensource.service.ICalculatorService.division(..))" id="pointcut2"/>
另外切入點表達式一樣支持模糊匹配的方式。
測試類:
public class MyTest { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("spring-bean.xml"); ICalculatorService bean = (ICalculatorService)ac.getBean("calculatorServiceTarget"); IComparatorService bean1 = (IComparatorService)ac.getBean("comparatorServiceTarget"); int division = bean.division(10, 2); System.out.println("兩數相除商爲:"+division); System.err.println("---------------------------------------------------------"); int add = bean.add(0, 2); System.out.println("兩數想加和爲:"+add); System.err.println("---------------------------------------------------------"); bean1.comparator(0, 1); } }
實驗結果:
AspectJ框架對於Aop的實現配置比較簡單,實現上也很靈活,還支持註解式開發,本文用到的式配置式開發,另外還有對於切面方法參數的配置,還有不少點。
最後說一點,咱們做爲程序員,研究問題仍是要仔細深刻一點的。當你對原理了解的有夠透徹,開發起來也就駕輕就熟了,不少開發中的問題和疑惑也就迎刃而解了,並且在面對其餘問題的時候也可作到舉一反三。固然在開發中沒有太多的時間讓你去研究原理,開發中要以實現功能爲前提,可等項目上線的後,你有大把的時間或者空餘的時間,你大可去刨根問底,深刻的去研究一項技術,爲以爲這對一名程序員的成長是很重要的事情。