AOP概述
面向切面编程,实际是一种编程思想。
AOP的实践:
- 匹配方法:
- 方法插入位置(before–after–afterThrowing–afterReturning–around):切面
- 通知(advise):切面+处理的逻辑
实现方式:责任链模式+观察者模式(回调机制)
核心类:
- MethodInterceptor
- InvocationHandler:JDK动态代理
SpringAOP设计的主要目的是将多个方法中的公用逻辑抽离出来,封装在一个Interctor拦截器中,然后使用该拦截器对这些方法的调用Invocation进行拦截,从而将这些公用逻辑添加回去,完成一次完整的方法调用。
原理:让JVM根据需求动态生成字节码(可存在内存中,可写入硬盘中的class文件),从而出现了java asm框架。
- 如何动态生成?
重新生成,或在原class文件基础之上,直接添加日志处理的相关逻辑。- asm是什么?
ASM是一个通用的Java字节码操作和分析框架。 它可以用于修改现有类或直接以二进制形式动态生成类。 ASM提供了一些常见的字节码转换和分析算法,可以从中构建自定义复杂转换和代码分析工具。 ASM提供与其他Java字节码框架类似的功能,但专注于性能。 因为它的设计和实现尽可能小而且快,所以它非常适合在动态系统中使用(但当然也可以以静态方式使用,例如在编译器中)。
从应用程序编码到应用程序执行的完整过程来看:
首先在应用代码的方法中定义业务逻辑,然后在xml文件中使用AOP相关的标签描述这个方法或者在这个方法中添加AOP相关的注解,此时应用程序编码层面的工作已经完成了;
然后在运行应用程序,执行这个方法之前,首先需要加载这个方法所在的类,对于普通方法,直接调用对应方法即可;而对于使用了SpringAOP功能的方法,则需要结合xml文件或者注解来在运行时动态生成这个类的代理类,这个代理类集成了拦截器提供的公用逻辑和应用代码中方法定义的业务逻辑。然后实际调用和执行的是这个代理类的方法:一般为先执行拦截器的方法,然后执行应用方法定义的业务逻辑,最后进行执行拦截器的方法,即在业务逻辑方法执行前后可以定义执行拦截器的方法,这样就可以将抽离的公用逻辑添加回去。这样在方法执行层面,跟在应用方法中实现全部逻辑,即公用逻辑和业务逻辑,达到一样的效果。
Spring的AOP在接口设计层面参照了Aspectj框架的概念,但是不依赖与Aspectj框架的实现。以下具体分析基础接口设计。
AOP包结构
如何定义对应功能角色
Advice:辅助功能定义
- AfterAdvice:目标执行后来执行的辅助功能
- BeforeAdvice:目标执行前来执行的辅助功能
PointCut:辅助功能的目标方法
- ClassFilter:类过滤器
- MethodMatcher:方法匹配器.给定类和方法,看该方法是否需要该辅助功能。
Advisor:辅助功能和目标方法的融合
- MethodInterceptor:目标方法执行拦截器。
MethodInvocation:目标方法调用
- ProxyMethodInvocation通过代理对象来包装目标类对象,并通过代理方法来执行目标方法。
通过为目标对象添加额外接口的方式添加辅助功能
- IntroductionInfo:定义提供辅助功能的接口集合
- IntroductionAdvisor:将IntroductionInfo包含的接口集合添加到目标类中,即目标类额外实现该接口集合的接口。之后可以直接通过目标类对象访问这些接口的方法。
- DynamicIntroductionAdvice:判断给定的接口是否是IntroductionInfo提供的,即是否在IntroductionInfo定义的接口集合中。
- IntroductionAwareMethodMatcher:判断目标类的给定方法是否为IntroductionInfo中的接口集合中的某个接口中定义的方法。
Spring AOP和IOC的关系
AOP依赖于IOC来实现,在AOP中,使用一个代理类来包装目标类,在代理类中拦截目标类的方法执行并织入辅助功能。在Spring容器启动时,创建代理类bean替代目标类注册到IOC中,从而在应用代码中注入的目标类实例其实是目标类对应的代理类的实例,即使用AOP处理目标类生成的代理类。
|-----------------------------------------------break line-------------------------------------------------------|
如何配置AOP
- 在应用代码中,可以通过在spring的XML配置文件applicationContext.xml或者基于注解方式来配置AOP。
- AOP配置的核心元素为:pointcut,advisor,aspect,pointcut用于定义需要该辅助功能的类或方法集合;advisor则是将advice和pointcut结合起来,在spring的IOC容器启动时,为pointcut匹配的类生成代理对象,使用拦截器拦截对应的方法的执行,将辅助功能advice添加进去;aspect表示一个完整切面,即在aspect对应的类中定义辅助方法advice,然后在aspect中组装到pointcut拦截的方法集合中。
xml配置:
- 基于aspect配置
写一个增强定义类;
在xml中定义切入点且关联切入点和增强定义类:
- 基于advisor:
- 与aspect不同的是,需要对每个advice都定义一个类,然后使用advisor组装到pointcut拦截的方法。
- 辅助方法对应的类定义:其中一个环绕增强AroundAdvice定义。
基于注解的配置方式
- 略
- 冷门小知识:环绕通知的切点方法前的代码先执行还是@before标注的代码先执行?
内部源码解析
- 在内部源码实现当中,主要是在spring容器启动,加载解析applicationContext.xml时,解析对应的标签来完成AOP相关组件的加载。
- 与spring的其他标签解析规则一样,在spring-aop源码包的META-INF目录的spring.handlers文件中定义aop命令空间解析器:
AopNamespaceHandler源码如下:
-
核心逻辑为:首先创建一个BeanPostProcessor接口的实现类AspectJAwareAdvisorAutoProxyCreator的对象注册到spring中,具体为BeanPostProcessor的子接口InstantiationAwareBeanPostProcessor接口的实现类。
-
AspectJAwareAdvisorAutoProxyCreator的作用是在spring创建每个bean对象实例时,都检查一下是否在pointcut的拦截范围内,如果存在则需要结合advisor获取辅助方法为该bean对象创建对应的代理对象来注册到spring的IOC容器,即实际注册到spring的IOC容器的不是bean对象自身而是该代理对象,AspectJAwareAdvisorAutoProxyCreator的核心方法为postProcessBeforeInstantiation:
注:本文大量材料来自https://blog.csdn.net/u010013573/article/details/88324682;只在此基础上增加了自己的理解作为知识梳理。请