上一章:[Spring+SpringMVC+Mybatis]框架學習筆記(三):Spring實現JDBC
下一章:[Spring+SpringMVC+Mybatis]框架學習筆記(五):SpringAOP_顧問html
AOP: Aspect Oriented Programming 面向切面編程java
AOP的實現能夠把業務邏輯和系統級的服務進行隔離,使業務邏輯跟各個系統級服務的耦合度下降,提升系統的重用性和開發效率。spring
業務邏輯:某個類的某個方法自己要實現的功能。編程
系統級的服務:系統的日誌、事務、權限驗證安全
舉例:六七十年代,村支書要通知一個事情,原來要一家一家逐個告訴他們;有了廣播(AOP)之後,只須要用廣播,你們就知道了。app
AOP底層實現的原理:動態代理框架
動態代理有兩種方式:ide
把前5個術語串聯起來:學習
將切面織入到目標對象的鏈接點方法中,使鏈接點成爲切入點。測試
1)搭建SpringAOP開發環境須要引入的jar包;
aopalliance-1.0.jar
spring-aop-4.2.1.RELEASE.jar
2)實現通知
3)註冊目標類
4)註冊通知
5)註冊代理生產器,並注入目標類和通知
ps:通知的注意點:
package com.steven.spring.sysmgr.service; import java.util.List; import com.steven.spring.sysmgr.entity.Student; public interface IStudentService { public boolean addStudent(Student student); public boolean delStudent(Integer studentId); public boolean updateStudent(Student student); public List<Student> getStudentList(); }
package com.steven.spring.sysmgr.service.impl; import java.util.ArrayList; import java.util.List; import com.steven.spring.sysmgr.entity.Student; import com.steven.spring.sysmgr.service.IStudentService; public class StudentService implements IStudentService{ @Override public boolean addStudent(Student student) { System.out.println("執行增長功能"); return true; } @Override public boolean delStudent(Integer studentId) { //模擬異常,在異常通知中使用 int i = 1 / 0; System.out.println("執行刪除功能"); return true; } @Override public boolean updateStudent(Student student) { System.out.println("執行修改功能"); return true; } @Override public List<Student> getStudentList() { System.out.println("執行增長功能"); return new ArrayList<Student>(); } }
a) 前置通知
package com.steven.spring.sysmgr.advice; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; /** * 前置通知 * @author chenyang * */ public class MyBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { // TODO Auto-generated method stub System.out.println("這是前置通知,應該在方法執行以前打印出來"); } }
b) 後置通知
package com.steven.spring.sysmgr.advice; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; /** * 後置通知 * @author chenyang * */ public class MyAfterAdvice implements AfterReturningAdvice { //該方法中的代碼就是要織入到目標類方法的切面代碼 @Override public void afterReturning(Object returnValue, Method paraMethod, Object[] paramArrayOfObject, Object target) throws Throwable { System.out.println("方法執行的結果:" + returnValue); System.out.println("這是後置通知,應該在方法執行以後打印出來"); } }
c) 環繞通知
package com.steven.spring.sysmgr.advice; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; /** * 環繞通知 * @author chenyang * */ public class MyAroundAdvice implements MethodInterceptor { // 環繞通知能夠改變方法的返回值 @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("這是環繞通知的前面執行部分"); Object result = invocation.proceed(); System.out.println("方法的執行結果是:" + result); System.out.println("這是環繞通知的後面執行部分"); result = false; return result; } }
d) 異常通知
package com.steven.spring.sysmgr.advice; import org.springframework.aop.ThrowsAdvice; /** * 異常通知 * @author chenyang * */ public class MyThrowingAdvice implements ThrowsAdvice { public void afterThrowing(Exception e){ System.out.println("發生的異常:" + e); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 註冊目標類,並描述依賴關係 --> <bean id="studentService" class="com.steven.spring.sysmgr.service.impl.StudentService"></bean> <!-- 註冊前置通知 --> <bean id="beforeAdvice" class="com.steven.spring.sysmgr.advice.MyBeforeAdvice"></bean> <!-- 註冊後置通知 --> <bean id="afterAdvice" class="com.steven.spring.sysmgr.advice.MyAfterAdvice"></bean> <!-- 註冊環繞通知 --> <bean id="aroundAdvice" class="com.steven.spring.sysmgr.advice.MyAroundAdvice"></bean> <!-- 註冊異常通知 --> <bean id="throwingAdvice" class="com.steven.spring.sysmgr.advice.MyThrowingAdvice"></bean> <!-- 註冊前置通知的代理生成器,注入目標類接口、目標類、通知 --> <bean id="myBeforeProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="studentService"/> <property name="interfaces" value="com.steven.spring.sysmgr.service.IStudentService"/> <property name="interceptorNames" value="beforeAdvice"/> </bean> <!-- 註冊後置通知的代理生成器,注入目標類、通知 --> <bean id="myAfterProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="studentService"/> <!-- 這裏省略了目標類接口的實現類,由於系統能本身找到 --> <property name="interceptorNames" value="afterAdvice"/> </bean> <!-- 註冊環繞通知的代理生成器,注入目標類、通知 --> <bean id="myAroundProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="studentService"/> <property name="interceptorNames" value="aroundAdvice"/> </bean> <!-- 註冊異常通知的代理生成器,注入目標類、通知 --> <bean id="myThrowingProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="studentService"/> <property name="interceptorNames" value="throwingAdvice"/> </bean> </beans>
ps:
教你何時用value,何時用ref?
ref是引用(指針),value是布爾、string等得值。
用ref仍是value,須要看源碼中這個name是什麼類型。 全選name的引號中的值,alt + / , 若彈出的類的參數是對象,就用ref;若不是,就用value。
package com.steven.spring.sysmgr.test; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.steven.spring.sysmgr.entity.Student; import com.steven.spring.sysmgr.service.IStudentService; /** * 測試各類通知 * @author chenyang * */ public class AdviceTest { private ApplicationContext ac = null; @Before public void init(){ ac = new ClassPathXmlApplicationContext("applicationContext.xml"); } //測試前置通知,預期目標:將前置通知打印的內容出如今目標方法內容的前面 @Test public void testBeforeAdvice(){ IStudentService studentService = (IStudentService) ac.getBean("myBeforeProxy"); studentService.addStudent(new Student()); } //測試後置通知 @Test public void testAfterAdvice(){ IStudentService studentService = (IStudentService) ac.getBean("myAfterProxy"); studentService.addStudent(new Student()); } //測試環繞通知 @Test public void testAroundAdvice(){ IStudentService studentService = (IStudentService) ac.getBean("myAroundProxy"); studentService.addStudent(new Student()); } //測試異常通知 @Test public void testThrowingAdvice(){ IStudentService studentService = (IStudentService) ac.getBean("myThrowingProxy"); studentService.delStudent(1); } }
上一章:[Spring+SpringMVC+Mybatis]框架學習筆記(三):Spring實現JDBC
下一章:[Spring+SpringMVC+Mybatis]框架學習筆記(五):SpringAOP_顧問