[Spring3.x源码]AOP(二)组装配置信息

来源:互联网 发布:淘宝买家电话采集 编辑:程序博客网 时间:2024/04/28 20:09

AbstractApplicationContext context = new FileSystemXmlApplicationContext("beans.xml");这个过程不仅会解析普通的<bean>标签,<aop>标签也会被解析。

1.IoC在解析XML的时候,DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)中解析根节点的子节点。

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 {delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);}}

isDefaultNamespace()判断标签的命名空间是不是http://www.springframework.org/schema/beans,不是的话表示该标签为自定义标签,调用parseCustomElement解析节点。<aop>竟然也算是自定义标签。

delegate在DefaultBeanDefinitionDocumentReader.createHelper方法创建的。

BeanDefinitionParserDelegate.parseCustomElement(Element ele):

public BeanDefinition parseCustomElement(Element ele) {return parseCustomElement(ele, null);}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));}

readerContext是XmlReaderContext类的对象,是在DefaultBeanDefinitionDocumentReader中创建BeanDefinitionParserDelegate时,当构造函数的参数传入的。

this.delegate = createHelper(readerContext, root, parent);protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, environment);delegate.initDefaults(root, parentDelegate);return delegate;}
而DefaultBeanDefinitionDocumentReader的readerContext是在XmlBeanDefinitionReader.registerBeanDefinitions中创建DefaultBeanDefinitionDocumentReader的时候通过赋值的:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {//返回DefaultBeanDefinitionDocumentReaderBeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();documentReader.setEnvironment(this.getEnvironment());int countBefore = getRegistry().getBeanDefinitionCount();//createReaderContext(resource)就是readerContext的来源,返回XmlReaderContext对象documentReader.registerBeanDefinitions(doc, createReaderContext(resource));return getRegistry().getBeanDefinitionCount() - countBefore;}protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));}private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
XmlBeanDefinitionReader.createReaderContext(resource)是readerContext的来源
protected XmlReaderContext createReaderContext(Resource resource) {if (this.namespaceHandlerResolver == null) {this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();}return new XmlReaderContext(resource, this.problemReporter, this.eventListener,this.sourceExtractor, this, this.namespaceHandlerResolver);}
而这个this.namespaceHandlerResolver就是BeanDefinitionParserDelegate.parseCustomElement方法中this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);要调用的。
如果此对象为空,就创建一个createDefaultNamespaceHandlerResolver():

protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());}

2.回到BeanDefinitionParserDelegate.parseCustomElement中,DefaultNamespaceHandlerResolver.resolve(String namespaceUri),根据标签<aop:config>去取相关的命名空间,在根据虚拟的命名空间去取对应的解析类。

public NamespaceHandler resolve(String namespaceUri) {Map<String, Object> 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;}catch (ClassNotFoundException ex) {throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +namespaceUri + "] not found", ex);}catch (LinkageError err) {throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +namespaceUri + "]: problem with handler class file or dependent class", err);}}}

getHandlerMappings():

private Map<String, Object> getHandlerMappings() {if (this.handlerMappings == null) {synchronized (this) {if (this.handlerMappings == null) {try {Properties mappings =PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);if (logger.isDebugEnabled()) {logger.debug("Loaded NamespaceHandler mappings: " + mappings);}Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>();CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);this.handlerMappings = handlerMappings;}catch (IOException ex) {throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);}}}}return this.handlerMappings;}

PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);载入配置文件的信息,配置文件地址变量this.handlerMappingsLocation的来源:

public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";private final String handlerMappingsLocation;public DefaultNamespaceHandlerResolver() {this(null, DEFAULT_HANDLER_MAPPINGS_LOCATION);}public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);}public DefaultNamespaceHandlerResolver(ClassLoader classLoader, String handlerMappingsLocation) {Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());this.handlerMappingsLocation = handlerMappingsLocation;}

将所有包/META-INF/spring.handlers文件内容保存到Map类型的handlerMappings属性中。

AOP的标签<aop>对应的命名空间是http://www.springframework.org/schema/aop,在/spring-aop/src/main/resources/META-INF/spring.handlers这个文件中看看spring.handlers的内容:http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

这里将配置文件开头的命名空间虚拟路径和真实的类关联起来。

暂时回到DefaultNamespaceHandlerResolver.resolve(String namespaceUri)中,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.1registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());}

3.将由这个AopNamespaceHandler类将<aop:config>的配置信息转为BeanDefinition

AopNamespaceHandler继承NamespaceHandlerSupport,

public BeanDefinition parse(Element element, ParserContext parserContext) {return findParserForElement(element, parserContext).parse(element, parserContext);}private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {String localName = parserContext.getDelegate().getLocalName(element);BeanDefinitionParser parser = this.parsers.get(localName);if (parser == null) {parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);}return parser;}

返回<aop:config>标签对应的解析类,AopNamespaceHandler.init()方法中已经配置了——ConfigBeanDefinitionParser。

4.到了这里,spring才有解析<aop:config>的意思,ConfigBeanDefinitionParser.parse(Element element, ParseContext parserContext):

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);if (POINTCUT.equals(localName)) {parsePointcut(elt, parserContext);}else if (ADVISOR.equals(localName)) {parseAdvisor(elt, parserContext);}else if (ASPECT.equals(localName)) {parseAspect(elt, parserContext);}}parserContext.popAndRegisterContainingComponent();return null;}
configureAutoProxyCreator(parserContext, element);创建AspectJAwareAdvisorAutoProxyCreator实例,备用。

/** * Configures the auto proxy creator needed to support the {@link BeanDefinition BeanDefinitions} * created by the '<code><aop:config/></code>' tag. Will force class proxying if the * '<code>proxy-target-class</code>' attribute is set to '<code>true</code>'. * @see AopNamespaceUtils */private void configureAutoProxyCreator(ParserContext parserContext, Element element) {AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);}
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary()

public static void registerAspectJAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);registerComponentIfNecessary(beanDefinition, parserContext);}
AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);}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;}
registry是DefaultListableBeanFactory的实例,registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);将BeanDefinition保存到其beanDefinitionMap属性中。

在AbstractApplicationContext.refresh()中会调用registerBeanPostProcessors()方法将此bean实例化,并调用beanFactory.addBeanPostProcessor()将其保存到AbstractBeanFactory的属性beanPostProcessors中。(AspectJAwareAdvisorAutoProxyCreator通过复杂继承关系算是实现了BeanPostProcessor接口)

5.开始解析<aop:aspect>标签ConfigBeanDefinitionParser.parseAspect():
private void parseAspect(Element aspectElement, ParserContext parserContext) {String aspectId = aspectElement.getAttribute(ID);String aspectName = aspectElement.getAttribute(REF);try {this.parseState.push(new AspectEntry(aspectId, aspectName));List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();List<BeanReference> beanReferences = new ArrayList<BeanReference>();List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);for (int i = METHOD_INDEX; i < declareParents.size(); i++) {Element declareParentsElement = declareParents.get(i);beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));}// We have to parse "advice" and all the advice kinds in one loop, to get the// ordering semantics right.NodeList nodeList = aspectElement.getChildNodes();boolean adviceFoundAlready = false;for (int i = 0; i < nodeList.getLength(); i++) {Node node = nodeList.item(i);if (isAdviceNode(node, parserContext)) {if (!adviceFoundAlready) {adviceFoundAlready = true;if (!StringUtils.hasText(aspectName)) {parserContext.getReaderContext().error("<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",aspectElement, this.parseState.snapshot());return;}beanReferences.add(new RuntimeBeanReference(aspectName));}AbstractBeanDefinition advisorDefinition = parseAdvice(aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);beanDefinitions.add(advisorDefinition);}}AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);parserContext.pushContainingComponent(aspectComponentDefinition);List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);for (Element pointcutElement : pointcuts) {parsePointcut(pointcutElement, parserContext);}parserContext.popAndRegisterContainingComponent();}finally {this.parseState.pop();}}
for循环中的isAdviceNode(node, parserContext)做为过滤条件将只解析before、after、after-returning、after-throwing、around这样的子标签
/** * Return <code>true</code> if the supplied node describes an advice type. May be one of: * '<code>before</code>', '<code>after</code>', '<code>after-returning</code>', * '<code>after-throwing</code>' or '<code>around</code>'. */private boolean isAdviceNode(Node aNode, ParserContext parserContext) {if (!(aNode instanceof Element)) {return false;}else {String name = parserContext.getDelegate().getLocalName(aNode);return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));}}
将aspectName=log,aspectElement=<aop:aspect>,adviceElement=<aop:after>...当参数传入parseAdvice,解析切面类。

/** * Parses one of '<code>before</code>', '<code>after</code>', '<code>after-returning</code>', * '<code>after-throwing</code>' or '<code>around</code>' and registers the resulting * BeanDefinition with the supplied BeanDefinitionRegistry. * @return the generated advice RootBeanDefinition */private AbstractBeanDefinition parseAdvice(String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {try {this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));// create the method factory beanRootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);methodDefinition.getPropertyValues().add("targetBeanName", aspectName);methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));methodDefinition.setSynthetic(true);// create instance factory definitionRootBeanDefinition aspectFactoryDef =new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);aspectFactoryDef.setSynthetic(true);// register the pointcutAbstractBeanDefinition adviceDef = createAdviceDefinition(adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,beanDefinitions, beanReferences);// configure the advisorRootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);advisorDefinition.setSource(parserContext.extractSource(adviceElement));advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);if (aspectElement.hasAttribute(ORDER_PROPERTY)) {advisorDefinition.getPropertyValues().add(ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));}// register the final advisorparserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);return advisorDefinition;}finally {this.parseState.pop();}}
methodDefinition切面信息,包含切面类、方法
createAdviceDefinition()方法将切面信息、切入点信息的整合关联。advisor=advice+pointCut

/** * Creates the RootBeanDefinition for a POJO advice bean. Also causes pointcut * parsing to occur so that the pointcut may be associate with the advice bean. * This same pointcut is also configured as the pointcut for the enclosing * Advisor definition using the supplied MutablePropertyValues. */private AbstractBeanDefinition createAdviceDefinition(Element adviceElement, ParserContext parserContext, String aspectName, int order,RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));adviceDefinition.setSource(parserContext.extractSource(adviceElement));adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);if (adviceElement.hasAttribute(RETURNING)) {adviceDefinition.getPropertyValues().add(RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));}if (adviceElement.hasAttribute(THROWING)) {adviceDefinition.getPropertyValues().add(THROWING_PROPERTY, adviceElement.getAttribute(THROWING));}if (adviceElement.hasAttribute(ARG_NAMES)) {adviceDefinition.getPropertyValues().add(ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));}ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);Object pointcut = parsePointcutProperty(adviceElement, parserContext);if (pointcut instanceof BeanDefinition) {cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);beanDefinitions.add((BeanDefinition) pointcut);}else if (pointcut instanceof String) {RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);beanReferences.add(pointcutRef);}cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);return adviceDefinition;}

RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));根据切面的类型(如before、after等)调取相应的类,创建切面类信息。

private Class getAdviceClass(Element adviceElement, ParserContext parserContext) {String elementName = parserContext.getDelegate().getLocalName(adviceElement);if (BEFORE.equals(elementName)) {return AspectJMethodBeforeAdvice.class;}else if (AFTER.equals(elementName)) {return AspectJAfterAdvice.class;}else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {return AspectJAfterReturningAdvice.class;}else if (AFTER_THROWING_ELEMENT.equals(elementName)) {return AspectJAfterThrowingAdvice.class;}else if (AROUND.equals(elementName)) {return AspectJAroundAdvice.class;}else {throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");}}
Object pointcut = parsePointcutProperty(adviceElement, parserContext);返回切入点信息(例子中,配置文件beans.xml中的servicesPointcut)。

/** * Parses the <code>pointcut</code> or <code>pointcut-ref</code> attributes of the supplied * {@link Element} and add a <code>pointcut</code> property as appropriate. Generates a * {@link org.springframework.beans.factory.config.BeanDefinition} for the pointcut if  necessary * and returns its bean name, otherwise returns the bean name of the referred pointcut. */private Object parsePointcutProperty(Element element, ParserContext parserContext) {if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {parserContext.getReaderContext().error("Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",element, this.parseState.snapshot());return null;}else if (element.hasAttribute(POINTCUT)) {// Create a pointcut for the anonymous pc and register it.String expression = element.getAttribute(POINTCUT);AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);pointcutDefinition.setSource(parserContext.extractSource(element));return pointcutDefinition;}else if (element.hasAttribute(POINTCUT_REF)) {String pointcutRef = element.getAttribute(POINTCUT_REF);if (!StringUtils.hasText(pointcutRef)) {parserContext.getReaderContext().error("'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());return null;}return pointcutRef;}else {parserContext.getReaderContext().error("Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",element, this.parseState.snapshot());return null;}}

advisor封装advice的信息(1:1),advice含有pointCut的信息(1:1)。

每个<aop:before>这种标签包含了类-方法信息,配置成一个advice。advisor是advice它的封装。

原创粉丝点击