概念AOP介紹AOP核心概念AOP標籤配置元素AOP實現步驟實例基於XML基於註解java
AOP(Aspect-Oriented Programming:面向切面編程)可以將那些與業務無關,卻爲業務模塊所共同調用的邏輯或責任(例如事務處理、日誌管理、權限控制等)封裝起來,便於減小系統的重複代碼,下降模塊間的耦合度,並有利於將來的可拓展性和可維護性。web
Spring AOP 就是基於動態代理的,若是要代理的對象,實現了某個接口,那麼 Spring AOP 會使用 JDK Proxy,去建立代理對象,而對於沒有實現接口的對象,就沒法使用 JDK Proxy 去進行代理了,,這時候 Spring AOP會使用 Cglib 生成一個被代理對象的子類來做爲代理,以下圖所示:spring
除此以外還有一種狀況,若是被代理對象實現了接口,能夠強制使用 Cglib 實現 AOP。express
固然你也可使用 AspectJ ,Spring AOP 已經集成了AspectJ ,AspectJ 應該算的上是 Java 生態系統中最完整的 AOP 框架了。Spring AOP 基於註解配置的狀況下,須要依賴於 AspectJ 包的標準註解,可是不須要額外的編譯以及 AspectJ 的織入器,而基於 XML 配置不須要,因此 Spring AOP 只是複用了 AspectJ 的註解,並無其餘依賴 AspectJ 的地方。apache
使用 AOP 以後咱們能夠把一些通用功能抽象出來,在須要用到的地方直接使用便可,這樣大大簡化了代碼量。咱們須要增長新功能時也方便,這樣也提升了系統擴展性。日誌功能、事務管理等等場景都用到了 AOP 。編程
當 Spring 須要使用 @AspectJ 註解支持時,須要在 Spring 配置文件中以下配置:mvc
<aop:aspectj-autoproxy/>
複製代碼
而關於強制使用 Cglib,能夠經過在 Spring 配置文件以下實現:app
<aop:aspectj-autoproxy proxy-target-class="true"/>
複製代碼
proxy-target-class 屬性值決定是基於接口的仍是基於類的代理被建立,默認爲 false。若是 proxy-target-class 屬性值被設置爲 true,那麼基於類的代理將有效(這時須要 Cglib 庫)。反之是基於接口的代理(JDK的動態代理)。框架
因此,雖然使用了 AspectJ 的 Annotation,可是並無使用它的編譯器和織入器。其實現原理是 JDK 動態代理或 Cglib,在運行時生成代理類。maven
鏈接點:JoinPoint,就是要被攔截的方法
切入點:PointCut,定義在哪些類,哪些方法上切入(攔截)
通知:Advice,在攔截到鏈接點以後要執行的代碼,通知主要有五種,前置通知,後置通知,異常通知,最終通知和環繞通知。
切面:AspectJ,就是切入點加上通知
織入:weaving,把切面加入對象,並建立出代理對象的過程。
aop:aspect: 定義一個切面
aop:before: 定義一個前置通知
aop:after: 定義一個後置通知
aop:around: 定義一個環繞通知
aop:after-returning : 定義一個返回通知
aop:after-throwing :定義一個異常通知
aop:config: 頂層的aop配置元素
aop:pointcut: 定義切入點
繼續使用租房的案例,接下來新建一個切面類:
public class ProxyXML {
public void seeHouse(){
System.out.println("帶客戶看房子");
}
public Object getMoney(ProceedingJoinPoint p){
System.out.println("租房.....before");
Object o = null;
try{
o = p.proceed();
}catch(Throwable e){
e.printStackTrace();
}
System.out.println("租房.....after");
return o;
}
public void fare(){
System.out.println("收取中介費");
}
}
複製代碼
配置文件:
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="host" class="com.msdn.bean.Host" />
<bean id="proxy" class="com.msdn.aop.ProxyXML" />
<!--Spring基於Xml的切面-->
<aop:config>
<!--定義切點函數-->
<aop:pointcut id="rentPointCut" expression="execution(* com.msdn.bean.Host.rent())"/>
<!-- 定義切面 order 定義優先級,值越小優先級越大-->
<aop:aspect ref="proxy" order="0">
<!--前置通知-->
<aop:before method="seeHouse" pointcut-ref="rentPointCut" />
<!--環繞通知-->
<aop:around method="getMoney" pointcut-ref="rentPointCut" />
<!--後置通知-->
<aop:after method="fare" pointcut-ref="rentPointCut" />
</aop:aspect>
</aop:config>
</beans>
複製代碼
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring_study</artifactId>
<groupId>com.msdn</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-chap3</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
</dependencies>
</project>
複製代碼
測試代碼:
@Test
public void aopTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop.xml");
Object host = context.getBean("host");
Rent o = (Rent) host;
o.rent();
}
複製代碼
執行結果爲:
帶客戶看房子
租房.....before
房屋出租
租房.....after
收取中介費
複製代碼
切面類:
@Order(0)
@Aspect
@Component
public class ProxyAnnotation {
@Before(value = "execution(* com.msdn.bean.Host.rent())")
public void seeHouse(){
System.out.println("帶客戶看房子");
}
@Around(value = "execution(* com.msdn.bean.Host.rent())")
public Object getMoney(ProceedingJoinPoint p){
System.out.println("租房.....before");
Object o = null;
try{
o = p.proceed();
}catch(Throwable e){
e.printStackTrace();
}
System.out.println("租房.....after");
return o;
}
@After(value = "execution(* com.msdn.bean.Host.rent())")
public void fare(){
System.out.println("收取中介費");
}
}
複製代碼
切面類版本二:
@Order(0)
@Aspect
@Component
public class ProxyAnnotation2 {
@Pointcut("execution(* com.msdn.bean.Host.rent())")
public void rentPointCut(){
}
@Before(value = "rentPointCut()")
public void seeHouse(){
System.out.println("帶客戶看房子");
}
@Around(value = "rentPointCut()")
public Object getMoney(ProceedingJoinPoint p){
System.out.println("租房.....before,優先級更高");
Object o = null;
try{
o = p.proceed();
}catch(Throwable e){
e.printStackTrace();
}
System.out.println("租房.....after");
return o;
}
@After(value = "rentPointCut()")
public void fare(){
System.out.println("收取中介費");
}
}
複製代碼
配置文件:
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.msdn.bean,com.msdn.aop" />
<aop:aspectj-autoproxy proxy-target-class="true" />
</beans>
複製代碼
測試代碼:
@Test
public void aopTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop2.xml");
Object host = context.getBean("host");
Rent o = (Rent) host;
o.rent();
}
複製代碼
執行結果爲:
租房.....before
帶客戶看房子
房屋出租
租房.....after
收取中介費
複製代碼