AOP(Aspect Oriented Programming),即面向切面的程式設計。
(一)什麼是面向切面的程式設計
切面是指代碼中一些公共的非核心子產品的抽象,比如日志列印,可以将其從核心代碼中剝離出來,當程式運作需要時通過切面插入公共代碼即可,進而降低代碼的耦合度,提高代碼的可複用性,并使得我們程式設計的時候能夠更專注于核心業務代碼的編寫,這種程式設計模式叫做面向切面的程式設計。
類可以繼承,是以可以看做是有一個縱向的關系鍊,而切面可以橫向在多個類的方法中插入,是以也說是橫切面。Spring AOP中,切面出現的類通過IOC容器執行個體化并注入,進而将切面中的方法插入到核心業務代碼中。
(二)面向切面的程式設計的一些基本概念
- 切面(aspect):代碼中的一些公共子產品的抽象,通常是一個類。
- 連接配接點(joinpoint):可能插入切面的點。
- 切入點(pointcut):(a predicate that matches join points)插入切面的連接配接點。
- 通知(advice):也就是攔截到連接配接點之後,要執行的代碼,也即是要執行的切面類的方法。通知有以下幾種類型:
before advice:連接配接點之前執行。
after return advice:連接配接點正常傳回後執行
after throwing advice:連接配接點抛出異常後執行
after(final) advice:連接配接點正常傳回或者抛出異常後都會被執行的
around advice: 連接配接點前後都執行
這裡我們可以總結一下連接配接點(joinpoint)、切入點(pointcut)、通知(advice)之間的關系:通過切入點的描述找到連接配接點,在連接配接點插入相應類型的advice。
- 目标對象:目标對象是要被攔截的對象,或者要被插入代碼的方法。
- AOP代理對象:是目标對象和插入的切面對象融合之後的對象。一個 AOP 代理對象是一個 JDK 動态代理對象(基于接口)或 CGLIB 代理對象(基于類)。
- 織入:切面和目标對象連接配接建立代理對象的過程。
(三)測試
接下來以一個執行個體說明,eclipse建立一個工程,工程視圖如下(截圖一部分),需要spring等相關jar包:
(1)核心業務接口和實作類
CoreService.java接口:
package com.spring.service;
public interface CoreService{
public void coreMethod();
public void coreBusiness();
}
(2)實作類
package com.spring.service;
public class ImpCoreService implements CoreService {
public void coreMethod(){
System.out.println("This is coreMethod");
}
public void coreBusiness(){
System.out.println("This is coreBusiness");
}
}
(3)切面類
package com.spring.aop;
public class Logger {
public void aopLogBefore(){
System.out.println("before");
}
public void aopLogAfter(){
System.out.println("after");
}
}
(4)測試主類:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.service.CoreService;
public class MainApp {
public static void main(String[] args) {
//建立Spring ApplicationContext 容器,利用配置檔案Beans.xml
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
//容器注入ImpCoreService對象
CoreService core = (CoreService)context.getBean("ImpCoreService");
core.coreBusiness();
System.out.println();
core.coreMethod();
}
}
(5)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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- bean 是一個被執行個體化,組裝,并通過 Spring IoC 容器所管理的對象 -->
<!-- id用于擷取對象使用 -->
<bean id="ImpCoreService" class="com.spring.service.ImpCoreService">
</bean>
<bean id="Logger" class="com.spring.aop.Logger">
</bean>
<aop:config>
<aop:aspect id="LoggerAspect" ref="Logger">
<!--aop:pointcut 描述了連接配接點,通過這個描述可知,這裡連接配接點是CoreService接口中的所有方法,也可以改變描述隻連接配接一個方法-->
<aop:pointcut id="TempPointcut" expression="execution(* com.spring.service.CoreService.*(..))" />
<!--一個前置和後置的advice執行個體-->
<aop:before method="aopLogBefore" pointcut-ref="TempPointcut" />
<aop:after method="aopLogAfter" pointcut-ref="TempPointcut" />
</aop:aspect>
</aop:config>
</beans>
這裡通過XML配置檔案來實作AOP(也可以通過注解),執行結果如下,可以看到切面對象插入到了目标對象中。或者說advice代碼插入到了業務代碼中。