一. Spring AOP 面向切面編程(也叫面向方面編程)
- AOP本質上就是一種代理模式
Aspect Oriented Programming(AOP)是 Spring框架中的核心內容之一。本質上是一種代理模式——Spring AOP就是基於動態代理的。
有了動態代理,Spring就可以對其管理的對象的業務邏輯處理流程進行干預——Spring可以在處理流程中插一腳,乾點什麼事。
可以乾點什麼呢?
分離業務代碼,提高程序的可重用性。
- AOP的應用場景和要解決的問題
AOP的應用場景是相互獨立的各個類的方法中總存在着一些相同的業務代碼。這些相同的業務代碼由於是分佈在不相干的各個類中(類之間甚至沒有公共的接口),要想通過繼承關係(垂直方向的代碼複用)進行代碼複用比較困難。把重複的代碼封裝成公共的方法再調用又會造成對各個類的代碼侵入(增加了耦合度)。所以就希望能有一種方式可以把分佈在不同類方法中的相同代碼段抽離出來複用,又不會對原來的各個類造成代碼的侵入。AOP應運而生。
- 使用AOP複用代碼
AOP的方法就是利用動態代理,代理各目標對象,然後將各個被代理類方法中相同的代碼片段統一拿到代理類中。這樣就好像在各個並列的被代理對象中橫向切一刀,把公共的代碼切片拿出來放到代理類中統一處理——這是一種橫向的代碼複用方式。
-
具體概念可以參考這裏
-
代碼實例
二. Spring AOP的示例
- Spring中使用AOP涉及的jar包
aopalliance.jar
aspectjweaver-1.6.6.jar
spring-aspects-4.0.6.RELEASE.jar
- Spring的配置文件配置AOP
<?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="studentServiceAspect" class="com.bee.advice.StudentServiceAspect"></bean>
<bean id="studentService" class="com.bee.service.impl.StudentServiceImpl"></bean>
<aop:config>
<aop:aspect id="studentServiceAspect" ref="studentServiceAspect">
AOP只能作用於方法,下邊的定義是用於匹配方法的(包括返回值,函數名,參數)。
匹配的方法就是StudentService接口中定義的抽象方法。
<aop:pointcut expression="execution(* com.bee.service.*.*(..))" id="businessService"/>
<aop:before method="doBefore" pointcut-ref="businessService"/>
<aop:after method="doAfter" pointcut-ref="businessService"/>
<aop:around method="doAround" pointcut-ref="businessService"/>
<aop:after-returning method="doAfterReturning" pointcut-ref="businessService"/>
<aop:after-throwing method="doAfterThrowing" pointcut-ref="businessService" throwing="ex"/>
</aop:aspect>
</aop:config>
</beans>
expression屬性值表達式的含義:
execution( * com.bee.service. * . * ( .. ) )
返回值 包路徑 類名 方法名 參數
其中*
表示匹配任意名稱,..
表示匹配任意個數的參數。
- 定義被代理的對象(目標對象Target)
package com.bee.service;
public interface StudentService {
void addStudent(String name);
}
------------------------------------------------------------------------
package com.bee.service.impl;
public class StudentServiceImpl implements StudentService{
@Override
public void addStudent(String name) {
// System.out.println("開始添加學生"+name); 不使用AOP產生的代碼侵入
System.out.println("添加學生"+name); //目標對象的業務邏輯
System.out.println(1/0); //目標對象產生異常
// System.out.println("完成學生"+name+"的添加"); 不使用AOP產生的代碼侵入
}
}
- 定義切面(Aspect)
這裏定義的是橫向抽取出來的公共代碼。
package com.bee.advice;
public class StudentServiceAspect {
public void doBefore(JoinPoint jp){
System.out.println("類名:"+jp.getTarget().getClass().getName());
System.out.println("方法名:"+jp.getSignature().getName());
System.out.println("開始添加學生:"+jp.getArgs()[0]);
}
public void doAfter(JoinPoint jp){
System.out.println("類名:"+jp.getTarget().getClass().getName());
System.out.println("方法名:"+jp.getSignature().getName());
System.out.println("學生添加完成:"+jp.getArgs()[0]);
}
public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("添加學生前");
Object retVal=pjp.proceed(); //執行目標對象匹配的方法
System.out.println(retVal);
System.out.println("添加學生後");
return retVal; //返回目標對象匹配方法的返回值
}
public void doAfterReturning(JoinPoint jp){
System.out.println("返回通知");
}
public void doAfterThrowing(JoinPoint jp,Throwable ex){
System.out.println("異常通知");
System.out.println("異常信息:"+ex.getMessage());
}
}
- 測試
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
StudentService studentService=(StudentService)ac.getBean("studentService");
studentService.addStudent("張麻子");