spring源码解析---spring-core(一)
  OFqMI21Mpnzn 2023年11月02日 51 0


https://github.com/seaswalker

https://github.com/seaswalker/Spring

使用版本spring4.2.2或者4.1.1


基本



本部分从最基本的Spring开始。配置文件:


<?
           xml 
           version
           =
           "
           1.0
           " 
           encoding
           =
           "
           UTF-8
           "
           ?>
 
          
<beans 
           xmlns="http://www.springframework.org/schema/beans"
 
          
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 
          
       xsi:schemaLocation="
 
          
http://www.springframework.org/schema/beans
 
          
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           ">
 
          
<
           bean 
           class
           =
           "
           base.SimpleBean
           "
           ></
           bean
           >
 
          
</
           beans
           >


###原作者没有写beans的命名空间及约束 导致xml验证失败,这里加上了



###bean部分就是类的引用地址


启动代码:


public 
           static 
           void 
           main(
           String
           [] args) {
 
          
ClassPathXmlApplicationContext 
           context 
           = 
           new 
           ClassPathXmlApplicationContext
           (
           "
           config.xml
           "
           );
 
          
SimpleBean 
           bean 
           = 
           context
           .
           getBean(
           SimpleBean
           .
           class);
 
          
bean
           .
           send();
 
          
context
           .
           close();
 
          
}
 
        
SimpleBean:
 
        
public 
           class 
           SimpleBean 
           {
 
          
public 
           void 
           send
           () {
 
          
System
           .
           out
           .
           println(
           "
           I am send method from SimpleBean!
           "
           );
 
          
}
 
          
}

ClassPathXmlApplicationContext



整个继承体系如下:



spring源码解析---spring-core(一)_xml


ResourceLoader代表了 加载资源的一种方式,正是策略模式的实现


 


构造器源码:


public           ClassPathXmlApplicationContext(
          String
          [] configLocations, 
          boolean 
          refresh, 
          ApplicationContext 
          parent) {
          
//          null
          
super          (parent);
          
setConfigLocations(configLocations);
          
//          默认true
          
if           (refresh) {
          
refresh();
          
}
          }


spring源码解析---spring-core(一)_xml_02



spring源码解析---spring-core(一)_spring_03


 


ClassPathXmlApplicationContext           context           =           new 
          ClassPathXmlApplicationContext
          (
          "
          config.xml
          "
          ); 调用只会是上述两个方法其中一个,这里明显是
          ClassPathXmlApplicationContext(String configLocation)

后面实际调用的都是本类的这个方法,如下图:



spring源码解析---spring-core(一)_xml_04


 


其实ClassPathXmlApplicationContext类里面的构造器(包括无参的共有9个在这个版本)。


 

 


构造器


 



spring源码解析---spring-core(一)_java_05



spring源码解析---spring-core(一)_构造器_06


AbstractApplicationContext


首先看父类构造器,沿着继承体系一直向上调用,直到AbstractApplicationContext:


 



spring源码解析---spring-core(一)_构造器_07



spring源码解析---spring-core(一)_java_08


public           AbstractApplicationContext(          ApplicationContext           parent) {
          
    this          ();
          
    setParent(parent);
          
}
          
public           AbstractApplicationContext() {
          
    this          .          resourcePatternResolver           =           getResourcePatternResolver();
          
}


PathMatchingResourcePatternResolver支持Ant风格的路径解析。下面简单概述下ant风格路径.



spring源码解析---spring-core(一)_java_09


 


 


设置配置文件路径


AbstractRefreshableConfigApplicationContext. setConfigLocations:

public           void           setConfigLocations(          String          .          ..           locations) {
          
if           (locations           !=           null          ) {
          
Assert          .          noNullElements(locations,           "          Config locations must not be null          "          );
          
this          .          configLocations           =           new           String          [locations          .          length];
          
for           (          int           i           =           0          ; i           <           locations          .
          length; i
          ++
          ) {
          
this          .          configLocations[i]           =           resolvePath(locations[i])          .          trim();
          
}
          
}           else           {
          
this          .          configLocations           =           null          ;
          
}
          
}
          

           
         
          
resolvePath:
          
protected             String             resolvePath(            String             path) {
            
return             getEnvironment()            .            resolveRequiredPlaceholders(path);
            
}


此方法的目的在于将占位符(placeholder)解析成实际的地址。比如可以这么写:  new ClassPathXmlApplicationContext("classpath:config.xml"); 那么classpath:就是需要被解析的。



spring源码解析---spring-core(一)_java_10

spring源码解析---spring-core(一)_spring_11


getEnvironment方法来自于ConfigurableApplicationContext接口,源码很简单,如果为空就调用createEnvironment创建一个。AbstractApplicationContext.createEnvironment:


protected             ConfigurableEnvironment             createEnvironment() {
            
    return             new             StandardEnvironment            ();//看下面的继承关系可以知道            StandardEnvironment是            ConfigurableEnvironment的实现类
            
}



spring源码解析---spring-core(一)_java_12


 


 


Environment接口


继承体系:



spring源码解析---spring-core(一)_java_13


Environmen接口**代表了当前应用所处的环境。**从此接口的方法可以看出,其主要和profile、Property相关。


Profile


Spring Profile特性是从3.1开始的,其主要是为了解决这样一种问题: 线上环境和测试环境使用不同的配置或是数据库或是其它。有了Profile便可以在 不同环境之间无缝切换。**Spring容器管理的所有bean都是和一个profile绑定在一起的。**使用了Profile的配置文件示例:


 



spring源码解析---spring-core(一)_java_14


 


在启动代码中可以用如下代码设置活跃(当前使用的)Profile:


context         .         getEnvironment()         .         setActiveProfiles(         "         dev
         "
         );


当然使用的方式还有很多(比如注解),参考:


spring3.1 profile 配置不同的环境 (打开失败)

Spring Profiles example

Property


这里的Property指的是程序运行时的一些参数,引用注释:


properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects,Maps, and so on.

Environment实现类 AbstractEnvironment 构造器


private          final          MutablePropertySources          propertySources          =          new          MutablePropertySources         (         this         .         logger);
         
public          AbstractEnvironment() {
         
customizePropertySources(         this         .         propertySources);
         
}



spring源码解析---spring-core(一)_java_15


PropertySources接口


继承体系:



spring源码解析---spring-core(一)_java_16

spring源码解析---spring-core(一)_构造器_17


 


 


此接口实际上是PropertySource的容器,默认的MutablePropertySources实现内部含有一个CopyOnWriteArrayList作为存储载体。


StandardEnvironment.customizePropertySources:


/*         * System environment property source name: {@value}          */         public          static          final          String          SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME          =          "         systemEnvironment         "         ;
         
/*         * JVM system properties property source name: {@value}          */         public          static          final          String          SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME          =          "         systemProperties         "         ;
         
@Override         protected          void          customizePropertySources(         MutablePropertySources          propertySources) {
         
propertySources         .         addLast(         new          MapPropertySource
         
(         SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME         , getSystemProperties()));
         
propertySources         .         addLast(         new          SystemEnvironmentPropertySource
         
(         SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME         , getSystemEnvironment()));
         
}


PropertySource接口


PropertySource接口代表了键值对的Property来源。继承体系:


 


 



spring源码解析---spring-core(一)_构造器_18


 


AbstractEnvironment.getSystemProperties:(此方法在 org.springframework.core.env.AbstractEnvironment里面 )



spring源码解析---spring-core(一)_spring_19


 


@Override       public        Map<       String       ,        Object       >
       
try
       
return (       Map)        System       .getProperties();      
       

       }
      
       
catch (       AccessControlException
       
return (       Map)        new        ReadOnlySystemAttributesMap() {      
       
@Override
       
protected        String        getSystemAttribute(       String        attributeName) {      
       
try
       
return        System       .getProperty(attributeName);      
       

       }
      
       
catch (       AccessControlException
       
if (logger       .isInfoEnabled()) {      
       
.info(format(       "       Caught AccessControlException when accessing system        "        +
       
"       property [%s]; its value will be returned [null]. Reason: %s       ",      
       
.getMessage()));      
       

       }
      
       
return        null;      
       

       }
      
       

       }
      
       

       };
      
       

       }
      
       

       }


这里的实现很有意思,如果安全管理器阻止获取全部的系统属性,那么会尝试获取单个属性的可能性,如果还不行就抛异常了。


getSystemEnvironment方法也是一个套路,不过最终调用的是System.getenv,可以获取jvm和OS的一些版本信息。


路径Placeholder处理


AbstractEnvironment.resolveRequiredPlaceholders:


 


@Override        public         String resolveRequiredPlaceholders(        String text) throws         IllegalArgumentException
        
//        text即配置文件路径,比如classpath:config.xml
        
return         this        .propertyResolver        .resolveRequiredPlaceholders(text);       
        

        }
       
       
propertyResolver是一个PropertySourcesPropertyResolver对象:
       
private          final          ConfigurablePropertyResolver          propertyResolver          =
         
new          PropertySourcesPropertyResolver         (         this         .         propertySources);


PropertyResolver接口


PropertyResolver继承体系(排除Environment分支):


 


路径Placeholder处理


AbstractEnvironment.resolveRequiredPlaceholders:

@Override        public         String         resolveRequiredPlaceholders(        String         text) throws         IllegalArgumentException         {
        
//        text即配置文件路径,比如classpath:config.xml
        
return         this        .        propertyResolver        .        resolveRequiredPlaceholders(text);
        
}
      
propertyResolver是一个PropertySourcesPropertyResolver对象:
      
private         final         ConfigurablePropertyResolver         propertyResolver         =
        
new         PropertySourcesPropertyResolver        (        this        .        propertySources);


PropertyResolver接口


PropertyResolver继承体系(排除Environment分支):


 



spring源码解析---spring-core(一)_构造器_20


 


此接口正是用来解析PropertyResource。


解析


AbstractPropertyResolver.resolveRequiredPlaceholders:


 


 



spring源码解析---spring-core(一)_java_21



spring源码解析---spring-core(一)_spring_22



spring源码解析---spring-core(一)_xml_23


 


@Override       public        String resolveRequiredPlaceholders(       String text) throws        IllegalArgumentException
       
if (       this       .strictHelper        ==        null) {      
       
this       .strictHelper        = createPlaceholderHelper(       false);      
       

       }
      
       
return doResolvePlaceholders(text,        this       .strictHelper);      
       

       }
      
      
private         PropertyPlaceholderHelper         createPlaceholderHelper(        boolean         ignoreUnresolvablePlaceholders) {
        
//        三个参数分别是${, }, :
        
return         new         PropertyPlaceholderHelper        (        this        .        placeholderPrefix,         this        .        placeholderSuffix,
        
this        .        valueSeparator, ignoreUnresolvablePlaceholders);
        
}
      
doResolvePlaceholders:
      
private         String         doResolvePlaceholders(        String         text,         PropertyPlaceholderHelper         helper) {
        
//        PlaceholderResolver接口依然是策略模式的体现
        
return         helper        .        replacePlaceholders(text,         new         PropertyPlaceholderHelper        .        PlaceholderResolver        () {
        
@Override
        
public         String         resolvePlaceholder        (        String         placeholderName        ) {
        
    return         getPropertyAsRawString(placeholderName);
        
}
        
});
        
}


其实代码执行到这里的时候还没有进行xml配置文件的解析,那么这里的解析placeHolder是什么意思呢,原因在于可以这么写:


System
        .
        setProperty(
        "
        spring
        "
        ,         "
        classpath
        "
        );
        
ClassPathXmlApplicationContext         context         =         new         ClassPathXmlApplicationContext
        (
        "
        ${spring}:config.xml
        "
        );
        
SimpleBean         bean         =         context
        .
        getBean(
        SimpleBean
        .
        class);


这样就可以正确解析。placeholder的替换其实就是字符串操作,这里只说一下正确的属性是怎么来的。实现的关键在于PropertySourcesPropertyResolver.getProperty:


 

@Override      protected       String getPropertyAsRawString(      String
      
    return getProperty(key,       String      .class,       false);     
      

      }
     
      
protected       <      T      >       T getProperty(      String key,       Class<      T      > targetValueType,       boolean
      
    if (      this      .propertySources       !=       null) {     
      
        for (      PropertySource<?> propertySource       :       this      .propertySources) {     
      
            Object value       = propertySource      .getProperty(key);     
      
            return
      

              }
     
      

      }
     
      
return       null;     
      

      }


很明显了,就是从System.getProperty和System.getenv获取,但是由于环境变量是无法自定义的,所以其实此处只能通过System.setProperty指定。


注意,classpath:XXX这种写法的classpath前缀到目前为止还没有被处理。


refresh



spring源码解析---spring-core(一)_spring_24


super(parent)和this.setConfigLocations(configLocations);说完 下面说是refresh这个方法


 


Spring bean解析就在此方法,所以单独提出来。


AbstractApplicationContext.refresh:



spring源码解析---spring-core(一)_java_25


作者版本:


@Override        public         void         refresh() throws         BeansException        ,         IllegalStateException         {
        
synchronized         (        this        .        startupShutdownMonitor) {
        
//         Prepare this context for refreshing.
        
prepareRefresh
        ();
        
//         Tell the subclass to refresh the internal bean factory.
        
ConfigurableListableBeanFactory         beanFactory         =         obtainFreshBeanFactory();
        
//         Prepare the bean factory for use in this context.
        
prepareBeanFactory(beanFactory);
        
try         {
        
//         Allows post-processing of the bean factory in context subclasses.
        
postProcessBeanFactory(beanFactory);
        
//         Invoke factory processors registered as beans in the context.
        
invokeBeanFactoryPostProcessors(beanFactory);
        
//         Register bean processors that intercept bean creation.
        
registerBeanPostProcessors(beanFactory);
        
//         Initialize message source for this context.
        
initMessageSource();
        
//         Initialize event multicaster for this context.
        
initApplicationEventMulticaster();
        
//         Initialize other special beans in specific context subclasses.
        
onRefresh();
        
//         Check for listener beans and register them.
        
registerListeners();
        
//         Instantiate all remaining (non-lazy-init) singletons.
        
finishBeanFactoryInitialization(beanFactory);
        
//         Last step: publish corresponding event.
        
finishRefresh();
        
}         catch         (        BeansException         ex) {
        
//         Destroy already created singletons to avoid dangling resources.
        
destroyBeans();
        
//         Reset 'active' flag.
        
cancelRefresh(ex);
        
//         Propagate exception to caller.
        
throw         ex;
        
}         finally         {
        
//         Reset common introspection caches in Spring's core, since we
        
//         might not ever need metadata for singleton beans anymore...
        
resetCommonCaches();
        
}
        
}
        
}


prepareRefresh


protected        void
       
this       .startupDate        =        System       .currentTimeMillis();      
       
this       .closed       .set(       false);      
       
this       .active       .set(       true);      
       
//        Initialize any placeholder property sources in the context environment
       
//       空实现
       

       initPropertySources();
      
       
//        Validate that all properties marked as required are resolvable
       
//        see ConfigurablePropertyResolver#setRequiredProperties
       
.validateRequiredProperties();      
       
//        Allow for the collection of early ApplicationEvents,
       
//        to be published once the multicaster is available...
       
this       .earlyApplicationEvents        =        new        LinkedHashSet<       ApplicationEvent       >();      
       

       }


属性校验


AbstractEnvironment.validateRequiredProperties:


@Override        public         void         validateRequiredProperties() throws         MissingRequiredPropertiesException         {
        
    this        .        propertyResolver        .        validateRequiredProperties();
        
}
      
AbstractPropertyResolver.validateRequiredProperties:
      
@Override        public         void         validateRequiredProperties() {
        
MissingRequiredPropertiesException         ex         =         new         MissingRequiredPropertiesException        ();
        
for         (        String         key         :         this        .        requiredProperties) {
        
    if         (        this        .        getProperty(key)         ==         null        ) {
        
        ex        .        addMissingRequiredProperty(key);
        
      }
        
    }
        
    if         (        !         ex        .        getMissingRequiredProperties()        .        isEmpty()) {
        
        throw         ex;
        
    }
        
}



spring源码解析---spring-core(一)_构造器_26


requiredProperties是通过setRequiredProperties方法设置的,保存在一个set里面,默认是空的,也就是不需要校验任何属性。



spring源码解析---spring-core(一)_spring_27

作者说是list集合里,实际是错的,当然也许是版本不同而已。

 


 


 


 


BeanFactory创建


      在refresh的这个方法里面


  

ConfigurableListableBeanFactory beanFactory = this.      obtainFreshBeanFactory      ();//下面会讲到这个
      
         this.prepareBeanFactory(beanFactory);

 


由obtainFreshBeanFactory调用AbstractRefreshableApplicationContext.refreshBeanFactory:(见下图)



spring源码解析---spring-core(一)_java_28



spring源码解析---spring-core(一)_spring_29


(这部分与作者源码一致)


 


BeanFactory接口


此接口实际上就是Bean容器,其继承体系:


 



spring源码解析---spring-core(一)_java_30


BeanFactory定制


AbstractRefreshableApplicationContext.customizeBeanFactory方法用于给子类提供一个自由配置的机会,默认实现:
     
protected        void        customizeBeanFactory(       DefaultListableBeanFactory        beanFactory) {
       
if        (       this       .       allowBeanDefinitionOverriding        !=        null       ) {
       
//       默认false,不允许覆盖
       
beanFactory       .       setAllowBeanDefinitionOverriding(       this       .       allowBeanDefinitionOverriding);
       
}
       
if        (       this       .       allowCircularReferences        !=        null       ) {
       
//       默认false,不允许循环引用
       
beanFactory       .       setAllowCircularReferences(       this       .       allowCircularReferences);
       
}
       
}


Bean加载


AbstractXmlApplicationContext.loadBeanDefinitions,这个便是核心的bean加载了:


@Override       protected        void        loadBeanDefinitions
       (
       DefaultListableBeanFactory 
       beanFactory) {
       
//        Create a new XmlBeanDefinitionReader for the given BeanFactory.
       
XmlBeanDefinitionReader        beanDefinitionReader        =        new        XmlBeanDefinitionReader       (beanFactory);
       
//        Configure the bean definition reader with this context's
       
//        resource loading environment.
       
beanDefinitionReader       .       setEnvironment(       this       .       getEnvironment());
       
beanDefinitionReader       .       setResourceLoader(       this       );
       
beanDefinitionReader       .       setEntityResolver(       new        ResourceEntityResolver
       (
       this
       ));// 
       为Bean读取器设置SAX xml解析器,
       下面会说到这个 
       
//        Allow a subclass to provide custom initialization of the reader,
       
//        then proceed with actually loading the bean definitions.
       
//       默认空实现
       
initBeanDefinitionReader(beanDefinitionReader);
       
loadBeanDefinitions(beanDefinitionReader);
       
}


EntityResolver


此处只说明用到的部分继承体系:



spring源码解析---spring-core(一)_spring_31

spring源码解析---spring-core(一)_构造器_32


 


EntityResolver 接口在org.xml.sax中定义。 DelegatingEntityResolver 用于schema和dtd的解析。


 


BeanDefinitionReader


继承体系:


 



spring源码解析---spring-core(一)_xml_33


 



spring源码解析---spring-core(一)_xml_34


路径解析(Ant)


protected       void       loadBeanDefinitions(      XmlBeanDefinitionReader       reader) {
      
Resource      [] configResources       =       getConfigResources();
      
if       (configResources       !=       null      ) {
      
reader      .      loadBeanDefinitions(configResources);
      
}
      
String      [] configLocations       =       getConfigLocations();
      
//      here
      
if       (configLocations       !=       null      ) {
      
reader      .      loadBeanDefinitions(configLocations);
      
}
      
}


AbstractBeanDefinitionReader.loadBeanDefinitions:



spring源码解析---spring-core(一)_spring_35



spring源码解析---spring-core(一)_构造器_36


下面作者这个肯定是不对的,因为调用了方法一样但参数列表不一样,实际是重载的 loadBeanDefinitions方法 ,上图两个是4.1.1的方法内容,与作者的版本不同。故贴出来。 


4.1.1版本与这个稍微有些不同


@Override     public      int loadBeanDefinitions(     String     .     .. locations) throws      BeanDefinitionStoreException
     
Assert     .notNull(locations,      "     Location array must not be null     ");    
     
int counter      =      0;    
     
for (     String location      :
     
+=
     

     }
    
     
return
     

     }



spring源码解析---spring-core(一)_xml_37


之后调用:


//第二个参数为空
     
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
     
    ResourceLoader resourceLoader = this.getResourceLoader();
     
    if (resourceLoader == null) {
     
        throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
     
    } else {
     
        int loadCount;
     
        if (!(resourceLoader instanceof ResourcePatternResolver)) {
     
            Resource resource =      resourceLoader.getResource
     (location);
     
            loadCount = this.loadBeanDefinitions((Resource)resource);
     
            if (actualResources != null) {
     
                actualResources.add(resource);
     
            }
     

      
    
     
            if (this.logger.isDebugEnabled()) {
     
                this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
     
            }
     

      
    
     
            return loadCount;
     
        } else {
     
            try {
     
                Resource[] resources = ((ResourcePatternResolver)resourceLoader).     getResources
     (location);
     
                loadCount = this.loadBeanDefinitions(resources);
     
                if (actualResources != null) {
     
                    Resource[] var6 = resources;
     
                    int var7 = resources.length;
     

      
    
     
                    for(int var8 = 0; var8 < var7; ++var8) {
     
                        Resource resource = var6[var8];
     
                        actualResources.add(resource);
     
                    }
     
                }
     

      
    
     
                if (this.logger.isDebugEnabled()) {
     
                    this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
     
                }
     

      
    
     
                return loadCount;
     
            } catch (IOException var10) {
     
                throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
     
            }
     
        }
     
    }
     
}


 


getResources(作者写成 getResource,一字之差缪之千里 ), 在AbstractApplicationContext. getResources :


@Override
       
public        Resource       [] getResources(       String        locationPattern) throws        IOException        {
       
//       构造器中初始化,PathMatchingResourcePatternResolver对象
       
return        this       .       resourcePatternResolver       .       getResources(locationPattern);
       
}


 



spring源码解析---spring-core(一)_spring_38



spring源码解析---spring-core(一)_构造器_39



spring源码解析---spring-core(一)_xml_40


进入第二个方法,因为第一个是掉本类的方法。


public        Resource[] getResources(String locationPattern)        throws        IOException {
       
//如果是ResourcePatternResolver
       
return this       .resourceLoader        instanceof        ResourcePatternResolver ? ((ResourcePatternResolver)       this       .resourceLoader).getResources(locationPattern) :        super       .getResources(locationPattern)       ;
       
}
     
PathMatchingResourcePatternResolver是ResourceLoader继承体系的一部分。
     
public        Resource[] getResources(String locationPattern)        throws        IOException {
       
    Assert.notNull(locationPattern       ,        "Location pattern must not be null"       )       ;
       
if        (locationPattern.startsWith(       "classpath*:"       )) {
       
    //       matcher是一个AntPathMatcher对象
       
        return this       .getPathMatcher().isPattern(locationPattern.substring(       "classpath*:"       .length())) ?        this       .findPathMatchingResources(locationPattern) :                                                              this       .findAllClassPathResources(locationPattern.substring(       "classpath*:"       .length()))       ;
       
}        else        {
       
       int        prefixEnd = locationPattern.indexOf(       ":"       ) +        1       ;
       
       return this       .getPathMatcher().       isPattern
       (locationPattern.substring(
       prefixEnd
       )) ? 
       this
       .findPathMatchingResources(locationPattern) : 
       new 
       Resource[]
       
      {       this       .getResourceLoader().getResource(locationPattern)}       ;
       
    }
       
}


isPattern:



spring源码解析---spring-core(一)_java_41


注:本来以为是数字 ,后面才发现ASCII代表的数字:详情可查 https://baike.baidu.com/item/ASCII/309296?fr=aladdin



spring源码解析---spring-core(一)_java_42

十进制指的是42


spring源码解析---spring-core(一)_构造器_43


也经过测试发现是根据十进制的ASCII码参与运算的。



spring源码解析---spring-core(一)_构造器_44


 


 



spring源码解析---spring-core(一)_java_45


  也就是可以这么写:


new     ClassPathXmlApplicationContext    (    "    con*.xml    "    );


更多的例子



spring源码解析---spring-core(一)_java_46


具体怎么解析ant风格的就不写了。


 


配置文件加载


入口方法在AbstractBeanDefinitionReader:



spring源码解析---spring-core(一)_构造器_47


//     加载     Resource     [] resources      =      ((     ResourcePatternResolver     ) resourceLoader)     .     getResources(location);
     
//     解析     int      loadCount      =      loadBeanDefinitions(resources);


最终逐个调用XmlBeanDefinitionReader的loadBeanDefinitions方法:



spring源码解析---spring-core(一)_构造器_48


Resource是代表一种资源的接口,其类图:


 



spring源码解析---spring-core(一)_构造器_49


 


 


EncodedResource扮演的其实是一个装饰器的模式,为InputStreamSource添加了字符编码(虽然默认为null)。这样为我们自定义xml配置文件的编码方式提供了机会。


之后关键的源码只有两三行:(这个是4.1.1版本中的源码,关键部分为标红的地方)


public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
   
    

        Assert.notNull(encodedResource, "EncodedResource must not be null");
   
    

        if (this.logger.isInfoEnabled()) {
   
    

        this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
   
    

        }
   
    

     
   
    

        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
   
    

        if (currentResources == null) {
   
    

        currentResources = new HashSet(4);
   
    

        this.resourcesCurrentlyBeingLoaded.set(currentResources);
   
    

        }
   
    

     
   
    

        if (!((Set)currentResources).add(encodedResource)) {
   
    

            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
   
    

        } else {
   
    

            int var5;
   
    

        try {
   
    
InputStream inputStream = encodedResource.getResource().getInputStream()
    ;
    

        try {
   
    
InputSource inputSource =     new     InputSource(inputStream)
    ;
    

        if (encodedResource.getEncoding() != null) {
   
    

            inputSource.setEncoding(encodedResource.getEncoding());
   
    

        }
   
    

     
   
    
var5 =     this
    .doLoadBeanDefinitions(inputSource
    ,     encodedResource.getResource())
    ;
    

        } finally {
   
    

           inputStream.close();
   
    

            }
   
    

        } catch (IOException var15) {
   
    

            throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
   
    

        } finally {
   
    

            ((Set)currentResources).remove(encodedResource);
   
    

        if (((Set)currentResources).isEmpty()) {
   
    

            this.resourcesCurrentlyBeingLoaded.remove();
   
    

            }
   
    

        }
   
    

            return var5;
   
    

        }
   
    

    }


spring源码解析---spring-core(一)_spring_50

其实也差不多。

InputSource是org.xml.sax的类。


doLoadBeanDefinitions:


protected    int    doLoadBeanDefinitions(   InputSource    inputSource,    Resource    resource) {
   
Document    doc    =    doLoadDocument(inputSource, resource);//下面先讲讲这部分 $   doLoadDocument   $ 加载document
   
return    registerBeanDefinitions(doc, resource);//在说说这部分$   registerBeanDefinitions   $  主要是注册bean
   
}   (4.1.1版本有些不同,主要在抛出异常方面)
  
(  $  doLoadDocument  $  )doLoadDocument:
  
protected    Document    doLoadDocument(   InputSource    inputSource,    Resource    resource) {
   
return    this   .   documentLoader   .   loadDocument
   (inputSource, 
   getEntityResolver
   (), 
   this
   .
   errorHandler,
   
getValidationModeForResource(resource), isNamespaceAware());
   
//loadDocument方法实际调用的是DefaultDocumentLoader里面的loadDocument方法 #DefaultDocumentLoader.loadDocument
   
}



spring源码解析---spring-core(一)_spring_51


实际这个documentLoader就是 DefaultDocumentLoader . 此类是DocumentLoader接口的唯一实现。 getEntityResolver 方法返回ResourceEntityResolver,上面说过了。errorHandler是一个SimpleSaxErrorHandler对象。


 



spring源码解析---spring-core(一)_xml_52



spring源码解析---spring-core(一)_java_53


校验模型 其实就是确定xml文件使用xsd方式还是dtd方式来校验,忘了的话左转度娘。Spring会通过读取xml文件的方式判断应该采用哪种。


NamespaceAware 默认false,因为默认配置了校验为true。(其实这个 默认校验 为true我还没找到)



spring源码解析---spring-core(一)_spring_54


 


DefaultDocumentLoader.loadDocument:


@Override    public     Document     loadDocument(    InputSource     inputSource,     EntityResolver     entityResolver,
    
ErrorHandler     errorHandler,     int     validationMode,     boolean     namespaceAware) {
    
//    这里就是老套路了,可以看出,Spring还是使用了dom的方式解析,即一次全部load到内存
    
DocumentBuilderFactory     factory     =     createDocumentBuilderFactory(validationMode, namespaceAware);
    
DocumentBuilder     builder     =     createDocumentBuilder(factory, entityResolver, errorHandler);
    
return     builder    .    parse(inputSource);
    
}


createDocumentBuilderFactory比较有意思:



spring源码解析---spring-core(一)_构造器_55


如上图所示,4.1.1版本的是这样,我跟确信下面的版本更成熟,因为很多地方是常量控制,4.1.1都是写死的常量。


 


protected   DocumentBuilderFactory   createDocumentBuilderFactory(  int   validationMode,   boolean   namespaceAware{
  
    DocumentBuilderFactory   factory   =   DocumentBuilderFactory  .  newInstance();
  
    factory  .  setNamespaceAware(namespaceAware);
  
    if   (validationMode   !=   XmlValidationModeDetector  .  VALIDATION_NONE  ) {
  
        //  此方法设为true仅对dtd有效,xsd(schema)无效
  
        factory  .  setValidating(  true  );
  
    if   (validationMode   ==   XmlValidationModeDetector  .  VALIDATION_XSD  ) {
  
            //   Enforce namespace aware for XSD...
  
            //  开启xsd(schema)支持
  
        factory  .  setNamespaceAware(  true  );
  
        //  这个也是Java支持Schema的套路,可以问度娘
  
        factory  .  setAttribute(  SCHEMA_LANGUAGE_ATTRIBUTE  ,   XSD_SCHEMA_LANGUAGE  );
  
    }
  
}
  
return   factory;
  
}


 


 

Bean解析(这部分放在 spring源码解析---spring-core(二)

 

 

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
OFqMI21Mpnzn