在使用AOP之前,首先我們先了解一下什么是AOP吧。在網上很多人將AOP翻譯為“面向切面編程”,什么是面向切面?與面向對象有什么區別呢?
在回答這兩個問題之前,我們先要明白切面的概念。
切面由切點與增強組成,它既包括了橫切邏輯的定義,也包括了連接點的定義,springAOP就是負責實施切面的框架,它將切面定義的橫切邏輯
織入到切面所指定的連接點中。
這時候就要問了:什么是切點?什么是增強?
先看個例子,在例子中再為大家一一解釋。
例子:在服務行業,熱情問好,帶人禮貌是每一個成熟的服務員應有的規范。
建立一個接口 Water.java 方法:問好與服務,greetTo(),serviceTo()
package test.aop; /** * * @author 作者: wcy * @version 創建時間:Mar 3, 2015 4:27:12 PM * @Description: TODO(一個服務生向顧客問候接待) */ public interface Waiter { public void greetTo(String name); public void serviceTo(String name); }
那么接下來一個生澀的,訓練不足的服務員,他只會生硬的打招呼,這對客人的服務可不好。
建立一個類NativeWater.java
package test.aop.impl; import test.aop.Waiter; /** * * @author 作者: wcy * @version 創建時間:Mar 3, 2015 4:29:53 PM * @Description: TODO(一個訓練不足的服務生) */ public class NativeWater implements Waiter{ public void greetTo(String name) { System.out.println("greet to :"+name+"...."); } public void serviceTo(String name) { System.out.println("service to :"+name+"...."); } }
這樣子不好,我們必須對訓練不足的服務員進行規范,在打招呼之前先熱情問好
package test.aop.impl; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; /** * * @author 作者: wcy * @version 創建時間:Mar 3, 2015 4:32:39 PM * @Description: TODO(服務生打招呼前,友好問候別人) */ public class GreetingBeforeAdvice implements MethodBeforeAdvice{ public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { String clientName = (String) arg1[0]; System.out.println("How are you ? Mr."+clientName+"~~~~~"); } }
好,已經對其進行規范了,我們就要測試一下:
package test.aop.impl; import org.junit.Before; import org.junit.Test; import org.springframework.aop.BeforeAdvice; import org.springframework.aop.framework.ProxyFactory; import test.aop.Waiter; /** * * @author 作者: wcy * @version 創建時間:Mar 3, 2015 4:40:14 PM * @Description: TODO(強制服務生要熱情問候顧客) */ public class BeforeAdviceTest { private Waiter waiter; private BeforeAdvice advice; private ProxyFactory pf; @Before public void init(){ waiter = new NativeWater(); advice = new GreetingBeforeAdvice(); pf = new ProxyFactory();//Spring工廠提供的代理類 pf.setTarget(waiter); //設置代理目標 pf.addAdvice(advice);//為代理目標添加增強 } @Test public void test01(){ Waiter proxy = (Waiter) pf.getProxy(); proxy.greetTo("xiaoyu"); proxy.serviceTo("xiaolian"); } }
運行的結果如下:
How are you ? Mr.xiaoyu~~~~~
greet to :xiaoyu....
How are you ? Mr.xiaolian~~~~~
service to :xiaolian....
好了,這就是一個面向切面的簡單例子,那我們就要總結一下了,面向切面需要什么東西。
1、目標類。也就是上文所說的NativeWater.java 該類是一個訓練不足的服務生,需要我們對其進行規范,所以要有規范類。
2、增強類。需要實現AOP的前置增強(同樣也有后置、環繞等增強),就是規范類,對服務生進行規范。
3、測試類。要為其進行代理,所以要有AOP的代理工廠。
詳細的AOP資料,百度很多我就不一一介紹了。
先說一下AOP的執行流程吧。
當我們調用某個定義了AOP的目標類中某個方法時,spring容器會為目標類生成代理類,這生成的方法有2種,一是:jdk的動態代理,使用它必須要有接口;二是CGLib代理,
代理類融合了原類和增強類,它可能與原類具有同樣的接口,也可能是原類的子類,所以當我們訪問原類的方法的時候,會先訪問增強類,再到原類。
好了,以上就說到這。
spring與springmvc整合出現AOP不起作用的原因:
1、spring與springmvc加載配置文件是不同步的,springmvc加載文件對注解進行掃描后,所有的注解都被掃到容器里面,當spring同樣加載配置文件掃描注解時,因為容器中已經
存在Service類,那么CGLib代理或jdk動態代理就不對它進行代理了,直接導致了applicationContext.xml中的事務不起作用,出現異常,事務不會滾。
2、解決方法:Spring MVC 和 Spring 整合的時候,SpringMVC的springmvc.xml文件中 配置掃描包,不要包含 service的注解,Spring的applicationContext.xml文件中 配置掃描包時,不要包含controller的注解,如下所示:
SpringMVC的xml配置:
<!--1、 注解探測器,對注解進行掃描 --> <context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>
同樣的,spring的applicationContext.xml配置文件也一樣,不要掃描@Controller注解
<!-- 注解掃描器 --> <context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
工作完成。