javascript
Spring实战学习笔记整理(4)-AOP(面向切面编程)
AOP與OOP概念
OOP(Object Oriented Programming,面向對象編程),通過封裝、繼承將程序抽象為各個層次的對象,進而組合為模塊或者程序,達到了軟件工程中的重用性、靈活性、擴展性。程序的運行籠統地可以看為各層次對象之間的相互調用。
AOP(Aspect Oriented Programming,面向切面編程),將程序運行過程分解為一個個的切面,對特定的切面(某個步驟或者階段)進行提取,達到解耦各種不同邏輯代碼。
OOP是在程序分塊層面上進行考慮,而AOP則是在程序運行的切面上進行考慮。
AOP使用
xml的使用方式
1.使用步驟(1)環境搭建,注意:導入aspectjweaver-1.9.5.jar(2)創建業務類、切面類(3)創建配置文件,并配置切面信息:以上涉及到的類必須納入到Spring IOC容器管理(4)測試 2.記憶的點2.1切點的聲明:標簽、表達式2.2通知:前置通知、后置通知、返回通知、異常通知、環繞通知(!joinPoint.proceed())注解的使用方式
1.使用步驟(1)環境搭建,注意:導入aspectjweaver-1.9.5.jar(2)創建業務類、切面類(定義了切面所有的東西)(3)開啟包掃描、開啟切面編程(4)測試 2.記憶的點2.1切點的聲明:注解、表達式、聲明在方法上2.2通知:前置通知、后置通知、返回通知、異常通知、環繞通知(!joinPoint.proceed())2.3切面類中@Aspect必須寫疫情足跡舉例:
使用自我掃碼進入形式和神奇設備負責記錄形式兩種形式,如圖所示:
自我掃碼進入形式
代碼部分:
Person.java
/*** Person類,用于演示疫情足跡登錄* @author Katrina**/ public class Person {/*** 回家*/public void goHome() {System.out.println("回家掃碼登記...");System.out.println("回家了");System.out.println("離家掃碼登記...");}/*** 去商場購物生活必需品*/public void goMarket() {System.out.println("去商場掃碼登記...");System.out.println("去商場購買生活必需品");System.out.println("離開商場掃碼登記...");}/*** 去工作*/public void goWork() {System.out.println("去工作掃碼登記...");System.out.println("去工作");System.out.println("離開掃碼登記...");}}PersonTest.java
/*** 測試類,用于演示疫情足跡記錄* @author Katrina**/ import org.junit.Test; public class PersonTest {/*** 測試非AOP疫情登記*/@Testpublic void test1() {Person person = new Person();person.goHome();person.goWork();person.goMarket();}}效果圖:
神奇設備負責記錄形式【xml形式配置AOP】
引入aspectjweaver-1.9.5.jarjar包
代碼部分:
part1:
AOPPerson.java
/*** AOPPerson類,用于演示AOP* @author Katrina**/ public class AOPPerson {/*** 回家方法*/public void goHome() {System.out.println("回家了");}/*** 去商場方法*/public void goMarket(String markerName) {System.out.println("去商場");}/*** 去工作方法*/public void goWork() {System.out.println("去工作");}}SuperMachine.java
/*** 超級機器,用于定義通知* @author Katrina**/ public class SuperMachine {/*** 進入前(方法執行前)進行登記信息*/public void beforeIn() {System.out.println("進入前登記信息...");}/*** 離開前(方法執行之后)進行登記信息*/public void beforeOut() {System.out.println("離開之前登記信息...");}}config.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:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"><!-- 注入類 --><bean id="AOPPerson" class="demo.AOPPerson"></bean><bean id="superMachine" class="demo.SuperMachine"></bean><!-- AOP配置 --><aop:config><!-- 切面配置 --><aop:aspect ref="superMachine"><!-- 定義切點:1.execution(執行): 2.表達式:execution(public * demo.AOPPerson.goHome(..) -> public void goHome() {表達式就是方法的描述:【訪問修飾符 返回值 方法的全路徑(參數列表)】通配符:*(全部)、..(0個或者多個)--><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.goHome())" id="pointCut"/> --><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.*())" id="pointCut"/> --><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.*(..))" id="pointCut"/> --><aop:pointcut expression="execution(public * demo.AOPPerson.*(..))" id="pointCut"/><!-- 注意:必須需要ref關聯 --><!-- 前置通知:執行方法之前執行 --><aop:before method="beforeIn" pointcut-ref="pointCut"/><!-- 后置通知:執行方法之后執行 --><aop:after method="beforeOut" pointcut-ref="pointCut"/></aop:aspect></aop:config> </beans>AOPPersonTest.java
import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; /*** aop方式測試類* @author Katrina**/ public class AOPPersonTest {private ClassPathXmlApplicationContext context;@Beforepublic void before() {context = new ClassPathXmlApplicationContext("config.xml");}/*** aop的demo*/@Testpublic void test1() {AOPPerson person = context.getBean(AOPPerson.class);person.goHome();person.goMarket("萬達超市");person.goWork();}@Afterpublic void after() {context.close();}}效果圖:
part2:
SuperMachine.java
/*** 超級機器,用于定義通知* @author Katrina**/ public class SuperMachine {/*** 進入前(方法執行前)進行登記信息*/public void beforeIn() {System.out.println("進入前登記信息...");}/*** 離開前(方法執行之后)進行登記信息*/public void beforeOut() {System.out.println("離開之前登記信息...");}/*** 返回通知*/public void returnMethod() {System.out.println("返回通知執行了...");}}config.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:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"><!-- 注入類 --><bean id="AOPPerson" class="demo.AOPPerson"></bean><bean id="superMachine" class="demo.SuperMachine"></bean><!-- AOP配置 --><aop:config><!-- 切面配置 --><aop:aspect ref="superMachine"><!-- 定義切點:1.execution(執行): 2.表達式:execution(public * demo.AOPPerson.goHome(..) -> public void goHome() {表達式就是方法的描述:【訪問修飾符 返回值 方法的全路徑(參數列表)】通配符:*(全部)、..(0個或者多個)--><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.goHome())" id="pointCut"/> --><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.*())" id="pointCut"/> --><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.*(..))" id="pointCut"/> --><aop:pointcut expression="execution(public * demo.AOPPerson.*(..))" id="pointCut"/><!-- 注意:必須需要ref關聯 --><!-- 前置通知:執行方法之前執行 --><aop:before method="beforeIn" pointcut-ref="pointCut"/><!-- 后置通知:執行方法之后執行 --><aop:after method="beforeOut" pointcut-ref="pointCut"/><!-- 返回通知:方法成功執行之后執行 --><aop:after-returning method="returnMethod" pointcut-ref="pointCut"/></aop:aspect> </aop:config> </beans>效果圖:
不對test進行修改,效果如圖所示:
其他情況,若修改回家方法(添加參數),且在賦值的時候有誤,則效果如圖所示:
part3:
SuperMachine.java
/*** 超級機器,用于定義通知* @author Katrina**/ public class SuperMachine {/*** 進入前(方法執行前)進行登記信息*/public void beforeIn() {System.out.println("進入前登記信息...");}/*** 離開前(方法執行之后)進行登記信息*/public void beforeOut() {System.out.println("離開之前登記信息...");}/*** 返回通知*/public void returnMethod() {System.out.println("返回通知執行了...");}/*** 異常通知*/public void afterThrowing() {System.out.println("出現異常了...");}}config.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:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"><!-- 注入類 --><bean id="AOPPerson" class="demo.AOPPerson"></bean><bean id="superMachine" class="demo.SuperMachine"></bean><!-- AOP配置 --><aop:config><!-- 切面配置 --><aop:aspect ref="superMachine"><!-- 定義切點:1.execution(執行): 2.表達式:execution(public * demo.AOPPerson.goHome(..) -> public void goHome() {表達式就是方法的描述:【訪問修飾符 返回值 方法的全路徑(參數列表)】通配符:*(全部)、..(0個或者多個)--><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.goHome())" id="pointCut"/> --><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.*())" id="pointCut"/> --><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.*(..))" id="pointCut"/> --><aop:pointcut expression="execution(public * demo.AOPPerson.*(..))" id="pointCut"/><!-- 注意:必須需要ref關聯 --><!-- 前置通知:執行方法之前執行 --><aop:before method="beforeIn" pointcut-ref="pointCut"/><!-- 后置通知:執行方法之后執行 --><aop:after method="beforeOut" pointcut-ref="pointCut"/><!-- 返回通知:方法成功執行之后執行 --><aop:after-returning method="returnMethod" pointcut-ref="pointCut"/><!-- 異常通知:方法出現異常后執行 --><aop:after-throwing method="afterThrowing" pointcut-ref="pointCut"/></aop:aspect></aop:config> </beans>效果圖:
情況一,在測試類中修改代碼為:person.goHome("123abc");,效果如圖所示:
情況二,在測試類中修改代碼為:person.goHome("123");,效果如圖所示:
part4:
SuperMachine.java
import org.aspectj.lang.ProceedingJoinPoint; /*** 超級機器,用于定義通知* @author Katrina**/ public class SuperMachine {/*** 環繞通知* @param joinPoint,一定要調用proceed方法*/public void around(ProceedingJoinPoint joinPoint) {System.out.println("進入前進行登記信息");boolean hasError = false;try {joinPoint.proceed(); //執行業務方法 } catch (Throwable e) {e.printStackTrace();System.out.println("出現異常了...");hasError = true;} if (hasError) {System.out.println("出現異常信息");} else {System.out.println("成功返回值信息");}System.out.println("離開前進行登記信息");}/*** 進入前(方法執行前)進行登記信息*/public void beforeIn() {System.out.println("進入前登記信息...");}/*** 離開前(方法執行之后)進行登記信息*/public void beforeOut() {System.out.println("離開之前登記信息...");}/*** 返回通知*/public void returnMethod() {System.out.println("返回通知執行了...");}/*** 異常通知*/public void afterThrowing() {System.out.println("出現異常了...");}}config.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:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"><!-- 注入類 --><bean id="AOPPerson" class="demo.AOPPerson"></bean><bean id="superMachine" class="demo.SuperMachine"></bean><!-- AOP配置 --><aop:config><!-- 切面配置 --><aop:aspect ref="superMachine"><!-- 定義切點:1.execution(執行): 2.表達式:execution(public * demo.AOPPerson.goHome(..) -> public void goHome() {表達式就是方法的描述:【訪問修飾符 返回值 方法的全路徑(參數列表)】通配符:*(全部)、..(0個或者多個)--><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.goHome())" id="pointCut"/> --><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.*())" id="pointCut"/> --><!-- <aop:pointcut expression="execution(public void demo.AOPPerson.*(..))" id="pointCut"/> --><aop:pointcut expression="execution(public * demo.AOPPerson.*(..))" id="pointCut"/><!-- 注意:必須需要ref關聯 --><!-- 前置通知:執行方法之前執行 --><!-- <aop:before method="beforeIn" pointcut-ref="pointCut"/> --><!-- 后置通知:執行方法之后執行 --><!-- <aop:after method="beforeOut" pointcut-ref="pointCut"/> --><!-- 返回通知:方法成功執行之后執行 --><!-- <aop:after-returning method="returnMethod" pointcut-ref="pointCut"/> --><!-- 異常通知:方法出現異常后執行 --><!-- <aop:after-throwing method="afterThrowing" pointcut-ref="pointCut"/> --><!-- 環繞通知 --><aop:around method="around" pointcut-ref="pointCut"/></aop:aspect></aop:config> </beans>效果圖:
情況一,在測試類中修改代碼為:person.goHome("123");,效果如圖所示:
情況二,在測試類中修改代碼為:person.goHome("abc");,效果如圖所示:
注解形式配置AOP
代碼部分:
part1:
UserControllor.java
import org.springframework.stereotype.Controller; /*** UserControllor,用于演示注解形式的切面編程* @author Katrina**/ @Controller public class UserControllor {/*** 添加用戶操作*/public void addUser() {System.out.println("添加用戶成功...");}/*** 編輯用戶操作*/public void editUser() {System.out.println("編輯用戶成功...");}}LogAOP.java
import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /*** 日志的切面* @author Katrina**/ @Component @Aspect //標明LogAOP是切面類 public class LogAOP {/** 1.聲明切點* 2.聲明通知*/@Pointcut(value = "execution(public * anno.UserControllor.*(..))")public void pointCut() { }/*** 使用@Before聲明前置通知*/@Before(value = "pointCut()")public void log() {System.out.println("在此處記錄日志...");}/*** 使用@After聲明后置通知*/@After(value = "pointCut()")public void after() {System.out.println("后置通知執行了...");}}anno-config.java
<?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:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"><!-- 開啟包掃描 --><context:component-scan base-package="anno"></context:component-scan><!-- 開啟AOP --><aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>UserControllorTest.java
import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; /*** 用于演示注解形式使用AOP* @author Katrina**/ public class UserControllorTest {@Testpublic void test() {//1.獲取容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("anno-config.xml");//2.取出實例,做操作UserControllor userControllor = context.getBean(UserControllor.class);userControllor.addUser();//3.關閉容器context.close();}}效果圖:
part2:
UserControllor.java
import org.springframework.stereotype.Controller; /*** UserControllor,用于演示注解形式的切面編程* @author Katrina**/ @Controller public class UserControllor {/*** 添加用戶操作*/public void addUser(String number) {System.out.println("添加用戶成功...");Integer.parseInt(number); //解析,可制造錯誤(如:1/0)}/*** 編輯用戶操作*/public void editUser() {System.out.println("編輯用戶成功...");}}LogAOP.java
import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /*** 日志的切面* @author Katrina**/ @Component @Aspect //標明LogAOP是切面類 public class LogAOP {/** 1.聲明切點* 2.聲明通知*/@Pointcut(value = "execution(public * anno.UserControllor.*(..))")public void pointCut() { }/*** 使用@Before聲明前置通知*/@Before(value = "pointCut()")public void log() {System.out.println("在此處記錄日志...");}/*** 使用@After聲明后置通知*/@After(value = "pointCut()")public void after() {System.out.println("后置通知執行了...");}/*** 使用@AfterReturning聲明返回通知*/@AfterReturning(value = "pointCut()")public void afterReturning() {System.out.println("方法成功執行了...");}}效果圖:
情況一,在測試類中修改代碼為:person.goHome("111");,效果如圖所示:
情況二,在測試類中修改代碼為:person.goHome("abc");,效果如圖所示:
part3:
LogAOP.java
import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /*** 日志的切面* @author Katrina**/ @Component @Aspect //標明LogAOP是切面類 public class LogAOP {/** 1.聲明切點* 2.聲明通知*/@Pointcut(value = "execution(public * anno.UserControllor.*(..))")public void pointCut() { }/*** 使用@Before聲明前置通知*/@Before(value = "pointCut()")public void log() {System.out.println("在此處記錄日志...");}/*** 使用@After聲明后置通知*/@After(value = "pointCut()")public void after() {System.out.println("后置通知執行了...");}/*** 使用@AfterReturning聲明返回通知*/@AfterReturning(value = "pointCut()")public void afterReturning() {System.out.println("方法成功執行了...");}/*** 使用@AfterThrowing表明異常通知*/@AfterThrowing(value = "pointCut()")public void afterThrowing() {System.out.println("發生異常了...");}}效果圖:
情況一,在測試類中修改代碼為:person.goHome("abc");,效果如圖所示:
情況二,在測試類中修改代碼為:person.goHome("111");,效果如圖所示:
part4:
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /*** 日志的切面* @author Katrina**/ @Component @Aspect //標明LogAOP是切面類 public class LogAOP {/** 1.聲明切點* 2.聲明通知*/@Pointcut(value = "execution(public * anno.UserControllor.*(..))")public void pointCut() { }/*** 使用@Before聲明前置通知*/ // @Before(value = "pointCut()")public void log() {System.out.println("在此處記錄日志...");}/*** 使用@After聲明后置通知*/ // @After(value = "pointCut()")public void after() {System.out.println("后置通知執行了...");}/*** 使用@AfterReturning聲明返回通知*/ // @AfterReturning(value = "pointCut()")public void afterReturning() {System.out.println("方法成功執行了...");}/*** 使用@AfterThrowing表明異常通知*/ // @AfterThrowing(value = "pointCut()")public void afterThrowing() {System.out.println("發生異常了...");}/*** 使用@Around注解聲明環繞通知* @param joinPoint*/@Around(value = "pointCut()")public void around(ProceedingJoinPoint joinPoint) {System.out.println("執行方法之前");try {joinPoint.proceed(); //執行業務方法} catch (Throwable e) {e.printStackTrace();System.out.println("出現異常了...");}System.out.println("執行方法之后");}}效果圖:
情況一,在測試類中修改代碼為:person.goHome("111");,效果如圖所示:
情況二,在測試類中修改代碼為:person.goHome("abc");,效果如圖所示:
總結
以上是生活随笔為你收集整理的Spring实战学习笔记整理(4)-AOP(面向切面编程)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue移动端项目返回上次浏览位置
- 下一篇: canvas上纯JS实现可滑动时间刻度轴