您的位置:首页 > 编程语言 > Java开发

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

2015-07-13 21:28 656 查看
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编制在代理对象里面。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: