《Spring源码深度解析》七(1)
第七章:AOP
7.1:切入点:
7.1.1:初始化:AopNamespaceHandler#init
注:如果声明了自定义的注解,那么就一定会在程序中的某个地方注册了对应的解析器,统一接口为BeanDefinitionParser,入口为parse函数
AopNamespaceHandler#init
public void init() {
...
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
...
}
7.1.2 解析:AspectJAutoProxyBeanDefinitionParser
parse:
public BeanDefinition parse(Element element, ParserContext parserContext) {
//注册AnnotationAspectJAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
//对于注解中子类处理
extendBeanDefinition(element, parserContext);
return null;
}
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
//7.1.3
//注册或升级AutoProxyCreator定义beanName为org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition
//对于AOP的实现,基本上都是靠AnnotationAwareAspectJAutoProxyCreator去完成,它可以根据
//@Point注解定义的切点来自动代理相匹配的bean。但是为了配置简便,Spring使用了自定义配置来帮助我们自动注册AnnotationAwareAspectJAutoProxyCreator ,其注册过程就是在这里实现的。
//这里涉及优先级的问题,即选择使用哪个自动代理创建器
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
//对proxy-target-class以及expose-proxy属性的处理
//若目标对象实现了至少一个接口,则会使用JDK动态代理,否则为cglib
//也可以强制使用cglib(<aop:config>的proxy-target-class属性设为true),但是无法adviseFinal方法,因为final方法不能被覆盖
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
//注册组件并通知,便于监听器做进一步处理
registerComponentIfNecessary(beanDefinition, parserContext);
}
bug:
7.1.3创建AOP代理:AnnotationAspectJAutoProxyCreator
间接实现了BeanPostProcessor接口,所以当Spring加载这个Bean时会在实例化前调用器postProcessAfterInitialization方法,对于AOP的分析也从这里开始:
7.1.3.1:postProcessAfterInitialization
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
//根据据给定的bean的class和name构建出一个key,格式:beanClassName_beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//如果它适合被代理, 则需要封装指定bean
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//如果已经处理过(无须put);或无须增强(无须put);或给定的bean类是否代表一个基础设施类,基础设施类不应代理(put);或配置了指定bean不需要自动代理(put),则返回bean
...
//如果存在增强方法则创建代理
//7.1.3.1.1 获取增强方法或者增强器。
//7.1.3.1.2 根据获取的增强进行代理。
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
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;
}
7.1.3.1.1:获取增强方法或者增强器。
1.获取所有的增强
2.寻找所有增强中适用于bean的增强并应用
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
...
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();//1.
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);//2.
...
}
7.1.3.1.1.1:获取所有的增强
解析流程分为四步,如下:
AnnotationAwareAspectJAutoProxyCreator#
protected List<Advisor> findCandidateAdvisors() {
//当使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持,
//在这里调用父类方法加载配置文件中的AOP声明
List<Advisor> advisors = super.findCandidateAdvisors();
if (this.aspectJAdvisorsBuilder != null) {
//1.获取所有beanName ,这一步骤中所有在beanFacotry中注册的bean都会被提取出来。
//2.遍历所有beanName,并找出声明AspectJ注解的类,进行进一步的处理。
//**3.对标记为AspectJ注解的类进行增强器的提取。所有的增强都由Advisor的实现类InstantiationModelAwarePointcutAdvisorImpl统一封装;不同的注解会生成不同的增强器,增强器会调用增强的方法
//前置增强:大致的结构是在拦截器链中放置MethodBeforeAdviceInterceptor(中间类)。而在MethodBeforeAdviceinterceptor中又放置了AspectJMethodBeforeAdvice,并在调用invoke时首先串联调用(中间类目的:将mi.processd()抽取出来,以便在befor之后调用,解耦)
//后置增强:没有提供中间的类,而是直接在拦截器链中使用了中间的AspectJAfterAdvice,try中调用mi.process(),finally中调用增强方法
//4.将提取结果加入缓存。
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
增强(advisor)使用了工厂模式,即advisorFactory
7.1.3.1.1.2:寻找所有适用于bean的增强并应用,即满足通配符的增强器
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
...
//过滤已经得到的advisors
//寻找适用于当前class的增强器,引介增强和普通增强分开处理
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
...
}
7.1.3.1.2:根据获取的增强进行代理,即创建代理,涉及ProxyFactory
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource){
//流程:
//1.获取当前类中的属性。
proxyFactory.copyFrom(this);
//2.添加代理接口。
evaluateProxyInterfaces(beanClass, proxyFactory)#proxyFactory.addInterface(ifc);
//3.封装Advisor并加入到ProxyFactory中。需要先将拦截器封装为增强器。
//设计:由于Spring涉及过多的拦截器、增强器、增强方法等方式来对逻辑进行增强,所以非常有必要统一封装成Advisor来进行代理的创建
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
//4.设置要代理的类。
proxyFactory.setTargetSource(targetSource);
//5.Spring为子类提供了定制的函数customizeProxyFactory(factory),子类可以在此函数中对ProxyFactory做进一步封装。
customizeProxyFactory(proxyFactory);
//6.进行代理的创建与获取操作。
proxyFactory.getProxy(getProxyClassLoader());
}
第六步中,关于代理的选择:
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))
三个判断解释:
JDK与CGlib选择的总结:
如何强制使用CGlib实现AOP、JDK和CGlib的区别、为什么优先使用JDK(final不可被覆盖):
JDKDynamicAopProxy#getProxy#invoke:
getProxy创建了代理实例;
invoke封装(new ReflectiveMethodlnvocation(…))、执行(retVal=ReflectiveMethodlnvocation.proceed())了一个拦截器链;
而proceed中增强的逻辑委派给了各个增强器来完成(invoke),拦截器全部执行完后,调用原先的方法。优化技巧:
后置可参考7.1.3.1.1.1中后置增强的执行,即直接调用了ReflectiveMethodlnvocation的proceed,用finally来实现后置,这样在所有的return结束后,即调用了原方法后才会调用后置方法
前置也可参考,即直接调用before,再返回proceed
这样就避免了原生的直接在调用原方法的前后增加逻辑,达到解耦的目的
CglibAopProxy#getProxy:
getProxy为创建Enhancer的全过程
getCallbacks(rootClass):设置拦截器链,加入Callback中。拦截器(advised属性)会被封装在DynamicAdvisedInterceptor(实现Methodlnterceptor)中注:CGlib中对于方法的拦截是通过将自定义的拦截器((实现Methodlnterceptor接口)加入Callback中并在调用代理时直接激活拦截器中的intercept 方法来实现的
因此cglib代理的核心逻辑在DynamicAdvisedInterceptor的intercept中
流程与JDK中的invoke类似:都是首先构造链,然后封装此链进行串联调用;
稍有些区别就是在JDK中直接构造ReflectiveMethodlnvocation ,
而在cglib中使用CglibMethodlnvocation 。CglibMethodlnvocation继承自ReflectiveMethodlnvocation , 但是proceed 方法并没有重写,达到职责明确,又能代码复用的目的(技巧)。
原文始发于微信公众号(不止于Java):《Spring源码深度解析》七(1)