AOP的概念
AOP(Aspect Oriented Programming),即面向切面程式設計,利用一種稱為"橫切"的技術,剖開封裝的對象内部,并将那些影響了多個類的公共行為封裝到一個可重用子產品,并将其命名為"Aspect",即切面。所謂"切面",簡單說就是那些與業務無關,卻為業務子產品所共同調用的邏輯或責任封裝起來,便于減少系統的重複代碼,降低子產品之間的耦合度,并有利于未來的可操作性和可維護性。
AOP開發術語
- 連接配接點(Joinpoint):連接配接點是程式類中客觀存在的方法,可被Spring攔截并切入内容。
- 切入點(Pointcut):被Spring切入連接配接點。
- 通知、增強(Advice):可以為切入點添加額外功能,分為:前置通知、後置通知、異常通知、環繞通知等。
- 目标對象(Target):代理的目标對象
- 引介(Introduction):一種特殊的增強,可在運作期為類動态添加Field和Method。
- 織入(Weaving):把通知應用到具體的類,進而建立新的代理類的過程。
- 代理(Proxy):被AOP織入通知後,産生的結果類。
- 切面(Aspect):由切點和通知組成,将橫切邏輯織入切面所指定的連接配接點中。
AOP增強類
前置增強:MethodBeforeAdvice
後置增強:AfterAdvice
後置增強:AfterReturningAdvice
異常增強:ThrowsAdvice
環繞增強:MethodInterceptor
切入點表達式
比對包名:execution(* com.robot.service.* .*(…))
- 傳回值任意,com.robot.service包下面的任意類,下面的任意方法,參數任意
<!--比對參數-->
<aop:pointcut id="myPointCut" expression="execution(* *(com.robot.pojo.User))" />
<!--比對方法名(無參)-->
<aop:pointcut id="myPointCut" expression="execution(* save())" />
<!--比對方法名(任意參數)-->
<aop:pointcut id="myPointCut" expression="execution(* save(..))" />
<!--比對傳回值類型-->
<aop:pointcut id="myPointCut" expression="execution(com.robot.pojo.User *(..))" />
<!--比對類名-->
<aop:pointcut id="myPointCut" expression="execution(* com.robot.service.userService.impl.UserServiceImpl.*(..))" />
<!--比對包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.robot.service.*.*(..))" />
<!--比對包名、以及子包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.robot..*.*(..))" />
AOP的實作
1、環境搭建
導入依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
在配置檔案中引入AOP命名空間
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
">
</beans>
2、建立切面類
- 以後置增強為例
- 基礎AfterReturningAdvice接口,重寫afterReturning方法
public class MyAfterAdvice implements AfterReturningAdvice {
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("後置增強:" + method.getName() + " 增強方法:" + o.getClass().getSimpleName());
}
}
3、建立需要被增強的類和接口
- 将要實作的效果就是,在調用此方法時,此方法會被增強
public interface UserDao {
int insert();
}
public class UserDaoImpl implements UserDao {
public int insert() {
System.out.println("UserDaoImpl::insert...");
return 0;
}
}
4、修改配置檔案
- 配置aop,expression為切入點表達式
- 具體行為execution(* com.robot.service.* .*(…)):傳回值任意,com.robot.service包下面的任意類,下面的任意方法,參數任意
<bean name="userService" class="com.robot.service.impl.UserServiceImpl"/>
<bean name="myAfterAdvice" class="com.robot.aop.MyAfterAdvice"/>
<aop:config>
<aop:pointcut id="myPointcut" expression="execution(* com.robot.service.*.*(..))"/>
<aop:advisor advice-ref="myAfterAdvice" pointcut-ref="myPointcut"/>
</aop:config>
5、測試
- 調用service層中的方法
public class UserServiceTest {
@Test
public void userServiceTest() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.insert();
}
}
結果如下
UserDaoImpl::insert...
後置增強:insert 增強方法:Integer
在被調用的insert()方法的後面切入了增強方法,輸出了方法内的語句,說明方法增強成功
總結
- 通過AOP提供的編碼流程,更便利的定制切面,更友善的定制了動态代理。
- 進而徹底解決了輔助功能備援的問題;
- 業務類中職責單一性得到更好保障;
- 輔助功能也有很好的複用性。