1AOP概述
AOP:是一种面向切面的编程范式,是一种编程思想,旨在通过分离横切关注点,提高模块化,可以跨越对象关注点。
面向切面编程:是指在程序运行期间将某段代码,动态的切入到某个类的指定方法的指定位置的这种编程思想叫做面向切面编程。
AOP编程操作的主要对象是切面(aspect),而切面模块化横切关注点。
AOP的典型应用即spring的事务机制,日志记录。
AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理,静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。
- AspectJ是一种编译期的用注解形式实现的AOP。
- Spring AOP是在运行期基于动态代理的方式将aspect织入目标代码
AOP的好处:
- 用于横切关注点的分离和织入横切关注点到系统,如日志;
- 完善OOP;
- 降低组件和模块之间的耦合性;
- 使系统容易扩展;
- 而且由于关注点分离从而可以获得组件的更好复用
2AOP术语
- 切面(Aspect)–“在哪干和干什么集合”
通知和切入点的组合 通知(Advice)–“干什么”
分为前置、后置、异常、最终、环绕通知五类顾问(Advisor):切面的另一种实现
Advice 和 Pointcut 组成的独立的单元,并且能够传给 proxy factory 对象目标(Target)–“对谁干”
将要被增强的对象,即包含主业务逻辑的类的对象。切入点(Pointcut )–“在哪里干的集合”
连接点(JoinPoint)– “在哪里干”
连接点是指可以被切面织入的方法。即被拦截到的方法。- 代理(Proxy)–通过代理来对目标对象应用切面
目的就是将切面织入到目标对象 - 横切关注点:从每个方法中抽取出来的同一类非核心业务。
Spring AOP
简介
- Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。
定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理
Spring默认使用Java动态代理来创建AOP代理
- 当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理
代理模式
- 代理类和被代理类实现共同的接口(或继承)
- 代理类中存有指向被代理类的索引
- 执行时通过调用代理类的方法、实际执行的是被代理类的方法
JDK代理
- 实现InvocationHandler
- 使用Proxy.newProxyInstance产生代理对象
- 被代理的对象必须要实现接口
public class JDKProxy implements InvocationHandler {
private Object targetObject;//需要代理的目标对象
//将目标对象传入进行代理
public Object newProxy(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);//返回代理对象
}
public Object invoke(Object proxy, Method method, Object[] args)//invoke方法
throws Throwable {
checkPopedom();//逻辑处理函数
Object ret = null; // 设置方法的返回值
//通过反射机制来运行目标对象的方法
ret = method.invoke(targetObject, args); //调用invoke方法,ret存储该方法的返回值
return ret;
}
private void checkPopedom() {//模拟检查权限的例子
System.out.println(".:检查权限 checkPopedom()!");
}
}
JDK动态代理和CGLIB代理的区别
- JDK动态代理只能对实现了接口的类生成代理,而不能针对类
- CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
- CGLib不能对声明为final的方法进行代
AspectJ
配置< aop:aspectj-autoproxy>
当Spring IOC容器侦测到bean配置文件中的< aop:aspectj-autoproxy>元素时,会自动为与AspectJ切面匹配的bean创建代理要在Spring中声明AspectJ切面,只需要在IOC容器中将切面声明为bean实例。
当在Spring IOC容器中初始化AspectJ切面之后,Spring IOC容器就会为那些与
AspectJ切面相匹配的bean创建代理。在AspectJ注解中,切面只是一个带有@Aspect注解的Java类,它往往要包含很多通知。
通知是标注有某种注解的简单的Java方法。
AspectJ支持5种类型的通知注解:
[1]@Before:前置通知,在方法执行之前执行
[2]@After:后置通知,在方法执行之后执行
[3]@AfterRunning:返回通知,在方法返回结果之后执行
[4]@AfterThrowing:异常通知,在方法抛出异常之后执行
[5]@Around:环绕通知,围绕着方法执行
切面表达式
匹配类型 + 通配符 + 逻辑运算符
1.匹配方法@excute
2.匹配包/类型within
//声明切入点PointCut
//匹配Query类里所有方法
@Pointcut("within(com.moni.service.Query)")
public void matchQuery(){}
//匹配包里所有方法
@Pointcut("within(com.moni.service..*)")
public void matchService(){}
//声明Advice
@Before("matchService())")
public void before(){}
@After("matchQuery()")
public void after(){}
public void match(){}
3.匹配对象
@this()
@target()
@bean()
4.匹配参数@args
//匹配所有以find开头 且只有一个Long型参数的方法
@Pointcut("excution(**..find*(Long))")
//匹配所有只有一个Long型参数的方法
@Pointcut("args(Long)")
5.匹配注解@Annotation
切入点execution表达式
//任意公共方法的执行
@Pointcut("execution(public * *(..))")
@Pointcut("execution(* com.moni.service..*.*(..))")
//任意返回值-service包-包及下任意子包-所有类-所有方法-任意参数