spring源码学习之aop事物标签解析

在使用spring事物对数据操作的时候,经常使用到aop、tx等标签,spring使用aop面向切面编程,来实现对事物的控制,那么srping是怎么解析这些标签的呢?解析的入口在哪里呢?

spring版本:4.2.0.RELEASE

简单实例

一个简单的例子开始,对数据库进行事物操作,bean.xml的配置如下:




	

	

	
		
		
		
		
	

	
	
		
		
		
	

	
		
		
		
	

	
	
		
	

	
	
		
			
			
			
			
			
			
		
	

	
	
		
		
	

编写一段测试代码

public class Test {
    private static Logger logger = Logger.getLogger(Test.class);

    public static void main(String[] args){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
        IAuthUserService authUserServiceImpl = ctx.getBean(AuthUserServiceImpl.class);
        Map params = new HashMap<>();
        params.put("userAccount","user002");
        int ret = authUserServiceImpl.delete("user002");
        //logger.info("查询结果:"+ JSON.toJSONString(authUsers));
    }
}

aop标签的解析

在执行new ClassPathXmlApplicationContext("bean.xml");这段代码的时候,看看spring都做过哪些事情。spring在使用事物的过程中有几个关键的类AnnotationAwareAspectJAutoProxyCreator、AspectJAwareAdvisorAutoProxyCreator、AspectJExpressionPointcut、DefaultBeanFactoryPointcutAdvisor等是怎么创建的。

下面看看标签,在spring启动的过程中,标签是怎么被解析和注册的,

spring源码学习之aop事物标签解析_第1张图片

ClassPathXmlApplicationContext在解析bean.xml文件的时候创建了一个xml阅读器XmlBeanDefinitionReader,

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        this.initBeanDefinitionReader(beanDefinitionReader);
        this.loadBeanDefinitions(beanDefinitionReader);
    }

这个reader负责加载bean.xml配置文件,并且使用xml文件创建一个Document 文档对象,resource对象就代表了bean.xml资源文件。

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			Document doc = doLoadDocument(inputSource, resource);
			return registerBeanDefinitions(doc, resource);
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		//......
	}

从这个doc对象中就可以获取到beans 这个root根元素,

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
		Element root = doc.getDocumentElement();//获取到beans这个root根据元素
		doRegisterBeanDefinitions(root);
	}
//在DefaultBeanDefinitionDocumentReader类中对所有的标签进行遍历
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
            //遍历根beans元素下的所有子节点
			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 {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

遍历到[aop:aspectj-autoproxy:]元素的时候,交给delegate去解析,

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));
	}

这个Element ele目前代表的元素就是aop:aspectj-autoproxy标签,getNamespaceURI(ele)就是解析这个标签的命名空间,namespaceUri的值就是我们在bean.xml文档开头所声明的命名空间xmlns:aop="http://www.springframework.org/schema/aop"的值http://www.springframework.org/schema/aop,这个地方就可以看到通过aop标签,就可以找到命名空间,那么通过这个命名空间是怎么解析出来的NamespaceHandler的呢,看看方法resolve(namespaceUri)做了什么。

public NamespaceHandler resolve(String namespaceUri) {
		Map handlerMappings = getHandlerMappings();
		Object handlerOrClassName = handlerMappings.get(namespaceUri);
		if (handlerOrClassName == null) {
			return null;
		}
		else if (handlerOrClassName instanceof NamespaceHandler) {
			return (NamespaceHandler) handlerOrClassName;
		}
		else {
			String className = (String) handlerOrClassName;
			try {
				Class handlerClass = ClassUtils.forName(className, this.classLoader);
				if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
					throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
							"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
				}
				NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
				namespaceHandler.init();
				handlerMappings.put(namespaceUri, namespaceHandler);
				return namespaceHandler;
			}
//....
		}
	}

这个getHandlerMappings方法解析出了所有命名空间和handler的映射,这样我们就可以拿到这个aop标签对应的handler处理器,并且调用处理器的init()方法完成处理器的初始化工作。那这个getHandlerMappings方法是怎么解析的呢。

private Map getHandlerMappings() {
		if (this.handlerMappings == null) {
			synchronized (this) {
				if (this.handlerMappings == null) {
					try {
//这个this.handlerMappingsLocation的值就是META-INF/spring.handlers
						Properties mappings =
								PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
						Map handlerMappings = new ConcurrentHashMap(mappings.size());
						CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
						this.handlerMappings = handlerMappings;
					}//....
				}
			}
		}
		return this.handlerMappings;
	}

从上面getHandlerMappings方法的源码中可以看得出来,映射关系是从Properties对象中取出来的,把这个Properties转换成了map对象,那这个Properties对象怎么加载的,还需要看看loadAllProperties方法。

public static Properties loadAllProperties(String resourceName, ClassLoader classLoader) throws IOException {
        Assert.notNull(resourceName, "Resource name must not be null");
        ClassLoader classLoaderToUse = classLoader;
        if(classLoader == null) {
            classLoaderToUse = ClassUtils.getDefaultClassLoader();
        }

        Enumeration urls = classLoaderToUse != null?classLoaderToUse.getResources(resourceName):ClassLoader.getSystemResources(resourceName);
        Properties props = new Properties();

        while(urls.hasMoreElements()) {
            URL url = (URL)urls.nextElement();
            URLConnection con = url.openConnection();
            ResourceUtils.useCachesIfNecessary(con);
            InputStream is = con.getInputStream();

            try {
                if(resourceName != null && resourceName.endsWith(".xml")) {
                    props.loadFromXML(is);
                } else {
                    props.load(is);
                }
            } finally {
                is.close();
            }
        }

        return props;
    }

loadAllProperties方法参数resourceName的值就是META-INF/spring.handlers,这是一个相对路径,根据这个路径中去加载文件中的内容,这个文件的位置就在spring-aop的jar包下面。

spring源码学习之aop事物标签解析_第2张图片

文件的内容就是一行key value键值对,这就可以清晰看到aop标签所对应的handler处理器是怎么解析出来的。

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

在回到上面resolve()方法handler被初始化的地方,handler类的全路径被解析出来,就可以被实例化出对象,在调用

namespaceHandler.init(),在AopNamespaceHandler处理器中看看init方法做了什么事情。

public void init() {
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}

初始化方法就完成了aop标签对应的这些元素的注册功能。每一个元素还有一个对应的解析器,

protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
		this.parsers.put(elementName, parser);
	}

注册的结果就是将元素和解析器放在一个map变量里,Map parsers = new HashMap();所有的解析器都是BeanDefinitionParser接口的子类。

aop元素解析

回到上面解析handler的地方

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));
	}

解析handler的过程完成了两件事情,一件是解析出handler,一件就是调用hanlder的init方法,完成初始化。初始化完成之后,就会调用handler的parse方法,进行aop元素的解析。

spring首先解析到的元素是aspectj-autoproxy,从handler的init方法可以知道,registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

这个元素对应的解析器就是AspectJAutoProxyBeanDefinitionParser,下面就看看这个解析器干了什么事情。

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}
private static BeanDefinition registerOrEscalateApcAsRequired(Class cls, BeanDefinitionRegistry registry, Object source) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be 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;
	}

这个解析器做主要的事情就是干了3件事情,
第一使用AnnotationAwareAspectJAutoProxyCreator类作为beanclass创建RootBeanDefinition,
第二将这个RootBeanDefinition注册到BeanFactory,这个registry的引用的对象就是DefaultListableBeanFactory工厂类的实例,以org.springframework.aop.config.internalAutoProxyCreator作为key,将RootBeanDefinition存储在BeanFactory的私有变量Map beanDefinitionMap中。

spring源码学习之aop事物标签解析_第3张图片
第三将标签中参数proxy-target-class封装在RootBeanDefinition中,这个参数会影响到spring在创建代理类的时候,是使用cglib还是jdk的动态代理。

这样就完成了标签的解析,此处以标签为例进行分析,其他的标签解析大致相似。

通过以上的解析过程,完成这几个标签的解析,这几个标签都和数据库事物相关。每一个标签都会一个RootBeanDefinition beanDefinition对象与之对应,并完成beanDefinition在BeanFactory类的注册。而每一个RootBeanDefinition又对应有一个classbean对象。

标签对应的classbean对象是AnnotationAwareAspectJAutoProxyCreator,

标签对应的classbean对象是AspectJAwareAdvisorAutoProxyCreator,

标签对应的classbean对象是AspectJExpressionPointcut,

标签对应的classbean对象是DefaultBeanFactoryPointcutAdvisor,

标签对应的classbean对象是NameMatchTransactionAttributeSource,

标签对应的classbean对象是TransactionInterceptor,

标签的属性被封装到了RuleBasedTransactionAttribute对象中,存储在标签对应的RootBeanDefinition属性集合中。

private RootBeanDefinition parseAttributeSource(Element attrEle, ParserContext parserContext) {
        List methods = DomUtils.getChildElementsByTagName(attrEle, "method");
        ManagedMap transactionAttributeMap = new ManagedMap(methods.size());
        transactionAttributeMap.setSource(parserContext.extractSource(attrEle));
        Iterator var5 = methods.iterator();

        while(var5.hasNext()) {
            Element methodEle = (Element)var5.next();
            String name = methodEle.getAttribute("name");
            TypedStringValue nameHolder = new TypedStringValue(name);
            nameHolder.setSource(parserContext.extractSource(methodEle));
            RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute();
            String propagation = methodEle.getAttribute("propagation");
            String isolation = methodEle.getAttribute("isolation");
            String timeout = methodEle.getAttribute("timeout");
            String readOnly = methodEle.getAttribute("read-only");
            if(StringUtils.hasText(propagation)) {
                attribute.setPropagationBehaviorName("PROPAGATION_" + propagation);
            }
            if(StringUtils.hasText(isolation)) {
                attribute.setIsolationLevelName("ISOLATION_" + isolation);
            }
            if(StringUtils.hasText(timeout)) {
                attribute.setTimeout(Integer.parseInt(timeout));
            }
            if(StringUtils.hasText(readOnly)) {
                attribute.setReadOnly(Boolean.valueOf(methodEle.getAttribute("read-only")).booleanValue());
            }
//......
            attribute.setRollbackRules(rollbackRules);
            transactionAttributeMap.put(nameHolder, attribute);
        }
        RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchTransactionAttributeSource.class);
        attributeSourceDefinition.setSource(parserContext.extractSource(attrEle));
        attributeSourceDefinition.getPropertyValues().add("nameMap", transactionAttributeMap);
        return attributeSourceDefinition;
    }

这些标签对应的classbean和属性集合将会在后面的章节中分析。

你可能感兴趣的:(spring)