zoukankan      html  css  js  c++  java
  • spring解析配置文件(三)

    一、从XmlBeanDefinitionReader的registerBeanDefinitions(doc,resource)开始

    1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    2             throws BeanDefinitionStoreException {
    3         try {
    4             Document doc = doLoadDocument(inputSource, resource);
    5             return registerBeanDefinitions(doc, resource);
    6         }

    进入第5行的registerBeanDefinitions方法

    1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    2         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    3         int countBefore = getRegistry().getBeanDefinitionCount();
    4         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    5         return getRegistry().getBeanDefinitionCount() - countBefore;
    6     }

    第二行创建了一个bean定义文档阅读器,创建的代码如下,第三行的getRegistry()方法得到是DefaultListableBeanFactory类的实例,是个bean工厂,这个工厂在准备读取xml时创建xml阅读器的时候就已经设置进去,getBeanDefinitions方法里的代码就这一句this.beanDefinitionMap.size(),获取bean定义容器的大小,很显然对于我这里是没有的,因为还没解析xml。

    1 protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
    2         return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
    3     }

    在看看第4行的documentReader.registerBeanDefinitions这个方法

    1 @Override
    2     public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    3         this.readerContext = readerContext;
    4         logger.debug("Loading bean definitions");
    5         Element root = doc.getDocumentElement();
    6         doRegisterBeanDefinitions(root);
    7     }

    第5行获得了xml的根元素<beans>然后调用

    doRegisterBeanDefinitions方法,并把根元素传入进入

     1 protected void doRegisterBeanDefinitions(Element root) {
     2         // Any nested <beans> elements will cause recursion in this method. In
     3         // order to propagate and preserve <beans> default-* attributes correctly,
     4         // keep track of the current (parent) delegate, which may be null. Create
     5         // the new (child) delegate with a reference to the parent for fallback purposes,
     6         // then ultimately reset this.delegate back to its original (parent) reference.
     7         // this behavior emulates a stack of delegates without actually necessitating one.
     8         BeanDefinitionParserDelegate parent = this.delegate;
     9         this.delegate = createDelegate(getReaderContext(), root, parent);
    10 
    11         if (this.delegate.isDefaultNamespace(root)) {
    12             String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
    13             if (StringUtils.hasText(profileSpec)) {
    14                 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
    15                         profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    16                 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    17                     return;
    18                 }
    19             }
    20         }
    21 
    22         preProcessXml(root);
    23         parseBeanDefinitions(root, this.delegate);
    24         postProcessXml(root);
    25 
    26         this.delegate = parent;
    27     }
    第9行创建了使用createDelegate方法创建了一个BeanDefinitionParserDelegate类的实例,它内部的代码如下
    1 protected BeanDefinitionParserDelegate createDelegate(
    2             XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
    3 
    4         BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
    5         delegate.initDefaults(root, parentDelegate);
    6         return delegate;
    7     }

    第4行的readerContext是一个XMLReaderContext,继续往下调用了initDefaults方法,初始化默认值

    1 public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
    2         populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
    3         this.readerContext.fireDefaultsRegistered(this.defaults);
    4     }

    进入populateDefaults方法

     1 protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
     2         String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
     3         if (DEFAULT_VALUE.equals(lazyInit)) {
     4             // Potentially inherited from outer <beans> sections, otherwise falling back to false.
     5             lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
     6         }
     7         defaults.setLazyInit(lazyInit);
     8 
     9         String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
    10         if (DEFAULT_VALUE.equals(merge)) {
    11             // Potentially inherited from outer <beans> sections, otherwise falling back to false.
    12             merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
    13         }
    14         defaults.setMerge(merge);
    15 
    16         String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
    17         if (DEFAULT_VALUE.equals(autowire)) {
    18             // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'.
    19             autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
    20         }
    21         defaults.setAutowire(autowire);
    22 
    23         // Don't fall back to parentDefaults for dependency-check as it's no longer supported in
    24         // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it.
    25         defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
    26 
    27         if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
    28             defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
    29         }
    30         else if (parentDefaults != null) {
    31             defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
    32         }
    33 
    34         if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
    35             defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
    36         }
    37         else if (parentDefaults != null) {
    38             defaults.setInitMethod(parentDefaults.getInitMethod());
    39         }
    40 
    41         if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
    42             defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
    43         }
    44         else if (parentDefaults != null) {
    45             defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
    46         }
    47 
    48         defaults.setSource(this.readerContext.extractSource(root));
    49     }

    第2行的DEFAULT_LAZY_INIT_ATTRIBUTE的值是default-lazy-init,第7行设置懒加载,还有默认的初始化方法什么的,把这些个属性全都设置到

    DocumentDefaultsDefinition 中。这个方法返回后继续调用了XmlReaderContext的fireDefaultsRegistered方法,不过里面啥都没做。

    接下来有回到了
    doRegisterBeanDefinitions方法
     1 protected void doRegisterBeanDefinitions(Element root) {
     2         // Any nested <beans> elements will cause recursion in this method. In
     3         // order to propagate and preserve <beans> default-* attributes correctly,
     4         // keep track of the current (parent) delegate, which may be null. Create
     5         // the new (child) delegate with a reference to the parent for fallback purposes,
     6         // then ultimately reset this.delegate back to its original (parent) reference.
     7         // this behavior emulates a stack of delegates without actually necessitating one.
     8         BeanDefinitionParserDelegate parent = this.delegate;
     9         this.delegate = createDelegate(getReaderContext(), root, parent);
    10 
    11         if (this.delegate.isDefaultNamespace(root)) {
    12             String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
    13             if (StringUtils.hasText(profileSpec)) {
    14                 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
    15                         profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    16                 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    17                     return;
    18                 }
    19             }
    20         }
    21 
    22         preProcessXml(root);
    23         parseBeanDefinitions(root, this.delegate);
    24         postProcessXml(root);
    25 
    26         this.delegate = parent;
    27     }

    第11行判断当前的根元素是否是默认的命名空间,spring中存在着两种标签,一种是默认的标签,另一种是自定义标签

    第12行获得profile属性,这个属性应用于对个beans标签的情况,从spring3开始的,这样我们可以写多套bean定义,特别是使用到数据源的时候,可以切换不同的数据源,想要使用哪个bean定义就激活谁,想详细了解的,可以去查查资料。

    第22行是个空方法,里面什么也没做,这个地方可以进行扩展,在解析bean定义之前,可以先处理自定义的标签

    第23行方法的代码如下

     1 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
     2         if (delegate.isDefaultNamespace(root)) {
     3             NodeList nl = root.getChildNodes();
     4             for (int i = 0; i < nl.getLength(); i++) {
     5                 Node node = nl.item(i);
     6                 if (node instanceof Element) {
     7                     Element ele = (Element) node;
     8                     if (delegate.isDefaultNamespace(ele)) {
     9                         parseDefaultElement(ele, delegate);
    10                     }
    11                     else {
    12                         delegate.parseCustomElement(ele);
    13                     }
    14                 }
    15             }
    16         }
    17         else {
    18             delegate.parseCustomElement(root);
    19         }
    20     }

    第2行判断root是否是默认的命名空间,第3行获得根元素下的子节点,循环遍历子节点,第8行判断每个子节点是否是默认的命名空间,如果是就执行parseDefaultElement方法,否则

    执行parseCustomElement方法,什么是自定义的标签呢,比如用户自己实现的标签,还有就是spring的aop,tx这类标签都是有自定义的命名空间的标签

    我们进到parseCustomElement方法中看看

    1 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    2         String namespaceUri = getNamespaceURI(ele);
    3         NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    4         if (handler == null) {
    5             error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
    6             return null;
    7         }
    8         return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    9     }

    第2行获取这个元素的命名空间,通过命名空间可以在类路径下的spring.handlers中找到对应的处理器,在spring.schemas中找到对应的xsd文件。进入resolve方法查看一下他的

    代码逻辑

     1 @Override
     2     public NamespaceHandler resolve(String namespaceUri) {
     3         Map<String, Object> handlerMappings = getHandlerMappings();
     4         Object handlerOrClassName = handlerMappings.get(namespaceUri);
     5         if (handlerOrClassName == null) {
     6             return null;
     7         }
     8         else if (handlerOrClassName instanceof NamespaceHandler) {
     9             return (NamespaceHandler) handlerOrClassName;
    10         }
    11         else {
    12             String className = (String) handlerOrClassName;
    13             try {
    14                 Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
    15                 if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
    16                     throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
    17                             "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
    18                 }
    19                 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
    20                 namespaceHandler.init();
    21                 handlerMappings.put(namespaceUri, namespaceHandler);
    22                 return namespaceHandler;
    23             }
    24             catch (ClassNotFoundException ex) {
    25                 throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
    26                         namespaceUri + "] not found", ex);
    27             }
    28             catch (LinkageError err) {
    29                 throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
    30                         namespaceUri + "]: problem with handler class file or dependent class", err);
    31             }
    32         }
    33     }

    第3行代码getHandlerMappings()获得所有的命名空间和处理程序的映射

     1 private Map<String, Object> getHandlerMappings() {
     2         if (this.handlerMappings == null) {
     3             synchronized (this) {
     4                 if (this.handlerMappings == null) {
     5                     try {
     6                         Properties mappings =
     7                                 PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
     8                         if (logger.isDebugEnabled()) {
     9                             logger.debug("Loaded NamespaceHandler mappings: " + mappings);
    10                         }
    11                         Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
    12                         CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
    13                         this.handlerMappings = handlerMappings;
    14                     }
    15                     catch (IOException ex) {
    16                         throw new IllegalStateException(
    17                                 "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
    18                     }
    19                 }
    20             }
    21         }
    22         return this.handlerMappings;
    23     }

    进入第7行看看

     1 public static Properties loadAllProperties(String resourceName, ClassLoader classLoader) throws IOException {
     2         Assert.notNull(resourceName, "Resource name must not be null");
     3         ClassLoader classLoaderToUse = classLoader;
     4         if (classLoaderToUse == null) {
     5             classLoaderToUse = ClassUtils.getDefaultClassLoader();
     6         }
     7         Enumeration<URL> urls = (classLoaderToUse != null ? classLoaderToUse.getResources(resourceName) :
     8                 ClassLoader.getSystemResources(resourceName));
     9         Properties props = new Properties();
    10         while (urls.hasMoreElements()) {
    11             URL url = urls.nextElement();
    12             URLConnection con = url.openConnection();
    13             ResourceUtils.useCachesIfNecessary(con);
    14             InputStream is = con.getInputStream();
    15             try {
    16                 if (resourceName.endsWith(XML_FILE_EXTENSION)) {
    17                     props.loadFromXML(is);
    18                 }
    19                 else {
    20                     props.load(is);
    21                 }
    22             }
    23             finally {
    24                 is.close();
    25             }
    26         }
    27         return props;
    28     }

    它是通过加载器加载classpath下的META-INF/spring.handler文件,使用jdk的Properties方法加载,加载完后返回properties的实例,最后拿到对应的标签处理器

     拿到命名空间处理器的类名后

    1 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
    2                 namespaceHandler.init();
    3                 handlerMappings.put(namespaceUri, namespaceHandler);
    4                 return namespaceHandler;

    第1行使用bean助手类实例化了这个命名空间处理器,并进行了初始化,加入我显示使用的是aop的命名空间,那么这个命名空间处理器是AopNamespaceHandler类的实例

    它对应init方法代码如下:这个aop命名空间处理器中拥有下面这些类别的标签解析器,第一个我们是最属性的,这个解析器里提供了aop:config标签中pointcut,before之类的解析方法

    第3行将初始化好的命名空间处理器放到handlerMappings中,如果下次要使用就直接可以拿到,不需要在此实例化

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

    下面是一些bean定义解析器的继承结构,各种各样的解析器

    向处理器中注册解析器
    1 protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
    2         this.parsers.put(elementName, parser);
    3     }

    第2行的parsers是一个Map,用来存放bean定义解析器

    得到命名空间处理器后再调用命名空间处理器的parse方法handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

    进入parse方法,这个方法又调用了findParserForElement方法
    1 private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
          
    2 String localName = parserContext.getDelegate().getLocalName(element); 3 BeanDefinitionParser parser = this.parsers.get(localName); 4 if (parser == null) { 5 parserContext.getReaderContext().fatal( 6 "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); 7 } 8 return parser; 9 }

    第2行,通过这个元素拿到了它的本地名字,比如aop:config元素的本地名为config

    通过config从命名空间中的解析器map容器中拿到了对应的解析器,然后调用这个aop的config解析器的parse方法

     1 @Override
     2     public BeanDefinition parse(Element element, ParserContext parserContext) {
     3         CompositeComponentDefinition compositeDef =
     4                 new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
     5         parserContext.pushContainingComponent(compositeDef);
     6 
     7         configureAutoProxyCreator(parserContext, element);
     8 
     9         List<Element> childElts = DomUtils.getChildElements(element);
    10         for (Element elt: childElts) {
    11             String localName = parserContext.getDelegate().getLocalName(elt);
    12             if (POINTCUT.equals(localName)) {
    13                 parsePointcut(elt, parserContext);
    14             }
    15             else if (ADVISOR.equals(localName)) {
    16                 parseAdvisor(elt, parserContext);
    17             }
    18             else if (ASPECT.equals(localName)) {
    19                 parseAspect(elt, parserContext);
    20             }
    21         }
    22 
    23         parserContext.popAndRegisterContainingComponent();
    24         return null;
    25     }
    第三行创建了一个组件定义,并将它压入ParseContext上下文中的stack中

    进入第7行的方法
    1 private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
    2         AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
    3     }

    这个方法是在配置自动代理创建者,这个方法在配置了<aop:config>才使用,如果你配置的是<aop:aspect-autoproxy/>这个标签,就会使用AspectJAutoProxyBeanDefinitionParser这个类的解析器。回到aop:config这个标签的解析器,上面的第2行使用了AopNamespaceUtils aop命名空间助手类注册一个自动代理切面创建者,进入这个方法看看

    1 public static void registerAspectJAutoProxyCreatorIfNecessary(
    2             ParserContext parserContext, Element sourceElement) {
    3 
    4         BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
    5                 parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    6         useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    7         registerComponentIfNecessary(beanDefinition, parserContext);
    8     }
    第4行调用了registerAspectJAutoProxyCreatorIfNecessary的重载方法,这个方法传入了BeanRegistry类的对象(这里的这个实例实际上是DefaultListableBeanFactory)和ParseContext包装后的可提取资源实例
    进入这个方法查看一下它的代码
    1 public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
    2         return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
    3     }

    第2行传入了一个AspectJAwareAdvisorAutoProxyCreator.class类对象,暂且不管它是干啥的,继续往下看

     1 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
     2         Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
     3         if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
     4             BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
     5             if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
     6                 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
     7                 int requiredPriority = findPriorityForClass(cls);
     8                 if (currentPriority < requiredPriority) {
     9                     apcDefinition.setBeanClassName(cls.getName());
    10                 }
    11             }
    12             return null;
    13         }
    14         RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    15         beanDefinition.setSource(source);
    16         beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    17         beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    18         registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    19         return beanDefinition;
    20     }

    第3行判断这个BeanFactory中的BeanDefinitionMap容器中是否存在一个key叫做AUTO_PROXY_CREATOR_BEAN_NAME

    (org.springframework.aop.config.internalAutoProxyCreator)的元素,如果存在就获得他的BeanDefinition对象,并且与我们传进来的AspectJAwareAdvisorAutoProxyCreator

    类名是否一样,如果一样就要根据优先级来选择其中一个作为自动创建代理类,在AopConfigUtils类中有个静态的属性list集合APC_PRIORITY_LIST,

    它在静态块中初始化

     1 private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<Class<?>>();
     2 
     3     /**
     4      * Setup the escalation list.
     5      */
     6     static {
     7         APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
     8         APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
     9         APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
    10     }

    我们在看看findPriorityForClass()方法

    private static int findPriorityForClass(String className) {
            for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
                Class<?> clazz = APC_PRIORITY_LIST.get(i);
                if (clazz.getName().equals(className)) {
                    return i;
                }
            }
            throw new IllegalArgumentException(
                    "Class name [" + className + "] is not a known auto-proxy creator class");
        }
    
    }

    看见了,它是以这些定义的顺序进行决定优先级的,只不过在集合中越后,优先级就越高

    让我们再次返回到registerOrEscalateApcAsRequired这个方法

     1 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
     2         Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
     3         if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
     4             BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
     5             if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
     6                 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
     7                 int requiredPriority = findPriorityForClass(cls);
     8                 if (currentPriority < requiredPriority) {
     9                     apcDefinition.setBeanClassName(cls.getName());
    10                 }
    11             }
    12             return null;
    13         }
    14         RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    15         beanDefinition.setSource(source);
    16         beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    17         beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    18         registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    19         return beanDefinition;
    20     }

    如果容器中没有AUTO_PROXY_CREATOR_BEAN_NAME对应的自动代理器,那么就跳到第14行,创建一个AspectJAwareAdvisorAutoProxyCreator实例注入到RootBeanDefinition类中,这个类是BeanDefinition的子类,第16行设置了这个BeanDefinition的优先级,第17行设置这个BeanDefinition的角色定位,用户自己定义的bean的角色是BeanDefinition.ROLE_APPLICTION

     第18行向beanFactory中注册这个BeanDefinition,它的实现代码如下

     1 @Override
     2     public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
     3             throws BeanDefinitionStoreException {
     4 
     5         Assert.hasText(beanName, "Bean name must not be empty");
     6         Assert.notNull(beanDefinition, "BeanDefinition must not be null");
     7 
     8         if (beanDefinition instanceof AbstractBeanDefinition) {
     9             try {
    10                 ((AbstractBeanDefinition) beanDefinition).validate();
    11             }
    12             catch (BeanDefinitionValidationException ex) {
    13                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
    14                         "Validation of bean definition failed", ex);
    15             }
    16         }
    17 
    18         BeanDefinition oldBeanDefinition;
    19 
    20         oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    21         if (oldBeanDefinition != null) {
    22             if (!isAllowBeanDefinitionOverriding()) {
    23                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
    24                         "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
    25                         "': There is already [" + oldBeanDefinition + "] bound.");
    26             }
    27             else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
    28                 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
    29                 if (this.logger.isWarnEnabled()) {
    30                     this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
    31                             "' with a framework-generated bean definition: replacing [" +
    32                             oldBeanDefinition + "] with [" + beanDefinition + "]");
    33                 }
    34             }
    35             else if (!beanDefinition.equals(oldBeanDefinition)) {
    36                 if (this.logger.isInfoEnabled()) {
    37                     this.logger.info("Overriding bean definition for bean '" + beanName +
    38                             "' with a different definition: replacing [" + oldBeanDefinition +
    39                             "] with [" + beanDefinition + "]");
    40                 }
    41             }
    42             else {
    43                 if (this.logger.isDebugEnabled()) {
    44                     this.logger.debug("Overriding bean definition for bean '" + beanName +
    45                             "' with an equivalent definition: replacing [" + oldBeanDefinition +
    46                             "] with [" + beanDefinition + "]");
    47                 }
    48             }
    49             this.beanDefinitionMap.put(beanName, beanDefinition);
    50         }
    51         else {
    52             if (hasBeanCreationStarted()) {
    53                 // Cannot modify startup-time collection elements anymore (for stable iteration)
    54                 synchronized (this.beanDefinitionMap) {
    55                     this.beanDefinitionMap.put(beanName, beanDefinition);
    56                     List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
    57                     updatedDefinitions.addAll(this.beanDefinitionNames);
    58                     updatedDefinitions.add(beanName);
    59                     this.beanDefinitionNames = updatedDefinitions;
    60                     if (this.manualSingletonNames.contains(beanName)) {
    61                         Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
    62                         updatedSingletons.remove(beanName);
    63                         this.manualSingletonNames = updatedSingletons;
    64                     }
    65                 }
    66             }
    67             else {
    68                 // Still in startup registration phase
    69                 this.beanDefinitionMap.put(beanName, beanDefinition);
    70                 this.beanDefinitionNames.add(beanName);
    71                 this.manualSingletonNames.remove(beanName);
    72             }
    73             this.frozenBeanDefinitionNames = null;
    74         }
    75 
    76         if (oldBeanDefinition != null || containsSingleton(beanName)) {
    77             resetBeanDefinition(beanName);
    78         }
    79     }

    第10行对这个BeanDefinition进行验证,如果这个BeanDefinition有需要重载的方法,并且还存在工厂方法,那就报错,这两者不能共存。静态工厂必须创建bean的实例

    什么是重载的方法,比如使用了lookup-method,replace-method这些标签,比如:

    <bean id="service" class="com.test.UserService" scope="prototype" />

    <bean id="userService" class="com.test.UserServiceCreator">

      <lookup-method name="getService" bean="server" />  

    </bean>

    我们调用UserServiceCreator的getService,取出来的值是UseService的实例,如果此时我们把UserSericeCreator设置一个静态工厂方法,修改成下面这种

    <bean id="userService" class="com.test.UserServiceCreator" factory-method="createService">

      <lookup-method name="getService" bean="server" />  

    </bean>

    这样配置是错误的,在Spring创建bean实例的时候,spring就不知你要创建的是哪个对象了,这个id为userService的bean应该是UserServiceCreator的代理实例(方法重载会用到动态代理)还是工厂方法createService创建的UserService实例,所以只能报错。

    第20行是获得老的BeanDefinition,如果存在老的BeanDefinition,就检查是否允许覆盖

    第49行将定义好的BeanDefinition存到BeanFactory的beanDefinitionMap中,覆盖oldBeanDefinition

    如果不存在oldBeanDefinition,那么跳到52行,判断是不是已经开始开始创建bean了,内部代码只是判断bean工厂的属性alreadyCreated集合是否不为空,为空就表示还没有开始,不为空表示开始了

    第69行将BeanDefinition注册到容器中,第70行将BeanDefinition的名字注入到容器中

    创建好AspectJAwareAdvisorAutoProxyCreator类的BeanDefinition后,继续调用了AopNamespaceUtils的useClassProxyingIfNecessary方法

     1 private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
     2         if (sourceElement != null) {
     3             boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
     4             if (proxyTargetClass) {
     5                 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
     6             }
     7             boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
     8             if (exposeProxy) {
     9                 AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
    10             }
    11         }
    12     }

    第3行的PROXY_TARGET_CLASS_ATTRIBUTE的值为proxy-target-class,如果这个属性为true那么就使用cglib做代理,默认为false使用JDK的动态代理

    进入第5行的forceAutoProxyCreatorToUseClassProxying方法

    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
                BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
                definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
            }

    很显然BeanFactory中是存在AUTO_PROXY_CREATOR_BEAN_NAME的,这个key对应对象是AspectJAwareAdvisorAutoProxyCreator的BeanDefinition,前面已经说过了。

    如果存在就给这个BeanDefinition添加属性值proxyTargetClass为true,表示将使用cglib进行代理,后面创建代理类的时候会再次提到

    第7行判断当前是否需要暴露代理

    useClassProxyingIfNecessary方法调用结束后有调用了AopNamespaceUtils的registerComponentIfNecessary方法

    1 private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) {
    2         if (beanDefinition != null) {
    3             BeanComponentDefinition componentDefinition =
    4                     new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
    5             parserContext.registerComponent(componentDefinition);
    6         }
    7     }

    第4行代码内部调用了以下这个方法,它在寻找propertyValues中是否有嵌入的BeanDefinition,BeanDefinitionHolder

     1 private void findInnerBeanDefinitionsAndBeanReferences(BeanDefinition beanDefinition) {
     2         List<BeanDefinition> innerBeans = new ArrayList<BeanDefinition>();
     3         List<BeanReference> references = new ArrayList<BeanReference>();
     4         PropertyValues propertyValues = beanDefinition.getPropertyValues();
     5         for (int i = 0; i < propertyValues.getPropertyValues().length; i++) {
     6             PropertyValue propertyValue = propertyValues.getPropertyValues()[i];
     7             Object value = propertyValue.getValue();
     8             if (value instanceof BeanDefinitionHolder) {
     9                 innerBeans.add(((BeanDefinitionHolder) value).getBeanDefinition());
    10             }
    11             else if (value instanceof BeanDefinition) {
    12                 innerBeans.add((BeanDefinition) value);
    13             }
    14             else if (value instanceof BeanReference) {
    15                 references.add((BeanReference) value);
    16             }
    17         }
    18         this.innerBeanDefinitions = innerBeans.toArray(new BeanDefinition[innerBeans.size()]);
    19         this.beanReferences = references.toArray(new BeanReference[references.size()]);
    20     }

    返回到上一层

    1 private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) {
    2         if (beanDefinition != null) {
    3             BeanComponentDefinition componentDefinition =
    4                     new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
    5             parserContext.registerComponent(componentDefinition);
    6         }
    7     }

    这个BeanComponentDefinition类是BeanDefinitionHolder的子类,从名字可以看出它叫BeanDefinition持有者,内部有一个beanName属性,相对应就有个BeanDefinition属性

    第5行将这个复合的BeanDefinitionHolder注册到了ParseContext的一个叫containingComponents的stack中

    这些方法调用完成后我们直接返回到ConfigBeanDefinitionParser类的parse方法。之前我们分析的是下面方法的第6行的configureAutoProxyCreator方法,有点绕,自己分析的时候需要结合

    序列图来看源码

     1 public BeanDefinition parse(Element element, ParserContext parserContext) {
     2         CompositeComponentDefinition compositeDef =
     3                 new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
     4         parserContext.pushContainingComponent(compositeDef);
     5 
     6         configureAutoProxyCreator(parserContext, element);
     7 
     8         List<Element> childElts = DomUtils.getChildElements(element);
     9         for (Element elt: childElts) {
    10             String localName = parserContext.getDelegate().getLocalName(elt);
    11             if (POINTCUT.equals(localName)) {
    12                 parsePointcut(elt, parserContext);
    13             }
    14             else if (ADVISOR.equals(localName)) {
    15                 parseAdvisor(elt, parserContext);
    16             }
    17             else if (ASPECT.equals(localName)) {
    18                 parseAspect(elt, parserContext);
    19             }
    20         }
    21 
    22         parserContext.popAndRegisterContainingComponent();
    23         return null;
    24     }

    第8行取得了<aop:config>的子元素,我这里就一个子元素<aop:aspect>

    循环遍历子元素,下面是ConfigBeanDefinitionParser类定义的标签元素

    class ConfigBeanDefinitionParser implements BeanDefinitionParser {
    
        private static final String ASPECT = "aspect";
        private static final String EXPRESSION = "expression";
        private static final String ID = "id";
        private static final String POINTCUT = "pointcut";
        private static final String ADVICE_BEAN_NAME = "adviceBeanName";
        private static final String ADVISOR = "advisor";
        private static final String ADVICE_REF = "advice-ref";
        private static final String POINTCUT_REF = "pointcut-ref";
        private static final String REF = "ref";
        private static final String BEFORE = "before";
        private static final String DECLARE_PARENTS = "declare-parents";
        private static final String TYPE_PATTERN = "types-matching";
        private static final String DEFAULT_IMPL = "default-impl";
        private static final String DELEGATE_REF = "delegate-ref";
        private static final String IMPLEMENT_INTERFACE = "implement-interface";
        private static final String AFTER = "after";
        private static final String AFTER_RETURNING_ELEMENT = "after-returning";
        private static final String AFTER_THROWING_ELEMENT = "after-throwing";
        private static final String AROUND = "around";
        private static final String RETURNING = "returning";
        private static final String RETURNING_PROPERTY = "returningName";
        private static final String THROWING = "throwing";
        private static final String THROWING_PROPERTY = "throwingName";
        private static final String ARG_NAMES = "arg-names";
        private static final String ARG_NAMES_PROPERTY = "argumentNames";
        private static final String ASPECT_NAME_PROPERTY = "aspectName";
        private static final String DECLARATION_ORDER_PROPERTY = "declarationOrder";
        private static final String ORDER_PROPERTY = "order";
        private static final int METHOD_INDEX = 0;
        private static final int POINTCUT_INDEX = 1;
        private static final int ASPECT_INSTANCE_FACTORY_INDEX = 2;

    上面这些静态常量很眼熟吧。我的测试标签是aop:aspect,所以我们直接跳到第18行,进入到parseAspect方法看看

     1 private void parseAspect(Element aspectElement, ParserContext parserContext) {
     2         String aspectId = aspectElement.getAttribute(ID);
     3         String aspectName = aspectElement.getAttribute(REF);
     4 
     5         try {
     6             this.parseState.push(new AspectEntry(aspectId, aspectName));
     7             List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
     8             List<BeanReference> beanReferences = new ArrayList<BeanReference>();
     9 
    10             List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
    11             for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
    12                 Element declareParentsElement = declareParents.get(i);
    13                 beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
    14             }
    15 
    16             // We have to parse "advice" and all the advice kinds in one loop, to get the
    17             // ordering semantics right.
    18             NodeList nodeList = aspectElement.getChildNodes();
    19             boolean adviceFoundAlready = false;
    20             for (int i = 0; i < nodeList.getLength(); i++) {
    21                 Node node = nodeList.item(i);
    22                 if (isAdviceNode(node, parserContext)) {
    23                     if (!adviceFoundAlready) {
    24                         adviceFoundAlready = true;
    25                         if (!StringUtils.hasText(aspectName)) {
    26                             parserContext.getReaderContext().error(
    27                                     "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
    28                                     aspectElement, this.parseState.snapshot());
    29                             return;
    30                         }
    31                         beanReferences.add(new RuntimeBeanReference(aspectName));
    32                     }
    33                     AbstractBeanDefinition advisorDefinition = parseAdvice(
    34                             aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
    35                     beanDefinitions.add(advisorDefinition);
    36                 }
    37             }
    38 
    39             AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
    40                     aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
    41             parserContext.pushContainingComponent(aspectComponentDefinition);
    42 
    43             List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
    44             for (Element pointcutElement : pointcuts) {
    45                 parsePointcut(pointcutElement, parserContext);
    46             }
    47 
    48             parserContext.popAndRegisterContainingComponent();
    49         }
    50         finally {
    51             this.parseState.pop();
    52         }
    53     }

    第2,3行获得ID和bean的引用

    第6行将ID和ref包装成一个entry压入到一个叫做parseState的stack中

    第10行意思是在aspect元素下寻找declare-parents子元素,这个故事告诉我们spring的助手类真的很好用。这个标签是用于给某个类设置父类。如果对这个标签感兴趣可以去搜索相关的资料

    第18行取得了aspect下的所有子元素

    第22行判断当前标签是不是通知类型的标签,具体的实现代码如下

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

    当找到通知类型的标签,如aop:before,我们跳到第33行,看看parseAdvice方法

     1 private AbstractBeanDefinition parseAdvice(
     2             String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
     3             List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
     4 
     5         try {
     6             this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
     7 
     8             // create the method factory bean
     9             RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
    10             methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
    11             methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
    12             methodDefinition.setSynthetic(true);
    13 
    14             // create instance factory definition
    15             RootBeanDefinition aspectFactoryDef =
    16                     new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
    17             aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
    18             aspectFactoryDef.setSynthetic(true);
    19 
    20             // register the pointcut
    21             AbstractBeanDefinition adviceDef = createAdviceDefinition(
    22                     adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
    23                     beanDefinitions, beanReferences);
    24 
    25             // configure the advisor
    26             RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
    27             advisorDefinition.setSource(parserContext.extractSource(adviceElement));
    28             advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
    29             if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
    30                 advisorDefinition.getPropertyValues().add(
    31                         ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
    32             }
    33 
    34             // register the final advisor
    35             parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
    36 
    37             return advisorDefinition;
    38         }
    39         finally {
    40             this.parseState.pop();
    41         }
    42     }

    第9行又创建了一个RootBeanDefinition的实例

    第10行将切面的id和切面的方法保存到这个RootBeanDefinition中

    主要看到第21createAdviceDefinition的代码

     1 private AbstractBeanDefinition createAdviceDefinition(
     2             Element adviceElement, ParserContext parserContext, String aspectName, int order,
     3             RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
     4             List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
     5 
     6         RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
     7         adviceDefinition.setSource(parserContext.extractSource(adviceElement));
     8         //添加切面名
     9         adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
    10         adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
    11         //判断是否存在returning属性
    12         if (adviceElement.hasAttribute(RETURNING)) {
    13             adviceDefinition.getPropertyValues().add(
    14                     RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
    15         }
    16         if (adviceElement.hasAttribute(THROWING)) {
    17             adviceDefinition.getPropertyValues().add(
    18                     THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
    19         }
    //判断是否有参数
    20 if (adviceElement.hasAttribute(ARG_NAMES)) { 21 adviceDefinition.getPropertyValues().add( 22 ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES)); 23 } 24 25 ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues(); 26 cav.addIndexedArgumentValue(METHOD_INDEX, methodDef); 27 28 Object pointcut = parsePointcutProperty(adviceElement, parserContext); 29 if (pointcut instanceof BeanDefinition) { 30 cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut); 31 beanDefinitions.add((BeanDefinition) pointcut); 32 } 33 else if (pointcut instanceof String) { 34 RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut); 35 cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef); 36 beanReferences.add(pointcutRef); 37 } 38 39 cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef); 40 41 return adviceDefinition; 42 }

    第28行从这个通知元素中解析切点引用pointcut-ref,如果你在这个通知标签中使用的pointcut属性,那么会返回一个BeanDefinition类型

    讲了这么多BeanDefinition,这个BeanDefinition到底是个什么东西,BeanDefinition翻译过来就是bean定义的意思,相当于将xml文件中定义的Bean

    翻译成java代码,如<bean id="hello" class="com.test.Hello" scope="singleton" />在BeanDefinition这个类中会都会有相对应的属性,它也有id

    有className,有scope,有initMethodName,有destroyMethodName这些个属性,就相当于把xml定义的bean翻译成java代码。

    通知类型的标签设置完成后,我们再看看pointcut的解析

     1 private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
     2         String id = pointcutElement.getAttribute(ID);
     3         String expression = pointcutElement.getAttribute(EXPRESSION);
     4 
     5         AbstractBeanDefinition pointcutDefinition = null;
     6 
     7         try {
     8             this.parseState.push(new PointcutEntry(id));
     9             pointcutDefinition = createPointcutDefinition(expression);
    10             pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
    11 
    12             String pointcutBeanName = id;
    13             if (StringUtils.hasText(pointcutBeanName)) {
    14                 parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
    15             }
    16             else {
    17                 pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
    18             }
    19 
    20             parserContext.registerComponent(
    21                     new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
    22         }
    23         finally {
    24             this.parseState.pop();
    25         }
    26 
    27         return pointcutDefinition;
    28     }

     第9行创建了一个属性className为AspectJExpressionPointcut的BeanDefinition,具体这个拿来干嘛的,到后面使用到的时候再说,一路debug过来,定义了一大堆的BeanDefinition

    都是为后面创建bean做准备

    第14行把创建的切点BeanDefinition注册到BeanFactory中

    至此可以发现,所谓的xml的解析,都是将相应的配置信息解析出来封装成一个叫做BeanDefinition的对象,最后注册到BeanFactory的BeanDefinitionMap的map容器中

    aop:config解析完成后,我们看看bean标签的解析,bean是属于默认的命名空间中定义的标签,解析时使用的DefaultBeanDefinitionDocumentReader类的parseDefaultElement方法

     1 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
     2         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
     3             importBeanDefinitionResource(ele);
     4         }
     5         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
     6             processAliasRegistration(ele);
     7         }
     8         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
     9             processBeanDefinition(ele, delegate);
    10         }
    11         else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
    12             // recurse
    13             doRegisterBeanDefinitions(ele);
    14         }
    15     }

    我们解析的是bean标签,所以直接跳到第8行,看看processBeanDefinition方法

     1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
     2         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
     3         if (bdHolder != null) {
     4             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
     5             try {
     6                 // Register the final decorated instance.
     7                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
     8             }
     9             catch (BeanDefinitionStoreException ex) {
    10                 getReaderContext().error("Failed to register bean definition with name '" +
    11                         bdHolder.getBeanName() + "'", ele, ex);
    12             }
    13             // Send registration event.
    14             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    15         }
    16     }

    进入第2行的parseBeanDefinitionElement

     1 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
     2         String id = ele.getAttribute(ID_ATTRIBUTE);//取得bean标签的id
     3         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//取得Bean标签的name属性
     4 
     5         List<String> aliases = new ArrayList<String>();
     6         if (StringUtils.hasLength(nameAttr)) {
     7             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);//将name属性的到的名字按,分割,并作为别名
     8             aliases.addAll(Arrays.asList(nameArr));
     9         }
    10 
    11         String beanName = id;
    12         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
    13             beanName = aliases.remove(0);
    14             if (logger.isDebugEnabled()) {
    15                 logger.debug("No XML 'id' specified - using '" + beanName +
    16                         "' as bean name and " + aliases + " as aliases");
    17             }
    18         }
    19 
    20         if (containingBean == null) {
    21             checkNameUniqueness(beanName, aliases, ele);
    22         }
    23 
    24         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    25         if (beanDefinition != null) {
    26             if (!StringUtils.hasText(beanName)) {
    27                 try {
    28                     if (containingBean != null) {
    29                         beanName = BeanDefinitionReaderUtils.generateBeanName(
    30                                 beanDefinition, this.readerContext.getRegistry(), true);
    31                     }
    32                     else {
    33                         beanName = this.readerContext.generateBeanName(beanDefinition);
    34                         // Register an alias for the plain bean class name, if still possible,
    35                         // if the generator returned the class name plus a suffix.
    36                         // This is expected for Spring 1.2/2.0 backwards compatibility.
    37                         String beanClassName = beanDefinition.getBeanClassName();
    38                         if (beanClassName != null &&
    39                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
    40                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
    41                             aliases.add(beanClassName);
    42                         }
    43                     }
    44                     if (logger.isDebugEnabled()) {
    45                         logger.debug("Neither XML 'id' nor 'name' specified - " +
    46                                 "using generated bean name [" + beanName + "]");
    47                     }
    48                 }
    49                 catch (Exception ex) {
    50                     error(ex.getMessage(), ele);
    51                     return null;
    52                 }
    53             }
    54             String[] aliasesArray = StringUtils.toStringArray(aliases);
    55             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    56         }
    57 
    58         return null;
    59     }

    第12表示,如果存在id和name,并且id没有值,name有值,那么就取name的第一个name值做为beanName

    第21行,对beanName和别名进行检查,BeanDefinitionParserDelegate类中有个usedNames容器,这个容器用于保存已经使用了的beanName,所以这个方法是在检查是否有重复定义的beanName或者别名

    第24行又将bean标签翻译成了一个BeanDefinition,它是怎么翻译的等下再说,先往下看

    第29行,如果这个bean没有指定beanName,那么就自己生成一个,一般是这个bean类的类名加上#在加一个数字,这个数字是从零开始的,这个数字要看这个bean是BeanFactory中的第几个没有写beanName的bean了,他叫什么,这不是重点,我们一般也不会去写个没有beanName的bean,不写beanName的情况一般是给spring通过类型来自动注入

    下面开始讲讲它是怎么解析成BeanDefinition的

     1 String className = null;
     2         if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
     3             className = ele.getAttribute(CLASS_ATTRIBUTE).trim();//获得class属性定义的className
     4         }
     5 
     6         try {
     7             String parent = null;
     8             if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
     9                 parent = ele.getAttribute(PARENT_ATTRIBUTE); //如果有parent属性就获取到parent属性的值
    10             }
    11             AbstractBeanDefinition bd = createBeanDefinition(className, parent);//创建一个BeanDefinition对象
    12 
    13             parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
    14             bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));//如果这个bean元素有description子标签,获得他的值设置到BeanDefinition中
    15 
    16             parseMetaElements(ele, bd);//解析元标签<meta key="" value="">,当需要用到的时候,可以用过BeanDefinition的getAttribute(key)获得
    17             parseLookupOverrideSubElements(ele, bd.getMethodOverrides());//解析bean标签中是够含有lookup-method标签,如果有就设置到methodOverrides中
    18             parseReplacedMethodSubElements(ele, bd.getMethodOverrides());//解析replace-method标签
    19 
    20             parseConstructorArgElements(ele, bd);//解析构造器参数
    21             parsePropertyElements(ele, bd);//解析property标签
    22             parseQualifierElements(ele, bd);//解析qualifier
    23 
    24             bd.setResource(this.readerContext.getResource());
    25             bd.setSource(extractSource(ele));
    26 
    27             return bd;

    看到第13行,这个方法是用来解析bean定义的属性的

     1 public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
     2             BeanDefinition containingBean, AbstractBeanDefinition bd) {
     3 
     4         if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {//如果存在singleton这个属性,就解析,当不做任何处理,提示用户过时了,应该使用scope来代替
     5             error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
     6         }
     7         else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {//如果存在scope属性就取得取得他的值,并设置到BeanDefinition中
     8             bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
     9         }
    10         else if (containingBean != null) {
    11             // Take default from containing bean in case of an inner bean definition.
    12             bd.setScope(containingBean.getScope());
    13         }
    14 
    15         if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
    16             bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
    17         }
    18 
    19         String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
    20         if (DEFAULT_VALUE.equals(lazyInit)) {
    21             lazyInit = this.defaults.getLazyInit();
    22         }
    23         bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
    24 
    25         String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
    26         bd.setAutowireMode(getAutowireMode(autowire));
    27 
    28         String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
    29         bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
    30 
    31         if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
    32             String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
    33             bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
    34         }
    35 
    36         String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
    37         if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
    38             String candidatePattern = this.defaults.getAutowireCandidates();
    39             if (candidatePattern != null) {
    40                 String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
    41                 bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
    42             }
    43         }
    44         else {
    45             bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
    46         }
    47 
    48         if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
    49             bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
    50         }
    51 
    52         if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
    53             String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
    54             if (!"".equals(initMethodName)) {
    55                 bd.setInitMethodName(initMethodName);
    56             }
    57         }
    58         else {
    59             if (this.defaults.getInitMethod() != null) {
    60                 bd.setInitMethodName(this.defaults.getInitMethod());
    61                 bd.setEnforceInitMethod(false);
    62             }
    63         }
    64 
    65         if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
    66             String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
    67             bd.setDestroyMethodName(destroyMethodName);
    68         }
    69         else {
    70             if (this.defaults.getDestroyMethod() != null) {
    71                 bd.setDestroyMethodName(this.defaults.getDestroyMethod());
    72                 bd.setEnforceDestroyMethod(false);
    73             }
    74         }
    75 
    76         if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
    77             bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
    78         }
    79         if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
    80             bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
    81         }
    82 
    83         return bd;
    84     }

    将bean标签中所有的属性进行读取,有定义的就读过来设置到BeanDefinition中,如果没有的自然是使用默认值,解析完bean标签上的属性后,自然还有解析bean

    标签里面的子标签,这里选择其中解析property解析下,下面是部分源码

     1 String propertyName = ele.getAttribute(NAME_ATTRIBUTE);//获取property标签上的那么属性
     2         if (!StringUtils.hasLength(propertyName)) {
     3             error("Tag 'property' must have a 'name' attribute", ele);
     4             return;
     5         }
     6         this.parseState.push(new PropertyEntry(propertyName));
     7         try {
     8             if (bd.getPropertyValues().contains(propertyName)) {
     9                 error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
    10                 return;
    11             }
    12             Object val = parsePropertyValue(ele, bd, propertyName);
    13             PropertyValue pv = new PropertyValue(propertyName, val);//将属性值和对应的value打包成一个PropertyValue
    14             parseMetaElements(ele, pv);
    15             pv.setSource(extractSource(ele));
    16             bd.getPropertyValues().addPropertyValue(pv);//将包含属性值和值得propertyValue设置到BeanDefinition中

    我们看到第12行内部的部分代码

     1 if (hasRefAttribute) {
     2             String refName = ele.getAttribute(REF_ATTRIBUTE);
     3             if (!StringUtils.hasText(refName)) {
     4                 error(elementName + " contains empty 'ref' attribute", ele);
     5             }
     6             RuntimeBeanReference ref = new RuntimeBeanReference(refName);
     7             ref.setSource(extractSource(ele));
     8             return ref;
     9         }
    10         else if (hasValueAttribute) {
    11             TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
    12             valueHolder.setSource(extractSource(ele));
    13             return valueHolder;
    14         }

    第2行去获得ref属性的值,并且把这个值包装成一个RuntimeBeanReference对象

    第11行,如果不是个ref类型的值(value属性指定的值)就被包装成TypedStringValue类型的对象。

    回到processBeanDefinition方法

     1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
     2         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
     3         if (bdHolder != null) {
     4             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
     5             try {
     6                 // Register the final decorated instance.
     7                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
     8             }
     9             catch (BeanDefinitionStoreException ex) {
    10                 getReaderContext().error("Failed to register bean definition with name '" +
    11                         bdHolder.getBeanName() + "'", ele, ex);
    12             }
    13             // Send registration event.
    14             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    15         }
    16     }

    第四行又对BeanDefinitionHolder做了些装饰,这个方法的作用,主要是用来解析bean中嵌套的自定标签,如<bean id="" class=""><mytag:test /></bean>

    在这里顺便再分析一下bean中construct-arg的解析方式

     1 public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
     2         String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);//获取index属性的值
     3         String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);//获取type属性的值
     4         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//获取name属性的值
     5         if (StringUtils.hasLength(indexAttr)) {
     6             try {
     7                 int index = Integer.parseInt(indexAttr);
     8                 if (index < 0) {
     9                     error("'index' cannot be lower than 0", ele);
    10                 }
    11                 else {
    12                     try {
    13                         this.parseState.push(new ConstructorArgumentEntry(index));
    14                         Object value = parsePropertyValue(ele, bd, null);//这段代码和解析property标签的方式一样,对ref的值包装成RuntimeBeanReference实例,value包装成TypeStringValue的实例
    15                         ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
    16                         if (StringUtils.hasLength(typeAttr)) {
    17                             valueHolder.setType(typeAttr);
    18                         }
    19                         if (StringUtils.hasLength(nameAttr)) {
    20                             valueHolder.setName(nameAttr);
    21                         }
    22                         valueHolder.setSource(extractSource(ele));
    23                         if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
    24                             error("Ambiguous constructor-arg entries for index " + index, ele);
    25                         }
    26                         else {
    27                             bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
    28                         }
    29                     }
    30                     finally {
    31                         this.parseState.pop();
    32                     }
    33                 }
    34             }
    35             catch (NumberFormatException ex) {
    36                 error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
    37             }
    38         }
    39         else {
    40             try {
    41                 this.parseState.push(new ConstructorArgumentEntry());
    42                 Object value = parsePropertyValue(ele, bd, null);
    43                 ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
    44                 if (StringUtils.hasLength(typeAttr)) {
    45                     valueHolder.setType(typeAttr);
    46                 }
    47                 if (StringUtils.hasLength(nameAttr)) {
    48                     valueHolder.setName(nameAttr);
    49                 }
    50                 valueHolder.setSource(extractSource(ele));
    51                 bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
    52             }
    53             finally {
    54                 this.parseState.pop();
    55             }
    56         }
    57     }

    其实和解析property相同的套路,不同在与,property的是将返回回来的value用添加到了BeanDefinition的propertyValues属性中,而构造器标签对value的封装使用了

    ConstructorArgumentValues.ValueHolder值持有者来封装,并把这个值存放到BeanDefinition的
    indexedArgumentValue属性中

    一切都准备就绪了,各种属性都设置到为了BeanDefinition中了,那么剩下的就是注册到BeanFactory中了
     1 public static void registerBeanDefinition(
     2             BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
     3             throws BeanDefinitionStoreException {
     4 
     5         // Register bean definition under primary name.
     6         String beanName = definitionHolder.getBeanName();
     7         registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
     8 
     9         // Register aliases for bean name, if any.
    10         String[] aliases = definitionHolder.getAliases();
    11         if (aliases != null) {
    12             for (String alias : aliases) {
    13                 registry.registerAlias(beanName, alias);
    14             }
    15         }
    16     }

    看到第7行的代码有没有似曾相识的感觉,我们在分析aop:config的时候就已经分析过了,如果忘记了往上翻,这里就不再重复说了,现在主要是看第13的代码,别名的注册

     1 public void registerAlias(String name, String alias) {
     2         Assert.hasText(name, "'name' must not be empty");
     3         Assert.hasText(alias, "'alias' must not be empty");
     4         if (alias.equals(name)) {//如果别名和beanName相同,那么就删掉它,不需要别名
     5             this.aliasMap.remove(alias);
     6         }
     7         else {
     8             String registeredName = this.aliasMap.get(alias);//如果这个别名已经存在就拿出对应的beanName
     9             if (registeredName != null) {
    10                 if (registeredName.equals(name)) {//如果对应的beanName是相同的,那么就无需再次注册了
    11                     // An existing alias - no need to re-register
    12                     return;
    13                 }
    14                 if (!allowAliasOverriding()) {//如果不相等,就判断是否允许别名覆盖
    15                     throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
    16                             name + "': It is already registered for name '" + registeredName + "'.");
    17                 }
    18             }
    19             checkForAliasCircle(name, alias);
    20             this.aliasMap.put(alias, name);
    21         }
    22     }

    第19行进行别名循环依赖检查,如果出现a能找到b,b又能找c,c又能找到a就会出错

    当xml中所有的标签解析成BeanDefinition后,xml的解析工作也就结束了,接下来要做的事情就是创建bean了。

     
  • 相关阅读:
    基本数据类型包装类
    LeetCode算法题-Robot Return to Origin(Java实现)
    LeetCode算法题-Two Sum IV
    LeetCode算法题-Set Mismatch(Java实现)
    LeetCode算法题-Maximum Average Subarray I(Java实现)
    LeetCode算法题-Average of Levels in Binary Tree(Java实现)
    LeetCode算法题-Sum of Square Numbers(Java实现)
    LeetCode算法题-Maximum Product of Three Numbers(Java实现)
    LeetCode算法题-Merge Two Binary Trees(Java实现)
    LeetCode算法题-Construct String from Binary Tree(Java实现)
  • 原文地址:https://www.cnblogs.com/honger/p/6819149.html
Copyright © 2011-2022 走看看