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