面向切面编程的缩写。常用于日志、审计、声明式事务、安全和缓存等方面,甚至可以在不修改原有代码的情况下添加新逻辑,非常实用。
AOP术语:
Aspect | 切面 |
Join point | 程序执行时的点,通常是方法 |
Advice | 方法执行前/后的动作 |
Pointcut | advice执行的切入点 |
Introduction | 为已存在的类添加方法或属性 |
Target object | 切面作用的对象 |
AOP proxy | AOP框架创建的用于完成切面动作的对象 |
Weaving | 连接应用对象与切面的过程 |
Advice类型:
before | 方法执行前运行advice |
after | 方法执行后运行advice |
after-returning | 方法执行完全成功后运行advice |
after-throwing | 方法执行出现异常并退出后运行advice |
around | 运行方法前和后都执行advice |
可选择基于xml和基于注解方式的配置,但是现在的Spring Boot/Cloud都是用Java配置了,所以还是用注解吧,xml文件要写一大堆东西。
使用AOP需要添加AspectJ的两个依赖,在pom.xml文件里添加:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
版本不用添加,Spring Boot有内置的管理的版本。
然后创建一个普通的对象,一些方法,可以用作切入点,比如HelloWorld.java:
package com.explause.aopExamples;
public class HelloWorld {
private String message;
public void setMessage(String message){
this.message = message;
}
public String getMessage(){
return message;
}
public void throwException() throws Exception{
System.out.println("Exception raised");
throw new RuntimeException("An exception.");
}
}
然后创建HelloWorld的切面配置文件,HelloWorldAspect.java:
package com.explause.aopExamples;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class HelloWorldAspect {
@Pointcut("execution(* com.explause.aopExamples.HelloWorld.*(..))")
private void selectAll() {}
@Before("selectAll()")
public void beforeAdvice(){
System.out.println("In the beforeAdvice.");
}
@After("selectAll()")
public void afterAdvice(){
System.out.println("In the afterAdvice.");
}
@AfterReturning(pointcut = "selectAll()", returning = "retVal")
public void afterReturningAdvice(Object retVal) {
System.out.println("In the afterReturningAdvice:" + retVal.toString() );
}
@AfterThrowing(pointcut = "selectAll()", throwing = "ex")
public void AfterThrowingAdvice(Exception ex){
System.out.println("In the AfterThrowingAdvice: " + ex.toString());
}
}
上面@Aspect注解表示这是一个切面配置。
@Pointcut(“execution(* com.explause.aopExamples.HelloWorld.*(..))”)表示执行HelloWorld内的任何访问权限(public、private或者package)的接受任何参数的任何方法,都是一个切入点。
可以按需定制,具体的文档在eclipse的官方文档。
创建Bean配置文件BeanConfig.java:
package com.explause.aopExamples;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
public class BeanConfig {
@Bean
public HelloWorld hw() {
HelloWorld hw = new HelloWorld();
hw.setMessage("message in hw");
return hw;
}
@Bean
public HelloWorldAspect aop() {
return new HelloWorldAspect();
}
}
切面配置同样需要注册为Bean,还要添加@EnableAspectJAutoProxy注解开启AOP。
创建main函数(方法)AnnotationConfigDemo.java:
package com.explause.aopExamples;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AnnotationConfigDemo {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext("com.explause.aopExamples");
HelloWorld hw = context.getBean(HelloWorld.class);
hw.getMessage();
hw.throwException();
context.close();
}
}
输出结果: