一、Spring AOP
1. 常用注解
- @AspectJ 声明一个切面
- @Before 、@After 、@AfterReturning 、@Afterthrowing
- @Transactional
- @DeclareParents
2. AOP 术语
1. 连接点(join point ):
什么类的什么方法需要使用AOP
2. 切点( point cut ):
有时候我们的切面不单单应用于单个方法,也可能是多个类的不同方法,这时可以通过正则式和指示器的规则去定义,从而适配连接点。切点就是提供这样个功能的概念
// 拦截里面的正则匹配的方法
@Pointcut (execution("* com.xx.xx(..)")
public void pointCut(){}
3. 通知( advice ):
按照约定的流程,分为 before advice、 after advice、around advice、afterRetuming advice 、after Throwing advice
4. 目标对象(target):
即被代理对象
5. 引入( introduction ):
是指引入新的类和其方法 增强现有 Bean 的功能
6. 织入 weaving ):
通过动态代理技术,为原有服务对象生成代理对象 然后将与切点定义匹配的连接点拦截 ,并按约定将各类通知织入约定流程的过程
7. 切面( aspect ):
是一个可以定义切点、各类通知和引入的内容, SpringAOP 将通过它的信息来增强 Bean 的功能或者将对应的方法织入流程
流程:
- 确定连接点 (什么类的什么方法需要增强)
- 创建一个切面类 (@Aspect ,@Before,@After…)
- 定义一个切点(@Pointcut (execution("* com.xx.xx(…)") )
- 织入
3. 环绕通知
环绕通知是一个取代原有目标对象方法的通知,它也提供了回调原有目标对象方法的能力
@Around ("pointCut" )
public void around(ProceedingJoinPoint jp) throws Throwable{
sout("around before");
// 回调目标对象的原有方法
jp.method();
sout("around after");
}
4. 引入
@DeclareParents(value="", defaultImpl="") 引入新的类来增强服务
- value :指向你要增强功能的目标对象 ,如UserServicelmpl +
- defaultImpl: 引入增强的功能 ,如UserValidatorlmpl
原理: newProxyInstance 的第二个参数为一个对象数组,可以传递多个接口,如(UserValidator,UserService),让代理对象下挂到这两个接口,这样代理对象就可以互相转换这两个接口来使用各执的方法
5. 通知获取参数
// 约定将连接点(目标对象方法)名称为user的参数传递进来
// 参数JointPoint类型 对于非环绕通知而言
// 对于环绕通知而言,可以使用ProceedingJointPoint类型的参数
@Before("pointCut() && args(user)")
public void before(JoinPoint point ,User user) {}
6. 织入
织入是一个生成动态代理对象并且将切面和目标对象方法编织成为约定流程的过程。推荐采用接口+实现类的模式。
7. 多个切面
多个切面运行时的顺序
- @Order
- Ordered 接口,实现getOrder() 方法
二. JDK动态代理与CGLIB
当你需要使用 AOP 的类拥有接口时 它会以JDK动态代理运行,否则以 CGLIB(代码生成库) 运行
/// classLoade 类加载器
/// interfaces 绑定的接口,也就是把代理对象绑定到哪些接口下 可以是多个
/// invocationHandler绑定实现了InvocationHandler接口的代理对象的逻辑实现
// Proxy.newProxyinstance
public static Object newProxyinstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler invocationHandler) throws IllegalArgumentException{
}
/**
* InvocationHandler接口定义了一个invoke方法处理代理对象方法逻辑
* @param proxy 代理对象
* param me hod 当前方法
* @param args 运行参数
* @return 方法调用结果
*/
public Object invoke(Object proxy , Method method , Object[] args);