Spring IOC 源码解析(一)

Spring IOC 源码解析(一)

 

 

1、简介

在开始之前我们先来看看Bean的生命周期

IOC 核心类简介:
  1. ClassPathXmlApplicationContext:从程序内加载配置文件来启动Spring。
  2. FileSystemXmlApplicationContext:从文件系统内加载配置文件来启动Spring。
  3. AnnotationConfigApplicationContext:从java注解式配置的配置文件来启动Spring。
本文基于Spring5 中最经典的 ClassPathXmlApplicationContext 类来介绍:
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.0.RELEASE</version>
</dependency>    

 

2. ClassPathXmlApplicationContext 案例

2.1、然后写一个简单的接口和实现类

public interface IOCService {
    public String hello();
}
public class IOCServiceImpl implements IOCService {
    @Override
    public String hello() {
        return "Hello,IOC";
    }
}

2.2、新建一个application-ioc.xml

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

    <bean id="iocservice" class="com.dw.study.service.impl.IOCServiceImpl"/>
</beans>

2.3、启动Spring

public class IocTest {
    public static void main (String args[]){
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application-ioc.xml");
        IOCService iocService=context.getBean(IOCService.class);
        System.out.println(iocService.hello());
    }
}

 

3、源码分析
ClassPathXmlApplicationContext 类图关系:

 

看一下这个类的源代码
/**
 * 独立的 XML 应用程序上下文,从类路径中获取上下文定义文件,将普通路径解释为包含包路径的类路径资源名称(例如“mypackage/myresource.txt”)。
 * 配置位置默认值可以通过 覆盖 getConfigLocations,配置位置可以表示具体文件,如“/myfiles/context.xml”或 Ant 风格的模式,如“/myfiles/*-context.xml”
 * 如果有多个配置位置,后面的 Bean 定义将覆盖在早期加载的文件中定义的 Bean。可以利用这一点,通过额外的 XML 文件故意覆盖某些 Bean 定义。
 */
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {

    @Nullable
    private Resource[] configResources;

    /**
     * 使用给定的父级创建新的 ClassPathXmlApplicationContext
     *
     * @param configLocations 配置文件地址
     * @param refresh 是否自动刷新上下文、加载所有 Bean 定义和创建所有单例。
     * @param parent 父容器
     */
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
            throws BeansException {
        super(parent);
        // 设置配置文件路径
        setConfigLocations(configLocations);
        // 刷新容器, 加载beans(重点)
        if (refresh) {
            refresh();
        }
    }

    @Override
    @Nullable
    protected Resource[] getConfigResources() {
        return this.configResources;
    }
}

 

跟着setConfigLocations方法一直往下走
// 设置此应用程序上下文的配置位置
public void setConfigLocations(@Nullable 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++) {
            // 解析给定路径,如有必要,将占位符"${}"替换为相应的环境属性值。比如:configLocation: "${spring}:application-ioc.xml"
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }

 

resolvePath:

/** 解析给定路径,将占位符"${}"替换为相应的环境属性值。
 *  比如可以这么写: new ClassPathXmlApplicationContext("${spring}:application-ioc.xml");${spring}:就是需要被解析的。
 * 参数:路径 – 原始文件路径
 * 返回:解析的文件路径
*/
protected String resolvePath(String path) { return getEnvironment().resolveRequiredPlaceholders(path); } getEnvironment()方法来自于ConfigurableApplicationContext接口,源码很简单,如果为空就调用createEnvironment创建一个。 public ConfigurableEnvironment getEnvironment() { if (this.environment == null) { this.environment = createEnvironment(); } return this.environment; } protected ConfigurableEnvironment createEnvironment() { return new StandardEnvironment(); }

看一下 StandardEnvironment 这个类的继承图 

      这个接口比较重要的就是两部分内容了,一个是设置Spring的环境就是我们经常用的spring.profile配置,另外就是系统资源Property。StandardEnvironment类中的customizePropertySources方法就会往资源列表中添加Java进程中 JVM的变量 和 系统的环境变量。注意这个方法重写了AbstractEnvironment 的方法,在创建StanderdEnvironment时, 会自动调用父类AbstractEnvironment的构造方法,customizePropertySources(); 方法就会被执行。

  protected void customizePropertySources(MutablePropertySources propertySources) {
        propertySources.addLast(new MapPropertySource("systemProperties", this.getSystemProperties()));
        propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
    }

处理占位符: 

再次回到 resolvePath方法, AbstractEnvironment.resolveRequiredPlaceholders:

public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
        if (this.strictHelper == null) {
            this.strictHelper = this.createPlaceholderHelper(false);
        }
        // 路径解析
        return this.doResolvePlaceholders(text, this.strictHelper);
    }

      最终调用的 PropertyPlaceholderHelper 类的 parseStringValue() 方法解析,这个方法主要就是处理所有使用"${}"方式的占位符。eg: ${spring}:config.xml", 注意,classpath:XXX这种写法的classpath前缀到目前为止还没有被处理。

 protected String parseStringValue(String value, PropertyPlaceholderHelper.PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
        StringBuilder result = new StringBuilder(value);
        int startIndex = value.indexOf(this.placeholderPrefix);

        while(startIndex != -1) {
            int endIndex = this.findPlaceholderEndIndex(result, startIndex);
            if (endIndex != -1) {
                String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
                String originalPlaceholder = placeholder;
                if (!visitedPlaceholders.add(placeholder)) {
                    throw new IllegalArgumentException("Circular placeholder reference '" + placeholder + "' in property definitions");
                }

                placeholder = this.parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
                String propVal = placeholderResolver.resolvePlaceholder(placeholder);
                if (propVal == null && this.valueSeparator != null) {
                    int separatorIndex = placeholder.indexOf(this.valueSeparator);
                    if (separatorIndex != -1) {
                        String actualPlaceholder = placeholder.substring(0, separatorIndex);
                        String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
                        propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
                        if (propVal == null) {
                            propVal = defaultValue;
                        }
                    }
                }

                if (propVal != null) {
                    propVal = this.parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
                    result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
                    if (logger.isTraceEnabled()) {
                        logger.trace("Resolved placeholder '" + placeholder + "'");
                    }

                    startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
                } else {
                    if (!this.ignoreUnresolvablePlaceholders) {
                        throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "' in value \"" + value + "\"");
                    }

                    startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
                }

                visitedPlaceholders.remove(originalPlaceholder);
            } else {
                startIndex = -1;
            }
        }

        return result.toString();
    }

 

refresh()

配置文件名称解析完毕后,就到了最关键的一步refresh方法。这个方法, 接下来会用超级长的篇幅来解析这个方法, 先看一下这个方法里大致内容

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            /**
             * 前戏,做容器刷新前的准备工作
             * 1、设置容器的启动时间
             * 2、设置活跃状态为true
             * 3、设置关闭状态为false
             * 4、获取Environment对象,并加载当前系统的属性值到Environment对象中
             * 5、准备监听器和事件的集合对象,默认为空的集合
             */
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            // 创建容器对象:DefaultListableBeanFactory
            // 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            // beanFactory的准备工作,对各种属性进行填充
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                // 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                // 调用各种beanFactory处理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 注册bean处理器,这里只是注册功能,真正调用的是getBean方法
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                // 为上下文初始化message源,即不同语言的消息体,国际化处理,在springmvc的时候通过国际化的代码重点讲
                initMessageSource();

                // Initialize event multicaster for this context.
                // 初始化事件监听多路广播器
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                // 留给子类来初始化其他的bean
                onRefresh();

                // Check for listener beans and register them.
                // 在所有注册的bean中查找listener bean,注册到消息广播器中
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                // 初始化剩下的单实例(非懒加载的)
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                // 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                // 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件bean
                destroyBeans();

                // Reset 'active' flag.
                // 重置active标志
                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();
            }
        }
    }
}

是不是看着有点懵,不要着急,一行一行往下看,不研究明白誓不罢休。

  1. synchronized 为了避免refresh() 还没结束,再次发起启动或者销毁容器引起的冲突。

  2. prepareRefresh() 做一些准备工作,记录容器的启动时间、标记“已启动”状态、检查环境变量等。

protected void prepareRefresh() {
        // 记录容器启动时间、标记已启动
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);

        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }

        // Initialize any placeholder property sources in the context environment
        initPropertySources();

        // Validate that all properties marked as required are resolvable
        // see ConfigurablePropertyResolver#setRequiredProperties
        getEnvironment().validateRequiredProperties();

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

其中检查环境变量是核心方法,简单来说就是如果存在需要的环境变量的value 为空的时候就抛异常,然后停止启动Spring。

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

      基于这个特性我们可以做一些扩展,提前在集合requiredProperties中 放入我们这个项目必须存在的一些环境变量。 假说我们的生产环境数据库地址、用户名和密码都是使用环境变量的方式注入进去来代替测试环境的配置,那么就可以在这里添加这个校验,在程序刚启动的时候就能发现问题。

 

obtainFreshBeanFactory() 

乍一看这个方法也没几行代码,但是这个方法负责了BeanFactory的初始化、Bean的加载和注册等事件

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

先看refreshBeanFactory() 对此上下文的基础 Bean 工厂执行实际刷新,关闭以前的 Bean 工厂(如果有),并为上下文生命周期的下一阶段初始化新的 Bean 工厂。

protected final void refreshBeanFactory() throws BeansException {
// 判断当前ApplicationContext是否存在BeanFactory,如果存在的话就销毁所有 Bean,关闭 BeanFactory
// 注意,一个应用可以存在多个BeanFactory,这里判断的是当前ApplicationContext是否存在BeanFactory
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
        // 初始化DefaultListableBeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
             // 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
            customizeBeanFactory(beanFactory);
            // 加载 Bean 到 BeanFactory 中
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

这里一开始就实例化了一个DefaultListableBeanFactory,先看一下这个类的继承关系

 可以看到这个哥们的背景相当大,所有关于容器的接口、抽象类他都继承了。 是BeanFactory的默认实现。

 

BeanDefinition

在看loadBeanDefinitions()这个方法之前,就必须了解一个东西了。那就是:BeanDefinition 。我们知道BeanFactory是一个Bean容器,而BeanDefinition就是Bean的一 种形式(它里面包含了Bean指向的类、是否单例、是否懒加载、Bean的依赖关系等相关的属性)。BeanFactory中就是保存的BeanDefinition。 再来看看BeanDefinition的接口定义:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

// Bean的生命周期,默认只提供sington和prototype两种,在WebApplicationContext中还会有request, session, globalSession, application, websocket 等
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

// 设置父Bean
void setParentName(String parentName);

// 获取父Bean
String getParentName();

// 设置Bean的类名称
void setBeanClassName(String beanClassName);

// 获取Bean的类名称
String getBeanClassName();

// 设置bean的scope
void setScope(String scope);

String getScope();

// 设置是否懒加载
void setLazyInit(boolean lazyInit);

boolean isLazyInit();

// 设置该Bean依赖的所有Bean
void setDependsOn(String... dependsOn);

// 返回该Bean的所有依赖
String[] getDependsOn();

// 设置该Bean是否可以注入到其他Bean中
void setAutowireCandidate(boolean autowireCandidate);

// 该Bean是否可以注入到其他Bean中
boolean isAutowireCandidate();

// 同一接口的多个实现,如果不指定名字的话,Spring会优先选择设置primary为true的bean
void setPrimary(boolean primary);

// 是否是primary的
boolean isPrimary();

// 指定工厂名称
void setFactoryBeanName(String factoryBeanName);
// 获取工厂名称
String getFactoryBeanName();
// 指定工厂类中的工厂方法名称
void setFactoryMethodName(String factoryMethodName);
// 获取工厂类中的工厂方法名称
String getFactoryMethodName();

// 构造器参数
ConstructorArgumentValues getConstructorArgumentValues();

// Bean 中的属性值,后面给 bean 注入属性值的时候会说到
MutablePropertyValues getPropertyValues();

// 是否 singleton
boolean isSingleton();

// 是否 prototype
boolean isPrototype();

// 如果这个 Bean 是被设置为 abstract,那么不能实例化,常用于作为 父bean 用于继承
boolean isAbstract();

int getRole();
String getDescription();
String getResourceDescription();
BeanDefinition getOriginatingBeanDefinition();
}

 

读取XML配置文件

现在可以看loadBeanDefinitions()方法了,这个方法一顿重载,会根据xml文件的配置,加载各个 Bean,然后放到 BeanFactory 中。

  @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 创建一个XML 方式定义的 bean 的 一个读取类
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        // 配置读取xml bean 定义需要使用的资源
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
        // 接着往下看
        loadBeanDefinitions(beanDefinitionReader);
    }
    
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        // 看有没有系统指定的配置文件
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        // 加载我们最开始传入的`classpath:application-ioc.xml`
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }
    
    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int counter = 0;
        // 循环,处理所有配置文件,咱们这里就传了一个
        for (Resource resource : resources) {
        // 继续往下看
        counter += loadBeanDefinitions(resource);
        }
        // 最后返回加载的所有BeanDefinition的数量
        return counter;
    }
    
    @Override
    public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        Assert.notNull(locations, "Location array must not be null");
        int counter = 0;
           // 循环,处理所有配置文件,咱们这里就传了一个
        for (String location : locations) {
        // 继续往下看
            counter += loadBeanDefinitions(location);
        }
         // 最后返回加载的所有BeanDefinition的数量
        return counter;
    }

离解析越来越近了, 我们跟着loadBeanDefinitions()方法往下走,最终会进入类XmlBeanDefinitionReader,这是因为我们这里要解析的配置文件是XML。如果我们使用Java类配置或者是Groovy的话就是另外的类了。看一下这个类继承图: 

 接着看

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isInfoEnabled()) {
            logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }
        // 当前已经被加载的xml资源
        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                // 解析XML bean
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }

下面是分为两步

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
      try {
      // 1、将 xml 文件转换为 Document 对象
      Document doc = doLoadDocument(inputSource, resource);
      // 2、根据Document对象注册Bean
      return registerBeanDefinitions(doc, resource);
      }
     ...
}

xml文件解析成Document就不详细展开了,具体的可以参考:XML文件的解析,接着往下看注册Bean: 


public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   //构建读取Document的工具类
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   //获取已注册的bean数量
   int countBefore = getRegistry().getBeanDefinitionCount();
   // 在这接着往下看
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   // 返回本次注册的bean 的数量
   return getRegistry().getBeanDefinitionCount() - countBefore;
}

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); //获取Document的根节点 Element root = doc.getDocumentElement(); //继续往下 doRegisterBeanDefinitions(root); }

真正解析方法:

protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
        // 获取 <beans ... profile="***" /> 中的 profile参数与当前环境是否匹配,如果不匹配则不再进行解析
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }
        // 前置扩展点
        preProcessXml(root);
        // 解析XML的核心方法
        parseBeanDefinitions(root, this.delegate);
        // 后置扩展点
        postProcessXml(root);
        this.delegate = parent;
    }

改变bean定义的扩展点 preProcessXml和postProcessXml着两个办法是留给我们实现DefaultBeanDefinitionDocumentReader方法后自定义实现的。

解析XML 接下来,看核心解析方法 parseBeanDefinitions()

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        // 判断是否是默认的命名空间(默认Spring的命名空间)涉及到的就四个标签 <import />、<alias />、<bean /> 和 <beans />
        if (delegate.isDefaultNamespace(root)) {
          // 获取所有子节点
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                     // 处理Spring 默认的标签
                        parseDefaultElement(ele, delegate);
                    } else {
                     // 解析其他 namespace 的元素
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
         // 解析其他 namespace 的元素
            delegate.parseCustomElement(root);
        }
    }

接着往下看这些标签的处理方式 , Spring 的标签处理:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
    // 处理 <import /> 标签
    importBeanDefinitionResource(ele);
    }
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
    // 处理 <alias /> 标签
    // <alias name="fromName" alias="toName"/>
    processAliasRegistration(ele);
    }
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
    // 处理 <bean /> 标签定义
    processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
    // 处理 <beans /> 标签
    doRegisterBeanDefinitions(ele);
    }
}

简单看一下bean 标签的处理方式

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 将 xml文档中的bean标签解析成 BeanDefinition 对象
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
       bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    try {
       // 最终往Map容器中添加bean的定义
       BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    } catch (BeanDefinitionStoreException ex) {
       getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
    }
    // Send registration event.
    getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

 

先从第一行往下看

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    String id = ele.getAttribute(ID_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    List<String> aliases = new ArrayList<String>();
    // 将 name 属性的定义按照 “逗号、分号、空格” 切分,形成一个 别名列表数组,
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }

    String beanName = id;
    // 如果没有指定id, 那么用别名列表的第一个名字作为beanName
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
         beanName = aliases.remove(0);
        if (logger.isDebugEnabled()) {
        logger.debug("No XML 'id' specified - using '" + beanName +
        "' as bean name and " + aliases + " as aliases");
        }
    }
     // 验证beanName 的唯一性
    if (containingBean == null) {
       checkNameUniqueness(beanName, aliases, ele);
    }

// 根据 <bean ...>...</bean> 中的配置创建 BeanDefinition,然后把配置中的信息都设置到实例中,
// 这行执行完毕,一个 BeanDefinition 实例就出来了。等下接着往下看
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);

// <bean /> 标签完成
if (beanDefinition != null) {
// 如果没有设置 id 和 name,那么此时的 beanName 就会为 null
   if (!StringUtils.hasText(beanName)) {
        try {
            if (containingBean != null) {
            beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
            } else {
               beanName = this.readerContext.generateBeanName(beanDefinition);
               String beanClassName = beanDefinition.getBeanClassName();
               if (beanClassName != null &&
                     beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                     !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                  // 把 beanClassName 设置为 Bean 的别名
                  aliases.add(beanClassName);
               }
            }
            if (logger.isDebugEnabled()) {
               logger.debug("Neither XML 'id' nor 'name' specified - " +
                     "using generated bean name [" + beanName + "]");
            }
         }
         catch (Exception ex) {
            error(ex.getMessage(), ele);
            return null;
         }
      }
      String[] aliasesArray = StringUtils.toStringArray(aliases);
      // 返回 BeanDefinitionHolder
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}

return null;
}

创建BeanDefinition : 接着是最重要的地方,如何根据xml配置创建 BeanDefinition 实例。

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
    this.parseState.push(new BeanEntry(beanName));
    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
    try {
    
        String parent = null;      
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
             parent = ele.getAttribute(PARENT_ATTRIBUTE);
          }
          // 创建 BeanDefinition,然后设置类信息
          AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    
          // 设置 BeanDefinition 的一堆属性,这些属性定义在 AbstractBeanDefinition 中
          parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
          bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    
          /**
           * 下面的一堆是解析 <bean>......</bean> 内部的子元素,
           * 解析出来以后的信息都放到 bd 的属性中
           */
    
          // 解析 <meta />
          parseMetaElements(ele, bd);
          // 解析 <lookup-method />
          parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
          // 解析 <replaced-method />
          parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
          // 解析 <constructor-arg />
          parseConstructorArgElements(ele, bd);
          // 解析 <property />
          parsePropertyElements(ele, bd);
          // 解析 <qualifier />
          parseQualifierElements(ele, bd);
    
          bd.setResource(this.readerContext.getResource());
          bd.setSource(extractSource(ele));
    
          return bd;
    }
    catch (ClassNotFoundException ex) {
    error("Bean class [" + className + "] not found", ele, ex);
    }
    catch (NoClassDefFoundError err) {
    error("Class that bean class [" + className + "] depends on not found", ele, err);
    }
    catch (Throwable ex) {
    error("Unexpected failure during bean definition parsing", ele, ex);
    }
    finally {
    this.parseState.pop();
    }
    
    return null;
}

终于终于这么长时间把这个BeanDefinition搞出来了,太不容易了!!! 接着回到刚才的代码

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 上面说的一堆
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        // 如果有自定义属性的话,进行相应的解析
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    try {
        // 注册BeanDefinition
        BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    }
    catch (BeanDefinitionStoreException ex) {
        getReaderContext().error("Failed to register bean definition with name '" +
        bdHolder.getBeanName() + "'", ele, ex);
    }
    // 注册完成后,发送事件
    getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

 

Bean的注册 这次看注册beanDefinition的实现

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
// 注册这个 Bean, 下面接着看
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

// 如果配置有别名的话,也要根据别名全部注册一遍
String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

又是一个长方法。。。

 @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            } catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(...);
            }
        }

        BeanDefinition oldBeanDefinition;

        // 所有的 Bean 注册后都会被放入到这个beanDefinitionMap 中,查看是否已存在这个bean
        oldBeanDefinition = this.beanDefinitionMap.get(beanName);

       // 处理重复名称的 Bean 定义的情况
        if (oldBeanDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
            // 如果不允许覆盖的话,抛异常
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                                "': There is already [" + oldBeanDefinition + "] bound.");
            } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
           // 用框架定义的 Bean 覆盖用户自定义的 Bean
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            } else if (!beanDefinition.equals(oldBeanDefinition)) {
             // 用新的 Bean 覆盖旧的 Bean
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            } else {
              // log...用同等的 Bean 覆盖旧的 Bean
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            // 覆盖
            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
           // 判断是否已经有其他的 Bean 开始初始化了.注意,"注册Bean" 这个动作结束,Bean 依然还没有初始化 在 Spring 容器启动的最后,会 预初始化 所有的 singleton beans
            if (hasBeanCreationStarted()) {
                   // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            } else {
                // 将 BeanDefinition 放到这个 map 中,这个 map 保存了所有的 BeanDefinition
                this.beanDefinitionMap.put(beanName, beanDefinition);
                // 这是个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
                this.beanDefinitionNames.add(beanName);
                // 这是个 LinkedHashSet,代表的是手动注册的 singleton bean,
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

到这里已经初始化了 Bean 容器,的配置也相应的转换为了一个个BeanDefinition,然后注册了所有的BeanDefinition到beanDefinitionMap。

 

现在回到最开始的refresh()方法中的 prepareBeanFactory()

这个方法主要会设置BeanFactory的类加载器、添加几个 BeanPostProcessor、手动注册几个特殊的bean

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 设置为加载当前ApplicationContext类的类加载器
        beanFactory.setBeanClassLoader(getClassLoader());

        // 设置 BeanExpressionResolver
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        // 这里是Spring的又一个扩展点
        //在所有实现了Aware接口的bean在初始化的时候,这个 processor负责回调,
        // 这个我们很常用,如我们会为了获取 ApplicationContext 而 implement ApplicationContextAware
        // 注意:它不仅仅回调 ApplicationContextAware,还会负责回调 EnvironmentAware、ResourceLoaderAware 等
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        // 下面几行的意思就是,如果某个 bean 依赖于以下几个接口的实现类,在自动装配的时候忽略它们,Spring 会通过其他方式来处理这些依赖。
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

        //下面几行就是为特殊的几个 bean 赋值,如果有 bean 依赖了以下几个,会注入这边相应的值
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // 注册 事件监听器
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

        // 如果存在bean名称为loadTimeWeaver的bean则注册一个BeanPostProcessor
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // Set a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        // 如果没有定义 "environment" 这个 bean,那么 Spring 会 "手动" 注册一个
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        // 如果没有定义 "systemProperties" 这个 bean,那么 Spring 会 "手动" 注册一个
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
            // 如果没有定义 "systemEnvironment" 这个 bean,那么 Spring 会 "手动" 注册一个
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
    }
  1. postProcessBeanFactory() 这个比较简单,又是Spring的一个扩展点。 如果有Bean实现了BeanFactoryPostProcessor接口, 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事。

  2. invokeBeanFactoryPostProcessors() 调用BeanFactoryPostProcessor各个实现类的postProcessBeanFactory(factory) 方法。

  3. registerBeanPostProcessors() 又是一个扩展点 注册 BeanPostProcessor 的实现类,注意不是BeanFactoryPostProcessor 此接口有两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization分别会在Bean初始化之前和初始化之后得到执行。

  4. initMessageSource() 初始化当前 ApplicationContext 的 MessageSource,有想了解国际化的相关知识可以深入研究一下

 
 initApplicationEventMulticaster()

这个方法主要为初始化当前 ApplicationContext 的事件广播器

private void initApplicationEventMulticaster() throws BeansException {
        //如果用户配置了自定义事件广播器,就使用用户的
        if (containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME )) {
            this.applicationEventMulticaster = (ApplicationEventMulticaster)
                    getBean( APPLICATION_EVENT_MULTICASTER_BEAN_NAME ,
                            ApplicationEventMulticaster.class );
            if (logger.isInfoEnabled()) {
                logger.info("Using ApplicationEventMulticaster ["
                        + this. applicationEventMulticaster + "]" );
            }
        }else {
            //使用默认的事件广播器
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster();
            if (logger.isInfoEnabled()) {
                logger.info("Unable to locate ApplicationEventMulticaster with name '"+
                        APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                        "': using default [" + this .applicationEventMulticaster + "]");
            }
        }
    }

 

onRefresh()  又是一个扩展点,子类可以在这里来搞事情。

registerListeners() 注册事件监听器

protected void registerListeners() {
        //先添加手动set的一些监听器
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }

        //取到监听器的名称,设置到广播器
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // 如果存在早期应用事件,发布
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }

好的到这儿我们了解了BeanFactory容器的创建、配置文件的解析、BeanDefinition的注册, 后面的文章我们继续Bean的实例化。

 

posted @ 2023-07-02 14:28  邓维-java  阅读(288)  评论(0编辑  收藏  举报