1、spring aop 基礎
spring 有兩大核心功能,DI 和 AOP。DI有助于應用之間的解耦,而AOP可以實作橫切關注點與他們所影響的對象之間的解耦。spring 隻支援方法級别的連接配接點。
什麼是面向切面程式設計?切面能幫助我們子產品化橫切關注點。橫切關注點可以被子產品化為特殊的類,這些類被稱為切面。面向切面程式設計,可以讓我們把更多的注意力放在最重要的業務邏輯代碼,而次要關注的代碼放在切面裡。
2、通知
通知定義了切面是什麼以及切面什麼使用。通知有五種類型:
- Before: 在目标方法執行之前調用切面。
- After:在目标方法之後調用切面。
- After-returning:目标方法執行之後調用通知
- AfterThrowing:在目标方法抛出異常後調用通知
- Around: 在目标方法調用之前和調用之後執行自定義的行為
3、程式設計實作
(1)添加依賴
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
(2)使用注解@EnableAspectJAutoProxy開啟 AOP功能支援
@EnableAspectJAutoProxy
@Configuration
public class BeanConfig {
@Autowired
private DruidDataSource druidDataSource;
@Bean
public JdbcTemplate jdbcTemplate(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(druidDataSource);
return jdbcTemplate;
}
}
(3)具體代碼
-
使用@Aspect注解表明這是一個切面Bean
-
使用@Before @After等注解來表明通知類型
-
使用@Pointcut來實作:重用切面表達式
-
使用@Order來定義切面的優先級
package com.fengche.online.config;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 計算每一個controller執行的時間
* Created by Administrator on 2018/9/20
*/
@Component
@Aspect
//設定切面的優先級:值越小,優先度越高
@Order(1)
public class TimeAopConfig {
private static long beginTime = 0;
/**
* 重用切面表達式
* 參考https://docs.spring.io/spring/docs/4.3.15.RELEASE/spring-framework-reference/html/aop.html
*
* execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
* throws-pattern?)
*
* execution(<修飾符模式>?<傳回類型模式><方法名模式>(<參數模式>)<異常模式>?)
*/
@Pointcut(value = "execution(public * com.fengche.online.controller.*.*(..))")
public void aspect(){
}
@Before(value = "aspect()")
public void before(){
beginTime = new Date().getTime();
}
@After(value = "aspect()")
public void after(JoinPoint joinPoint){
long currentTime = new Date().getTime();
long runTime = (currentTime - beginTime);
String packageName = joinPoint.getSignature().getDeclaringTypeName();
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
// logger.info();
System.out.println(packageName + " " +methodName + " Action run time: " + runTime + "ms");
}
/**
* 異常通知
* 在目标方法抛出異常後調用通知
*/
@AfterThrowing("aspect()")
public void afterThrowing(){
}
/**
* 傳回通知
* 在目标方法成功執行之後調用通知
*/
@AfterReturning("aspect()")
public void returning(){
}
/**
* 環繞通知
* 通知包裹了被通知的方法,在被通知的方
* 法調用之前和調用之後執行自定義的行為
*/
@Around("aspect()")
public void aroud(){
}
}
參考:
1、spring 實戰 第四版
2、官方文檔:
https://docs.spring.io/spring/docs/4.3.15.RELEASE/spring-framework-reference/html/aop.html