AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
切 :指的是横切逻辑,原有业务逻辑代码不动,只能操作横切逻辑代码,所以面向横切逻辑。
面 :横切逻辑代码往往要影响的是很多个方法,每个方法如同一个点,多个点构成一个面。这里有一个面的概念。
AOP是Spring核心技术之一,引入maven坐标:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理。
下面定义接口,代理对象即切点,和相关类:
public interface PersonService {
Person createPerson(String name,Integer age,String company);
}
@Service
public class PersonServiceImpl implements PersonService{
public Person createPerson(String name, Integer age, String company) {
System.out.println("create-----");
return new Person(name,age,company);
}
}
public class Person {
private String name;
private Integer age;
private String company;
..省略get set 构造函数
}
下面为aop使用示例:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AspectService {
//定义切点函数,execution也支持模糊匹配 如execution(* com.zxy.aop.PersonServiceImpl.*(**))
//切点函数参数列表类型与代理对象函数参数列表相同,这是为了方便使用参数
@Pointcut(value = "execution(* com.zxy.aop.PersonServiceImpl.createPerson(String,Integer,String))&&
args(name,age,company))"
,argNames = "name,age,company")
public void point(String name,Integer age,String company){};
//函数执行前调用
@Before(value = "point(name,age,company)",argNames = "name,age,company")
public void before(String name,Integer age,String company){
System.out.println("before:"+name+"---"+age+"----"+company+"----");
}
//函数执行后调用
@After(value = "point(name,age,company)",argNames = "name,age,company")
public void after(String name,Integer age,String company){
System.out.println("after:"+name+"---"+age+"----"+company+"----");
}
//函数返回结果后调用
//returnValue可以获取返回结果
@AfterReturning(value = "point(name,age,company)",argNames = "name,age,company,returnValue",returning = "returnValue")
public void afterReturn(String name,Integer age,String company,Person returnValue){
System.out.println("return:"+name+"---"+age+"----"+company+"----");
System.out.println("returnValue:"+returnValue);
}
//函数抛出异常后调用,参数e获取抛出的异常
@AfterThrowing(value = "point(name,age,company)",argNames = "name,age,company,e",throwing = "e")
public void afterThrowing(String name,Integer age,String company,Exception e){
System.out.println("throw:"+name+"---"+age+"----"+company+"----");
System.out.println("throw:"+e);
}
//环绕函数调用
@Around(value = "point(name,age,company)",argNames = "joinPoint,name,age,company")
public Object around(ProceedingJoinPoint joinPoint, String name, Integer age, String company) throws Throwable {
System.out.println("aroundBefore"+name+"---"+age+"----"+company+"----");
Object[] args = joinPoint.getArgs();
res=joinPoint.proceed(args);
System.out.println("after");
return res;
}
}
hhh最后记得要在启动类或者配置类上开启EnableAspectJAutoProxy
@SpringBootApplication
@EnableAspectJAutoProxy
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
也可以使用自定义注解修饰代理对象
自定义一个注解,用来修饰方法
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MyTestAnnotation {
String value() default "default";
}
用自定义的注解修饰方法:
@MyTestAnnotation(value = "testAOP getPerson")
public Person getPerson(String name)
{
System.out.println("get person");
return new Person(name,33,"xxxxx");
}
aop使用示例:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Component
@Aspect
public class TestAnnotationAspect {
@Pointcut("@annotation(com.zxy.aop.MyTestAnnotation)")
public void pointcut(){};
@Around(value = "pointcut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature=(MethodSignature)joinPoint.getSignature();
Method method=signature.getMethod();
MyTestAnnotation myTestAnnotation = method.getAnnotation(MyTestAnnotation.class);
String value = myTestAnnotation.value();
System.out.println("around before");
System.out.println(value);
Object proceed = joinPoint.proceed(joinPoint.getArgs());
System.out.println(proceed);
System.out.println("around after");
}
}