Spring AOP簡介及簡單例項
一、SpringAOP 簡介
1.AOP思想:
AOP即面向切面程式設計,可以說是OOP的補充和完善。它利用一種稱為"橫切"的技術,剖解開封裝的物件內部,並將那些影響了多個類的公共行為封裝到一個可重用模組,並將其命名為"Aspect",即切面。
所謂"切面",簡單說就是那些與業務無關,卻為業務模組所共同呼叫的邏輯或責任封裝起來,便於減少系統的重複程式碼,降低模組之間的耦合度,並有利於未來的可操作性和可維護性。
2.AOP概念:
1)AOP把軟體系統分為兩個部分:核心關注點和橫切關注點。
業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。
橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處基本相似,比如設定頁面編碼、許可權認證、日誌、事務。
AOP的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。
3.AOP使用
AOP程式設計其實是很簡單的事情,縱觀AOP程式設計,程式設計師只需要參與三個部分:
- 1)定義普通業務元件
- 2)定義切入點,一個切入點可能橫切多個業務元件
- 3)定義增強處理,增強處理就是在AOP框架為普通業務元件織入的處理動作
所以進行AOP程式設計的關鍵就是定義切入點(在哪裡要新增方法)和定義增強處理(要新增的方法),一旦定義了合適的切入點和增強處理,AOP框架將自動生成AOP代理,即:代理物件的方法=增強處理+被代理物件的方法。
4.AOP概念:
橫切關注點:
切面(次要業務):是對橫向關注點的抽象<aop:aspect>
連線點(所有可能進行切面操作的方法即類中的所有方法):被攔截到的點,因為Spring只支援方法型別的連線點不能操作屬性和構造方法,所以在Spring中連線點指的就是被攔截到的方法,實際上連線點還可以是欄位或者構造器
切入點(具體攔截到的方法):對連線點進行攔截的定義<aop:pointer>
通知:所謂通知指的就是指攔截到連線點之後要執行的程式碼,通知分為前置、後置、異常、最終、環繞通知五類
目標物件:代理的目標物件
織入(weave):(在原有的方法織入一個新的方法形成一個大方法)將切面應用到目標物件並導致代理物件建立的過程
將切面的通知方法織入到切點方法的過程
5.Spring 對AOP的支援:
Spring中AOP代理由Spring的IOC容器負責生成、管理,其依賴關係也由IOC容器負責管理。因此,AOP代理可以直接使用容器中的其它bean例項作為目標,這種關係可由IOC容器的依賴注入提供。
<aop:config>
<aop:aspect id="time" ref="timeHandler"><>
<aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
<aop:before method="printTime" pointcut-ref="addAllMethod" />
<aop:after method="printTime" pointcut-ref="addAllMethod" />
</aop:aspect>
</aop:config>
二、SringAOP簡單例子--方法執行前列印當前時間
1.pom.xml
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.2</version>
</dependency>
2.業務邏輯
核心關注點(主要業務--列印Hello World!)
//介面
package org.lanqiao.aop;
public interface Hello {
void print();
}
//實現類
package org.lanqiao.aop;
public class HelloImpl implements Hello {
public void print() {
System.out.println("Hello World!");
}
}
橫切關注點(次要業務--列印當前時間)
package org.lanqiao.aop;
public interface TimeAOP {
void printTime();
}
package org.lanqiao.aop;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TimeAOPImpl implements TimeAOP {
@Override
public void printTime() {
long currentTime = System.currentTimeMillis();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日 HH時mm分ss秒");
Date date = new Date(currentTime);
System.out.println(formatter.format(date));
}
}
3.Spring配置檔案aop.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="hello" class="org.lanqiao.aop.HelloImpl"/>
<bean id="timeHander" class="org.lanqiao.aop.TimeAOPImpl"/>
<aop:config><!--橫切關注點,對哪些方法進行攔截,攔截後怎麼處理-->
<aop:aspect id="timeAspect" ref="timeHander"><!--定義切面 若有多個切面可通過執行順序 order="1"等控制順序或者上下文順序 -->
<aop:pointcut id="helloPointcut" expression="execution(* org.lanqiao.aop.Hello.*(..))"/><!--定義切入點-->
<aop:before method="printTime" pointcut-ref="helloPointcut"/><!--將通知織入到切入點-->
<!--<aop:around method="printTime" pointcut-ref="helloPointcut"/>-->
</aop:aspect>
</aop:config>
</beans>
常見切入點表示式的例子:
任意公共方法的執行:
execution(public * *(..))任何一個以“set”開始的方法的執行:
execution(* set*(..))
AccountService
介面的任意方法的執行:execution(* com.xyz.service.AccountService.*(..))定義在service包裡的任意方法的執行:
execution(* com.xyz.service.*.*(..))定義在service包或者子包裡的任意類的任意方法的執行:
execution(* com.xyz.service..*.*(..))
4.測試
package org.lanqiao;
import org.junit.Test;
import org.lanqiao.aop.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloTest
{
@Test
public void testPrint()
{
ApplicationContext ctx =
new ClassPathXmlApplicationContext("aop.xml");
Hello hello = (Hello)ctx.getBean("hello");
hello.print();
}
}
5.輸出結果
相互學習,共同指教!