spring源码分析之——spring aop原理

aop是spring中非常有趣的一个功能。如果应用得当会大有用处。现在从源码角度分析一下

 Spring aop的实现原理。

 

还是从上篇中提到的

<aop:config>

<aop:advisor>….</aop:advisor>

….

</aop:config>

这些配置信息的解析入手。spring中aop namespace的handler是AopNamespaceHandler。

其初始化代码如下(init方法调用的时机在上一篇分析事务时已经分析过了):

public void init() {

// In 2.0 XSD as well as in 2.1 XSD.

registerBeanDefinitionParser(“config”, new ConfigBeanDefinitionParser());

registerBeanDefinitionParser(“aspectj-autoproxy”, new AspectJAutoProxyBeanDefinitionParser());

registerBeanDefinitionDecorator(“scoped-proxy”, new ScopedProxyBeanDefinitionDecorator());

// Only in 2.0 XSD: moved to context namespace as of 2.1

registerBeanDefinitionParser(“spring-configured”, new SpringConfiguredBeanDefinitionParser());

}

可以看到,aop:config标签的解析类是:ConfigBeanDefinitionParser(解析类的调用时机在上一篇分析事务时也介绍过),其parse方法如下:

public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);

configureAutoProxyCreator(parserContext, element);

NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
String localName = parserContext.getDelegate().getLocalName(node);
if (POINTCUT.equals(localName)) {
parsePointcut((Element) node, parserContext);
}
else if (ADVISOR.equals(localName)) {
parseAdvisor((Element) node, parserContext);
}
else if (ASPECT.equals(localName)) {
parseAspect((Element) node, parserContext);
}
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}

它的功能大致有两块:1 . 注册一个AspectJAwareAdvisorAutoProxyCreator类型的bean。 2. 解析主标签下面的

   advisor标签,并且注册advisor.

   下面逐一分析一下这两个方面。

  1. AspectJAwareAdvisorAutoProxyCreator 类型bean 的注册。

       稍微从

configureAutoProxyCreator(parserContext, element);

这一句跟踪一下很容易就发现最后到了AopConfigUtils的如下方法:

private static BeanDefinition registerOrEscalateApcAsRequired(Class cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, “BeanDefinitionRegistry must not be null”);
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add(“order”, Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}

 注意参数里面的cls是AspectJAwareAdvisorAutoProxyCreator.class,这个是在前面把调用委托过来的时候直接写死的。这段代码注册了一个名为AUTO_PROXY_CREATOR_BEAN_NAME(org.springframework.aop.config.internalAutoProxyCreator)的bean。bean的类型是AspectJAwareAdvisorAutoProxyCreator。

     AspectJAwareAdvisorAutoProxyCreator到底有什么玄机呢?看了一下继承关系,赫然发现实现了InstantiationAwareBeanPostProcessor接口!这个接口是BeanPostProcessor的一个子类,在bean初始化的时候

调用。此接口的实现在AbstractAutoProxyCreator中(其他与本次分析无关的方法的实现在此没有列出):

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {

Object cacheKey = getCacheKey(beanClass, beanName);

if (!this.targetSourcedBeans.contains(cacheKey)) {

if (this.advisedBeans.contains(cacheKey) || this.nonAdvisedBeans.contains(cacheKey)) {

return null;

}

if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {

this.nonAdvisedBeans.add(cacheKey);

return null;

}

}

// Create proxy here if we have a custom TargetSource.

// Suppresses unnecessary default instantiation of the target bean:

// The TargetSource will handle target instances in a custom fashion.

TargetSource targetSource = getCustomTargetSource(beanClass, beanName);

if (targetSource != null) {

this.targetSourcedBeans.add(beanName);

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);

Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);

this.proxyTypes.put(cacheKey, proxy.getClass());

return proxy;

}

return null;

}


这段代码的作用就是每当bean初始化前,检查是否需要生成代理对象。如果需要,就生成代理。

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);

上面这段代码负责找到与当前bean相关联的Advisor(s).感兴趣的朋友可以继续追踪一下代码了解细节。大致思路就是

先找到所有实现了Advisor接口的bean,然后根据配置文件中的advisor配置从中挑出能cut到当前bean的advisor.

 

    接下来就是生成proxy了。代码如下:

protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

ProxyFactory proxyFactory = new ProxyFactory();
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
proxyFactory.copyFrom(this);

if (!shouldProxyTargetClass(beanClass, beanName)) {
// Must allow for introductions; can’t just set interfaces to
// the target’s interfaces only.
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
for (Class<?> targetInterface : targetInterfaces) {
proxyFactory.addInterface(targetInterface);
}
}

Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}

proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);

proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}

return proxyFactory.getProxy(this.proxyClassLoader);
}

通过读这段代码,也就明白了当在配置bean的时候proxyTargetClass属性时如果需要生成代理使用cglib的原因了。

    因为如果配置了这个属性,那么生成代理的时候会掠过对bean接口的解析,从而只能使用cglib代理。

 

     OK.第一个方面分析基本完成了。

    下面分析一下文章开头提到的第二个方面:

    aop:advisor的解析。

    这个解析是在ConfigBeanDefinitionParse里面完成的:

private void parseAdvisor(Element advisorElement, ParserContext parserContext) {

AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);

String id = advisorElement.getAttribute(ID);

try {

this.parseState.push(new AdvisorEntry(id));

String advisorBeanName = id;

if (StringUtils.hasText(advisorBeanName)) {

parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);

}

else {

advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);

}

Object pointcut = parsePointcutProperty(advisorElement, parserContext);

if (pointcut instanceof BeanDefinition) {

advisorDef.getPropertyValues().add(POINTCUT, pointcut);

parserContext.registerComponent(

new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));

}

else if (pointcut instanceof String) {

advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));

parserContext.registerComponent(

new AdvisorComponentDefinition(advisorBeanName, advisorDef));

}

}

finally {

this.parseState.pop();

}

}

这段代码实际上就是生成了一个beanclass 为DefaultBeanFactoryPointcutAdvisor的advisor.

    我们在分析第一个方面的时候,曾经提到过bean初始化前会调用

    postProcessBeforeInstantiation

而这个方法会找到所有跟需要实例化的bean关联的advisor,然后产生proxy.

    OK.终于明白了Advisor是如何产生作用的了!

 

   Spring AOP的原理大致如下: 

   配置一个实现了InstantiationAwareBeanPostProcessor接口的bean。在每次bean初始化的时候找到所有advisor,根据pointcut 判断是不是需要为将实例化的bean生成代理,如果需要,就把advice编制在代理对象里面。

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/questiontoomuch/article/details/46867961
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞