什么是AOP ?
AOP:面向切面编程Aspect Oriented Programming
。AOP是一种思想,其主要用于对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性。
也就是说要解决其横切性问题。
横切性问题:不会影响主业务逻辑的操作,例如权限,日志,事务。
AOP应用场景
AOP常用的使用场景:
- 日志
- 权限
- 事务
- 监控
SpringAOP和AOP的关系
AOP是一种设计思想。而SpringAOP是AOP思想的实现。
扩展:SpringAOP和AspectJ AOP的关系?
- SpringAOP和AspectJ AOP都是AOP思想的实现
- SpringAOP借用了AspectJ AOP的语法
早期SpringAOP有自己的一套AOP语法,但由于非常难用,所以无人接受和使用,所以后续基于AspectJ AOP的语法实现了AOP,这里仅借用了AOP语法,也就是注解,实现还是基于Spring来实现的。
SpringAOP名词概念
Aspect:切面,可以说是join point,point cut,advice等的集合
Join point:连接点,也就是需要进行切入的类/方法等
Point Cut:切入点,join point的集合
Advice:通知。通知包括通知的内容/通知到哪里,即在哪个Point Cut通知什么内容
weaving:织入,也就是通知的过程
AOP proxy:代理对象,切入后所生成的代理对象
Target Object:目标对象,也就是需要切入的对象
具体的概念可以参考官方文档,这里仅做参考。
SpringAOP的使用
// 引入依赖
compile(project(":spring-aop"))
compile(project(":spring-aspects"))
// 开启AspectJ proxyTargetClass = false false默认 使用jdk动态代理 true使用CGLIB动态代理
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ComponentScan("mine.test")
public class AppConfig {}
//定义切面
@Aspect
@Component
public class IndexDaoAspect {
/* 切入点 方法名无所谓
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
modifiers-pattern: 修饰类型
ret-type-pattern: 返回类型
declaring-type-pattern:方法所在类的全路径名
name-pattern:方法名类型 queryTest()
param-pattern:方法的参数类型,String/Integer ...
throws-pattern:方法抛出的异常
*/
@Pointcut("execution(public * mine.test.dao.*.*(..))") // the pointcut expression
private void pointCutExecution() {
}
// 和execution的区别就是精度问题 within定义到类 execution更精确,比如参数类型,抛出异常等
@Pointcut("within(mine.test.dao.* )") // the pointcut expression
private void pointCutWithin() {
}
/* 代理对象,也就是AOP代理后生成的代理对象
注:当使用CGLIB代理时,this和target无区别
1. 因为CGLIB基于继承,最终目标对象和代理对象都是IndexDao/IndexDao子对象,所以this(IndexDao)和target(IndexDao)都能切入
2. 当使用JDK代理时,最终目标对象为IndexDao,而代理对象则不继承IndexDao,这是this(IndexDao)就无效了,仅target(IndexDao)能够切入
3. 所以this一般用来切入一个接口的所有实现类
*/
@Pointcut("this(mine.test.dao.Dao )")
private void pointCutThis() {
}
// 目标对象,也就是未进行AOP代理前的对象
@Pointcut("target(mine.test.dao.IndexDao)")
private void pointCutTarget() {
}
// 参数,切入粒度比较大,所有参数为String的方法
@Pointcut("@args(java.lang.String)")
private void pointCutArgs() {
}
//注解 切入注解
@Pointcut("@args(java.lang.String)")
private void pointCutAnnotation() {
}
// 通知 before:位置 pointCut() 逻辑
@Before("pointCutExecution()")
public void before(){
System.out.println("before");
}
}
// target object
public interface Dao {
public void query();
}
// target object
@Repository("indexDao")
public class IndexDao implements Dao {
@Override
public void query(){
System.out.println("Index dao query something");
}
}