spring源码解读 AOP原理

本文主要分析通过这种标签来使用spring AOP的过程。Spring版本是4.1.7。在我看来Spring AOP主要分四个步骤,加载解析AOP标签,生成代理对象,拦截器的调用。下面就是通过这四个方面来分析Spring AOP的原理。

一.容器初始化,解析AOP标签。
1.先看一下我跟源码时关于AOP的配置





2.spring 在容器初始化时会通过一系列的BeanDefinitionParser将我们定义的内容解析成Spring内部的使用的数据结构BeanDefinition。spring 容器初始化的过程,不在多说,主要说明一下AOP标签解析的过程。AOP标签解析的入口
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
//解析除了Bean标签之外的其它标签
//AOP标签解析的入口
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}

在spring中bean标签是default,其它的任何标签都是custom。我们接着跟代码
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error(“Unable to locate Spring NamespaceHandler for XML schema namespace [” + namespaceUri + “]”, ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

获取NamespaceHandler的过程主要就是通过命名空间http://www.springframework.org/schema/aop,找到定义标签的Handler文件,在spring-aop的jar包里META—INF里的spring.handlers,内容如下:
http://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
Spring对不同的命名空间都有相对应的NamespaceHandler。从上面的内容可以看出处理AOP命名空间的是AopNamespaceHandler,我们看一下AopNamespaceHandler里的内容。
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
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());
}

}
从中可以看出NameSpaceHandler主要是来注册用来解析标签的BeanDefitionParser,解析标签的是ConfigBeanDefitionParser,看一下主要的解析过程
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
//解析标签
parserContext.pushContainingComponent(compositeDef);

    configureAutoProxyCreator(parserContext, element);

    List<Element> childElts = DomUtils.getChildElements(element);
    for (Element elt: childElts) {
        String localName = parserContext.getDelegate().getLocalName(elt);
        //解析<aop:pointcut>标签
        if (POINTCUT.equals(localName)) {
            parsePointcut(elt, parserContext);
        }
        //解析<aop:padvisor>标签
        else if (ADVISOR.equals(localName)) {
            parseAdvisor(elt, parserContext);
        //解析<aop:aspect>标签
        else if (ASPECT.equals(localName)) {
            parseAspect(elt, parserContext);
        }
    }

    parserContext.popAndRegisterContainingComponent();
    return null;
}

在解析的子标签时都是生成BeanDefinition,在BeanFactory中有个重要属性beanDefinitionMap,里面保存着解析的结果,大家调试的时候可以看下里面除了你定义的bean之外,还有Aop标签的解析结果。在解析是有个重要的步骤,如下
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}

向BeanFactory中AspectJAwareAdvisorAutoProxyCreator,这个其实就是个BeanPostProcessor,对spring了解的可以知道,这是spring对外暴露的扩展点,里面定义了俩个方法,postProcessBeforeInstantiation在bean初始化之前,postProcessAfterInitialization在Bean初始化之后用。AspectJAwareAdvisorAutoProxyCreator这个东西就是我们要找的东西,因为有了它我们才会生成代理对象。

二.生成代理对象。
1.在通过getBean()触发依赖注入之后,spring先生成对象的实例,然后进行初始化,在完成初始化之后会调用BeanPostProcessor的postProcessAfterInitialization()方法,这里就是生成代理对象的入口。上面我们说了spring在解析Aop标签时会向容器注入AspectJAwareAdvisorAutoProxyCreator,其postProcessAfterInitialization的方法在父类AbstractAutoProxyCreator里,我们看一下其方法的实现:
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

在看一下
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;
}

    //1.判断是否有advisor和当前bean的class匹配
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        //2.来生成代理对象
        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;
}

其中1的主要逻辑在AopUtils中,我们看一下主要的过程
public static List findAdvisorsThatCanApply(List candidateAdvisors, Class

猜你喜欢

转载自blog.csdn.net/sinat_37529004/article/details/81279590