Spring AOP 提供了 5 種類型的通知,它們分別是 Before Advice(前置通知)、After Returning Advice(后置通知)、Interception Around Advice(周圍通知)、Throws Advice(異常通知)和 Introduction Advice(引介通知)。
Spring AOP的增強類型
首先先了解一下增強接口的繼承關系:

下面分別進行介紹。
如上圖所示:
其中帶Spring標志的是Spring定義的擴展增強接口
其中帶aopalliance標志的是AOP聯盟所定義的接口
按照增加在目標類方法連接點的位置可以將增強划分為以下五類:
- 前置增強 (org.springframework.aop.BeforeAdvice) 表示在目標方法執行前來實施增強
- 后置增強 (org.springframework.aop.AfterReturningAdvice) 表示在目標方法執行后來實施增強
- 環繞增強 (org.aopalliance.intercept.MethodInterceptor) 表示在目標方法執行前后同時實施增強
- 異常拋出增強 (org.springframework.aop.ThrowsAdvice) 表示在目標方法拋出異常后來實施增強
- 引介增強 (org.springframework.aop.introductioninterceptor) 表示在目標類中添加一些新的方法和屬性
其中,引介增強是一種特殊的增強。他可以在目標類中添加屬性和方法,通過攔截定義一個接口,讓目標代理實現這個接口。他的連接點是類級別的,而前面的幾種則是方法級別的。
其中,環繞增強是AOP聯盟定義的接口,其他四種增強接口則是Spring定義的接口。
其實,AOP增強很簡單:
通過實現這些增強接口,在實現這些接口的方法當中定義橫切邏輯,然后通過配置Spring的配置文件就可以完成將增強織入到目標方法當中了。
補充:增強既包含了橫切邏輯同時又包含了部分連接點信息。
前置增強:
import org.springframework.aop.BeforeAdvice; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.aop.framework.ProxyFactory; import java.lang.reflect.Method; public class Main{ public static void main(String[] args) { //1、不使用xml配置實例化 Worker target=new DigWorker(); BeforeAdvice advice=new WearingBeforeAdvice(); //Spring提供的代理工廠 ProxyFactory pFactory=new ProxyFactory(); // //指定做優化,又將使用cglib動態 // pFactory.setOptimize(true); // // //指定對接口進行代理,通過JDK動態代理 // pFactory.setInterfaces(target.getClass().getInterfaces()); //設置代理目標,默認使用Cglib動態代理 pFactory.setTarget(target); //為代理目標添加前置增強,這里會為目標的每個方法都增加增強 pFactory.addAdvice(advice); //生成代理實例 Worker proxy=(Worker)pFactory.getProxy(); proxy.getTool("鑽機"); proxy.digSomething("煤炭"); proxy.initWork(); } } interface Worker { void getTool(String tool); void digSomething(String type); void initWork(); } class DigWorker implements Worker{ @Override public void getTool(String tool) { System.out.println("---------------調用方法--------------"); System.out.println("領取工具:"+tool); // throw new RuntimeException("運行異常"); } @Override public void digSomething(String type) { System.out.println("---------------調用方法--------------"); System.out.println("開始賣力挖取:"+type); } @Override public void initWork() { System.out.println("生成一個DigWorker實例"); } } class WearingBeforeAdvice implements MethodBeforeAdvice { public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { if(arg1.length>0) { String thing = (String) arg1[0]; System.out.println("--------------進行前置增強---------------"); System.out.println("得到" + thing + "之前先穿上工作服!!"); }else{ System.out.println("--------------進行前置增強2---------------"); } } }
--------------進行前置增強--------------- 得到鑽機之前先穿上工作服!! ---------------調用方法-------------- 領取工具:鑽機 --------------進行前置增強--------------- 得到煤炭之前先穿上工作服!! ---------------調用方法-------------- 開始賣力挖取:煤炭 --------------進行前置增強2--------------- 生成一個DigWorker實例
前置和后置:
import org.springframework.aop.AfterReturningAdvice; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.lang.reflect.Method; public class Main{ public static void main(String[] args) { //2、下面使用Spring的xml配置實例化 ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml"); //worker1帶前置和后置增強 Worker worker1=(Worker)ctx.getBean("worker1"); System.out.println("worker1進入工作:"); worker1.getTool("鋤頭"); } } interface Worker { void getTool(String tool); void digSomething(String type); void initWork(); } class DigWorker implements Worker{ @Override public void getTool(String tool) { System.out.println("---------------調用方法--------------"); System.out.println("領取工具:"+tool); // throw new RuntimeException("運行異常"); } @Override public void digSomething(String type) { System.out.println("---------------調用方法--------------"); System.out.println("開始賣力挖取:"+type); } @Override public void initWork() { System.out.println("生成一個DigWorker實例"); } } class WearingBeforeAdvice implements MethodBeforeAdvice { public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { if(arg1.length>0) { String thing = (String) arg1[0]; System.out.println("--------------進行前置增強---------------"); System.out.println("得到" + thing + "之前先穿上工作服!!"); }else{ System.out.println("--------------進行前置增強2---------------"); } } } class WeaningAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { System.out.println("--------------進行后置增強---------------"); System.out.println("工作結束,請先脫掉工作服"); } }
benas文件:
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <!-- 要進行增強的目標 --> <bean id="target" class="com.company.DigWorker" init-method="initWork"/> <!-- 前置增強的方法 --> <bean id="beforeAdvice" class="com.company.WearingBeforeAdvice" /> <!-- 后置增強的方法 --> <bean id="afterAdvice" class="com.company.WeaningAfterAdvice" /> <!--同時設置前置增強和后置增強方法 --> <bean id="worker1" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.company.Worker" p:interceptorNames="beforeAdvice,afterAdvice" p:target-ref="target" lazy-init="true"/> </beans>
Result:
生成一個DigWorker實例 worker1進入工作: --------------進行前置增強--------------- 得到鋤頭之前先穿上工作服!! ---------------調用方法-------------- 領取工具:鋤頭 --------------進行后置增強--------------- 工作結束,請先脫掉工作服
環繞增強:
import org.aopalliance.intercept.MethodInvocation; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.aopalliance.intercept.MethodInterceptor; public class Main{ public static void main(String[] args) { //2、下面使用Spring的xml配置實例化 ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml"); //work2帶環繞增強 Worker worker2=(Worker)ctx.getBean("worker2"); System.out.println("worker2進入工作:"); worker2.getTool("鑽機"); } } interface Worker { void getTool(String tool); void digSomething(String type); void initWork(); } class DigWorker implements Worker{ @Override public void getTool(String tool) { System.out.println("---------------調用方法--------------"); System.out.println("領取工具:"+tool); // throw new RuntimeException("運行異常"); } @Override public void digSomething(String type) { System.out.println("---------------調用方法--------------"); System.out.println("開始賣力挖取:"+type); } @Override public void initWork() { System.out.println("生成一個DigWorker實例"); } } class WearingInterceptor implements MethodInterceptor{ @Override public Object invoke(MethodInvocation arg0) throws Throwable { Object[] args=arg0.getArguments();//目標方法入參 String toolname=(String)args[0]; System.out.println("--------------環繞增強開始---------------"); System.out.println("得到"+toolname+"之前先穿上工作服"); Object object=arg0.proceed(); System.out.println("工作結束,請先脫掉工作服"); System.out.println("--------------環繞增強結束---------------"); return object; } }
beans.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <!-- 要進行增強的目標 --> <bean id="target" class="com.company.DigWorker" init-method="initWork"/> <!-- 環繞增強的方法 --> <bean id="aroundAdvice" class="com.company.WearingInterceptor" /> <!--設置環繞增強方法 --> <bean id="worker2" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.company.Worker" p:interceptorNames="aroundAdvice" p:target-ref="target" lazy-init="true"/> </beans>
Result:
生成一個DigWorker實例 worker2進入工作: --------------環繞增強開始--------------- 得到鑽機之前先穿上工作服 ---------------調用方法-------------- 領取工具:鑽機 工作結束,請先脫掉工作服 --------------環繞增強結束---------------
異常拋出增強:
import org.springframework.aop.ThrowsAdvice; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.lang.reflect.Method; public class Main{ public static void main(String[] args) throws Exception { //2、下面使用Spring的xml配置實例化 ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml"); //work3帶環繞增強 Worker worker3=(Worker)ctx.getBean("worker3"); System.out.println("worker3進入工作:"); worker3.getTool("錘子"); } } interface Worker { void getTool(String tool); void digSomething(String type); void initWork(); } class DigWorker implements Worker{ @Override public void getTool(String tool) { System.out.println("---------------調用方法--------------"); System.out.println("領取工具:"+tool); throw new RuntimeException("運行異常"); } @Override public void digSomething(String type) { System.out.println("---------------調用方法--------------"); System.out.println("開始賣力挖取:"+type); } @Override public void initWork() { System.out.println("生成一個DigWorker實例"); } } class WeaningThrowAdvice implements ThrowsAdvice { public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable { System.out.println("--------------------"); System.out.println("method:"+method.getName()); System.out.println("拋出異常"+ex.getMessage()); System.out.println("成功回滾事務"); } }
beans.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <!-- 要進行增強的目標 --> <bean id="target" class="com.company.DigWorker" init-method="initWork"/> <!-- 異常拋出增強的方法 --> <bean id="throwAdvice" class="com.company.WeaningThrowAdvice" /> <!--設置異常拋出增強方法 proxyTargetClass="true",使用CgLib代理--> <bean id="worker3" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="throwAdvice" p:target-ref="target" p:proxyTargetClass="true"/> </beans>
Result:
生成一個DigWorker實例 worker3進入工作: ---------------調用方法-------------- 領取工具:錘子 Exception in thread "main" java.lang.reflect.UndeclaredThrowableException at com.company.DigWorker$$EnhancerBySpringCGLIB$$b3caca85.getTool(<generated>) at com.company.Main.main(Main.java:18) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) Caused by: java.lang.IllegalAccessException: Class org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor can not access a member of class com.company.WeaningThrowAdvice with modifiers "public" at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102) at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296) at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288) at java.lang.reflect.Method.invoke(Method.java:491) at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invokeHandlerMethod(ThrowsAdviceInterceptor.java:145) at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:130) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656)
