什么是AOP,请看我之前写的手写一个AOP的实现
AOP场景演示
使用Spring的AOP功能演示一个案例,来说明一下Spring中AOP的使用
AOP:底层实现就是动态代理,指的是在程序运行期间动态的将某段代码切入到指定位置运行的编程方式
使用步骤
1、导入aop模块
<dependency> |
2、创建一个业务逻辑的类
public class MathCalculator { |
在业务逻辑运行的时候,将日志打印,方法之前、运行方法结束、方法出现异常我们都希望将日志打印出来。
3、定义一个日志切面类,日志切面类里面的方法需要动态感知MathCalculator.div运行到哪里,进行执行
public class LogAspects { |
通知方式:
- 前置通知(@Before):logStart(),在目标方法(div)运行之前运行
- 后置通知(@After):logEnd(),在目标方法(div)运行之后运行,无论方法是正常结束还是异常结束
- 返回通知(@AfterReturning):logReturn(),在目标方法(div)正常返回之后运行
- 异常通知(@AfterThrowing):logException(),在目标方法(div)出现异常以后运行
- 环绕通知(@Around):动态代理,手动推进目标方法的运行(joinPoint.procced())
4、给切面类的目标方法标注何时何地运行,(标注通知注解),并且可以获取到参数信息,以及返回值信息
|
- JoinPoint必须放在参数表的第一位,否则会报错
5、将切面类和目标逻辑类(目标方法)都加入到容器中;
|
6、必须告诉spring,哪个类是切面类——给切面类加一个注解(@Aspect)
|
7、开启基于注解的AOP功能,在配置类上面标注一个注解@EnableAspectJAutoProxy
|
<!--基于xml可以这样写,开启自动代理--> |
8、编写测试方法,看一下切面能否成功
|
AOP原理
@EnableAspectJAutoProxy
进入该注解的实现
.class) //导入了一个组件 (AspectJAutoProxyRegistrar |
AspectJAutoProxyRegistrar
是一个实现了ImportBeanDefinitionRegistrar
接口的类,ImportBeanDefinitionRegistrar
作用是给容器中导入组件,在IOC章节介绍过
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { |
AspectJAutoProxyRegistrar
利用ImportBeanDefinitionRegistrar
给容器中注册了一个bean:org.springframework.aop.config.internalAutoProxyCreator
= AnnotationAwareAspectJAutoProxyCreator
这个类的意思是注解模式自动的切面代理创建器。这个是主要实现的类
AnnotationAwareAspectJAutoProxyCreator分析
这是该类的继承关系,该类的上层父类AbstractAutoProxyCreator
实现了SmartInstantiationAwareBeanPostProcessor
接口和BeanFactoryAware
接口SmartInstantiationAwareBeanPostProcessor
:是一个后置处理器,在bean初始化完成前后做一些事情BeanFactoryAware
:用于自动注入bean工厂。获取bean用的。
接下来我门要看一看AbstractAutoProxyCreator
类在初始化bean前后做了什么操作以及在获取bean工厂是怎么获取的,我们一步一步的进行分析
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport |
那么我们再来看AbstractAdvisorAutoProxyCreator
类
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator { |
AspectJAwareAdvisorAutoProxyCreator
没有重写方法,我们直接看AnnotationAwareAspectJAutoProxyCreator
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { |
我们将这个初始化AOP的代码关系看明白以后,我们看看创建的步骤
1、我们首先创建了一个IOC容器
2、注册配置类,调用refresh()
刷新容器
3、在refresh()
方法中有一个方法为registerBeanPostProcessors(beanFactory);
注册bean的后置处理器,方便拦击bean的创建
- 获取IOC容器已经定义了
BeanPostProcessor
接口的类 - 给容器中加入一些别的
BeanPostProcessor
- 优先注册实现了
PriorityOrdered
接口的BeanPostProcessor
- 再给容器中注册实现了
Ordered
接口的BeanPostProcessor
- 最后注册没有实现优先级接口的
BeanPostProcessor
- 注册
BeanPostProcessor
实际上是创建对象,然后保存到容器中,创建出org.springframework.aop.config.internalAutoProxyCreator[AnnotationAwareAspectJAutoProxyCreator]
- 创建bean实例
populateBean
给bean的各种属性赋值initializeBean
:初始化beaninvokeAwareMethods()
:处理Aware接口的方法回调,这里的处理是BeanNameAware
、BeanClassLoaderAware
、BeanFactoryAware
这三个,其余的是在后置处理器处理的applyBeanPostProcessorsBeforeInitialization()
应用后置处理器的PostProcessorsBeforeInitialization()
方法invokeInitMethods()
执行初始化方法applyBeanPostProcessorsAfterInitialization()
执行后置处理器的PostProcessorsAfterInitialization()
方法
AnnotationAwareAspectJAutoProxyCreator
创建成功,并且在invokeAwareMethods()
方法中调用了AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()
方法
- 将
BeanPostProcessor
注册到BeanFactory
中
这样我们的AnnotationAwareAspectJAutoProxyCreator
就加入到了IOC容器中,因为AnnotationAwareAspectJAutoProxyCreator
也是一个后置处理器,会拦截bean的初始化过程,那么我们来看一看他到底在初始化的时候做了些什么
首先我们要注意一点,AnnotationAwareAspectJAutoProxyCreator
的父类实现的是InstantiationAwareBeanPostProcessor
的后置处理器
我们还是从创建容器开始,创建容器后有refresh()
方法,其中有一个方法是finishBeanFactoryInitialization(beanFactory);
创建剩余的bean,什么叫剩余的bean呢,就是在此之前已经创建了很特殊的bean,如后置处理器等,我们从这里开始分析AnnotationAwareAspectJAutoProxyCreator
做了什么
1、finishBeanFactoryInitialization(beanFactory)
:创建单实例bean,这里的创建是创建除去上面创建后置处理器的bean剩下的bean
- 遍历获取容器中左右的bean,依次创建对象
getBean(beanName)
- 在创建bean之前会去缓存中检查是否已经创建了相应的bean,如果创建了那么就包装一下返回,没有创建才会去创建,创建好的bean都会被缓存起来。
createBean(beanName, mbd, args)
才是真正的创建bean- 创建bean之前,调用
resolveBeforeInstantiation(beanName, mbdToUse)
,这句话有一个注释Give BeanPostProcessors a chance to return a proxy instead of the target bean instance
,注释的意思是说给beanpostprocessor一个机会来返回代理而不是目标bean实例,在这里来创建一个代理对象实现AOP。其中最主要的两个方法- bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);拿到所有后置处理器,如果是实现了
InstantiationAwareBeanPostProcessor
的后置处理器,就执行postProcessBeforeInstantiation
方法,所以实现了InstantiationAwareBeanPostProcessor
的类。都会在创建bean之前对bean的创建做一个拦截从而能影响bean的创建。 - bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);这是初始化后的后置处理器方法,因为上面如果创建代理成功,那么就已经初始化过了,所以需要在这里调用after拦截。
- bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);拿到所有后置处理器,如果是实现了
- 如果不能返回代理对象,那就调用
doCreateBean(beanName, mbdToUse, args)
创建bean
- 创建bean之前,调用
分析一下如何创建的代理
之前说到,在创建bean之前,会调用resolveBeforeInstantiation()
方法,这个方法会调用InstantiationAwareBeanPostProcessor
接口的postProcessBeforeInstantiation()
方法去尝试创建代理,那么这个postProcessBeforeInstantiation()
方法是如何执行的呢?就要用到最上面我们分析的AbstractAutoProxyCreator
中的postProcessBeforeInstantiation()
方法了。接下来我们就来分析这个方法的实现,到底是如何创建代理对象的。
1、判断当前bean是否在adviceBeans中,adviceBeans里面包含了所有需要增强的bean,也就是需要代理的bean
2、isInfrastructureClass(beanClass)
判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean或者是不是切面(看bean是不是有@Aspect注解)
3、shouldSkip(beanClass, beanName)
是否需要跳过,
- 获取候选的增强器(切面里面的通知方法)
- 获取完成后,判断是否是
AspectJPointcutAdvisor
类型的增强器 - 如果不是这种类型的返回false
4、当上面都不成立的时候,下面的判断方法是为只有设置了目标源TargetSource
才能来创建的,我们没有任何的TargetSourcecustom
所有后面的也不会生效,所以这个创建bean不是在Before进行创建的,这里spring是直接返回null。
5、调用MathCalculator
的初始化器将对象创建出来。
6、然后调用AbstractAutoProxyCreator
的postProcessAfterInitialization()
方法,对初始化完的bean进行包装。
|
wrapIfNecessary(bean, beanName, cacheKey)
:如果有需要的话进行包装protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);//获取当前bean的通知方法和增强器
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}getAdvicesAndAdvisorsForBean()
- 获取当前bean的所有增强器(通知方法)
- 找到能在当前bean使用的增强器(找哪些通知方法是需要切入当前bean的方法),就是根据我们在切面类上标注的注解来解析是否匹配。
- 给增强器排序,因为增强器是有先后顺序的
通过上述方法获取到了bean能用的增强器封装成
Object[] specificInterceptors
,保存当前bean到advisedBeans
表示被增强处理了如果当前bean需要增强,创建当前bean的代理对象
createProxy()
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();//创建一个代理工厂
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);//拿到所有当前bean能用的增强器
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}- 创建一个代理工厂
- 获取当前bean能用的所有增强器,并加入到代理工厂中
proxyFactory.getProxy(getProxyClassLoader())
用代理工厂创建对象
我们看看spring是怎么帮我们创建代理的
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}- 有两种创建代理对象的方法,一种是
JdkDynamicAopProxy
JDK代理,一种是ObjenesisCglibAopProxy
Cglib代理 - 这两种代理方式可以参考我写的[java代理模式]、[Cglib使用教程]结合源码看一下。
- 有两种创建代理对象的方法,一种是
到此为止我们就得到了一个被增强(代理)的类,以后从容器中获取的类都是代理类,不再是原来new出来的类了,这样我们调用方法就可以调用切面了。
AOP执行流程
代理对象的创建流程上文已经分析过了,那么创建好以后它是如何执行的呢?
|
首先我们来看一下这个测试方法,这个测试方法的mathCalculator
类是从容器中拿的,从容器中拿出来以后就是已经被代理过的对象了,这个对象中保存了很多的详细信息(比如增强器、目标对象等等)
当运行div方法的时候,代理类就会将这个方法代理到CglibAopProxy
类中的静态内部类DynamicAdvisedInterceptor
的intercept()
方法中,因为DynamicAdvisedInterceptor
实现了MethodInterceptor
,参考Cglib动态代理,所有的方法都会走这个intercept()
进行拦截,在这里面我们可以做很多事情对原本的div方法做增强,也就是所说的切面。
|
1、根据ProxyFactory对象获取目标方法的拦截器链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
- 如果获取的拦截器链是空的,那么就执行
methodProxy.invoke(target, argsToUse)
,直接运行目标方法, - 如果有拦截器链,把要执行的目标对象,目标方法,拦截器链等信息传入创建一个
CglibMethodInvocation
对象,然后调用proceed()
方法,
2、从上面可以看出,执行方法的时候主要有两步,获取拦截器链,包装CglibMethodInvocation
对象,下面来一个一个的看
我们来探究一下
getInterceptorsAndDynamicInterceptionAdvice
方法是做了什么public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}最主要的方法就是
this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice()
这里才是获取拦截器链的方法,其余的都是加入到缓存中。获取拦截器链的步骤
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}1)
List<Object> interceptorList
首先创建一个list用来装拦截器链,长度为我们设置的拦截器方法和一个默认的方法;
2)遍历所有的增强器,将所有的增强器包装为Interceptor
:registry.getInterceptors(advisor)
3) 如果我们的增强器是一个PointcutAdvisor
,那么就将增强器转成MethodInterceptor
,如果是MethodIntercepter
直接加入集合中,如果不是,使用AdvisorAdapter
将增强器转换成MethodInterceptor
转换完后加入到MethodInterceptor数组中
4)最终返回一个interceptorList,这就是一个拦截器链。
5)将拦截器链包装成一个CglibMethodInvocation
对象,然后调用proceed()
,执行拦截器链
6) 拦截器链:每一个通知方法又被包装为方法拦截器,利用MethodIntercepter
机制封装成一个list,作为一条链去执行。拦截器链执行(
proceed()
执行过程)
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}我们来一点一点得分析,这是如何执行得
this.currentInterceptorIndex
是-1,this.interceptorsAndDynamicMethodMatchers
存的是拦截器链中增强器的个数,因为这个方法是一个递归,所以当增强器全部都已经完成就返回invokeJoinpoint()
,invokeJoinpoint()
是用来执行目标函数的目标方法的。- 链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再执行。
- 拦截器链的机制能保证通知方法与目标方法的执行顺序。
总结
@EnableAspectJAutoProxy
会开启AOP功能,给容器中注册一个组件AnnotationAwareAspectJAutoProxyCreator
,AnnotationAwareAspectJAutoProxyCreator
是一个后置处理器,会在bean创建初始化完成以后,将bean包装一个代理注册到容器中。- 容器的创建流程
- registerBeanPostProcessors(beanFactory);注册后置处理器
- finishBeanFactoryInitialization(beanFactory);常见剩余的单实例bean
- 创建业务逻辑组件和切面组件
AnnotationAwareAspectJAutoProxyCreator
拦截组件创建过程- 组件创建完成以后,判断组件是否需要增强,如果要增强就把切面得通知方法包装成增强器(Advisor),给业务逻辑组件创建一个代理对象(Cglib)
- 执行目标方法
- 代理对象执行目标方法
- CglibAopProxy.intercept()拦截
- 得到目标方法得拦截器链(增强器包装成拦截器)
- 利用拦截器得链式机制,一此进入每一个拦截器进行执行
- 效果:正常执行->前置通知-》目标方法-》后置通知-》返回通知;
出现异常->前置通知-》目标方法-》后置通知-》异常通知;