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

来源:互联网 发布:淘宝事件营销的案例 编辑:程序博客网 时间:2024/05/21 23:48

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编制在代理对象里面。




0 0
原创粉丝点击