深入源码分析SpringIOC(一)

IOC初始化之准备工作(定位、加载、注册)

Spring基本认识

  1. 初衷:Spring框架一开始是为了解决开发的复杂性而存在的,所以归根解底他的目标就是四个字简化开发,这四个字几乎贯穿Spring,在学习Spring的过程中会慢慢领悟这四个字的意思。同时,Spring还保证了最小侵入式编程,其中有很多地方都可以使用配置文件来配置Spring,不需要对实际代码有过多侵入,或许这里Spring的注解有一些侵入性,所以我这里用最小侵入式来描述。
  2. IOC容器:如果将Spring比作舞台,那么Bean就是舞台上的演员,舞台就是为了演员而生,Spring的存在也就是为了Bean而存在,Spring编程思想是面向Bean的(BOP),俗称万物皆为Bean。而控制反转也是相对于IOC来说的,用户将万物的控制权交给了Spring去管理(也就是IOC容器),而用户只需要在配置文件中配置Bean与Bean之间的关系,将它们联系到一起,剩余工作只需要交给Spring去完成,所以Spring也被称为“粘合剂”,Spring是框架的框架这句话一点毛病都没有。
  3. 依赖注入:谈到依赖注入,首先需要介绍Bean的作用域。
    • 单例:Spring中Bean默认作用域Singleton,如无设置Lazy-init = true的话,在IOC初始化完毕之后会初始化单例Bean,此时就会触发实例化Bean对象,以及依赖注入。此作用域为注册式单例模式,在Map中维护Bean实例做到单例效果。
    • 原型:在IOC容器初始化时不会初始化,在真正getBean方法调用时才去实例化,而且每次getBean得到的原型Bean实例都不是同一个。
    • 还有一些例如request、session之类的作用域,这里不多赘述。在取出Bean的过程中,少不了实例化Bean与依赖注入,依赖注入将Bean与Bean联系在一起,就像“注入”一样将Bean的属性(依赖项)设置到Bean实例中,依赖注入是初始化Bean属性和跟其他Bean联系起来的一个重要过程。而依赖注入有三种方式:@Autowired注解方式Set方式构造器方式

介绍几个重要的类

BeanFactory

在这里插入图片描述
Spring 对Bean的操作是典型的工厂模式,上面定义了许多不同的BeanFactory,都是具有它各种各样不同的功能的,这些BeanFactory们为操作Bean带来了极大的便利。最底层的DefaultListableBeanFactory实现了以上所有接口,我们使用的默认的BeanFactory即为此类。看起来这个结构很复杂,但其实我们只需要看这些BeanFactory接口究竟可以干些什么,就可以大概知道它的作用了。

  • BeanFactory

    public interface BeanFactory {
    
    	//对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
    	//如果需要得到工厂本身,需要转义
    	String FACTORY_BEAN_PREFIX = "&";
    
    	//根据bean的名字,获取在IOC容器中得到bean实例
    	Object getBean(String name) throws BeansException;
    
    	//根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。
    	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
    
    	Object getBean(String name, Object... args) throws BeansException;
    
    	<T> T getBean(Class<T> requiredType) throws BeansException;
    
    	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    
    	//提供对bean的检索,看看是否在IOC容器有这个名字的bean
    	boolean containsBean(String name);
    
    	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    
    	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    
    	boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
    
    
    	//得到bean实例的Class类型
    	@Nullable
    	Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    
    	//得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
    	String[] getAliases(String name);
    
    }
    
    • getBean:获取Bean实例的方法。
    • containsBean:验证IOC容器是否有某个bean的方法。
    • getType:获取bean的class类型的方法。
    • getAliases:获取bean的别名的方法。
  • ListableBeanFactory

    public interface ListableBeanFactory extends BeanFactory {
    
    	boolean containsBeanDefinition(String beanName);
    
    	int getBeanDefinitionCount();
    
    	String[] getBeanDefinitionNames();
        
    	String[] getBeanNamesForType(ResolvableType type);
    
    	String[] getBeanNamesForType(@Nullable Class<?> type);
    
    	String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
    
    	<T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
    
    	<T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
    			throws BeansException;
    
    	String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
    
    	Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
    
    	@Nullable
    	<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
    			throws NoSuchBeanDefinitionException;
    
    }
    
    • containsBeanDefinition:在IOC容器存放Bean定义的地方是否存在此Bean定义类的方法。
    • getBeanNamesForType:根据Class获取IOC容器中此类型的所有BeanName的方法。
  • AutowireCapableBeanFactory(这个BeanFactory定义了很多操作Bean的功能):

    public interface AutowireCapableBeanFactory extends BeanFactory {
    
    	int AUTOWIRE_NO = 0;
    
    	int AUTOWIRE_BY_NAME = 1;
    
    	int AUTOWIRE_BY_TYPE = 2;
    
    	int AUTOWIRE_CONSTRUCTOR = 3;
    
    	@Deprecated
    	int AUTOWIRE_AUTODETECT = 4;
    
    	<T> T createBean(Class<T> beanClass) throws BeansException;
    
    	void autowireBean(Object existingBean) throws BeansException;
    
    	Object configureBean(Object existingBean, String beanName) throws BeansException;
    
    	Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
    
    	Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
    
    	void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)
    			throws BeansException;
    
    	void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
    
    	Object initializeBean(Object existingBean, String beanName) throws BeansException;
    
    	Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
    			throws BeansException;
    
    	Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    			throws BeansException;
    
    	void destroyBean(Object existingBean);
    
    	<T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
    
    	@Nullable
    	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
    
    	@Nullable
    	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
    			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
    
    }
    
    • createBean:定义了创建Bean的方法。
    • initializeBean:初始化Bean的方法,是一个回调方法。
    • applyBeanPostProcessorsBeforeInitialization:处理Bean-init方法初始化之前的方法,是一个回调方法。(此回调与下面的回调的时机都是在Bean实例化与依赖注入之后)
    • applyBeanPostProcessorsAfterInitialization:Bean-init方法初始化之后的方法,是一个回调方法。

BeanDefinition

在这里插入图片描述
IOC容器中存放了一个描述Bean的类,这个类就是BeanDefinition,它的最底层实现就是RootBeanDefinition,在IOC容器初始化的过程中,会以各种不同方式定位资源例如读取配置文件,读取注解方式等,然后加载这些配置信息,将这些Bean信息注册进IOC容器中,而这些Bean信息Spring将其封装为一个类即为BeanDefinition

  • BeanDefinition:

    public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    
    	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
    
    	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
    
    	int ROLE_APPLICATION = 0;
    
    	int ROLE_SUPPORT = 1;
    
    	int ROLE_INFRASTRUCTURE = 2;
    
    	void setParentName(@Nullable String parentName);
    
    	@Nullable
    	String getParentName();
    
    	void setBeanClassName(@Nullable String beanClassName);
    
    	@Nullable
    	String getBeanClassName();
    
    	void setScope(@Nullable String scope);
    
    	@Nullable
    	String getScope();
    
    	void setLazyInit(boolean lazyInit);
    
    	boolean isLazyInit();
    
    	void setDependsOn(@Nullable String... dependsOn);
    
    	@Nullable
    	String[] getDependsOn();
    
    	void setAutowireCandidate(boolean autowireCandidate);
    
    	boolean isAutowireCandidate();
    
    	void setPrimary(boolean primary);
    
    	boolean isPrimary();
    
    	void setFactoryBeanName(@Nullable String factoryBeanName);
    
    	@Nullable
    	String getFactoryBeanName();
    
    	void setFactoryMethodName(@Nullable String factoryMethodName);
    
    	@Nullable
    	String getFactoryMethodName();
    
    	ConstructorArgumentValues getConstructorArgumentValues();
    
    	default boolean hasConstructorArgumentValues() {
    		return !getConstructorArgumentValues().isEmpty();
    	}
    
    	MutablePropertyValues getPropertyValues();
    
    	default boolean hasPropertyValues() {
    		return !getPropertyValues().isEmpty();
    	}
        
    	// Read-only attributes
        
    	boolean isSingleton();
    
    	boolean isPrototype();
    
    	boolean isAbstract();
    
    	int getRole();
    
    	@Nullable
    	String getDescription();
    
    	@Nullable
    	String getResourceDescription();
    
    	@Nullable
    	BeanDefinition getOriginatingBeanDefinition();
    
    }
    

    这个接口定义了大部分描述Bean信息需要用到的方法,例如:

    • isSingleton/isPrototype:定义了判断Bean作用域是否单例或原型的方法。
    • getPropertyValues:定义了获取Bean中属性值方法,在依赖注入时会用到这个方法。
    • getDependsOn:获取依赖Bean的名称列表。
    • isLazyInit:判断此Bean是否延迟加载。
    • getScope:获取Bean的作用域。

ApplicationContext

在这里插入图片描述
其中,ApplicationContext是Spring的上下文,定义了IOC容器初始化的过程,从类结构上可以看到,它也是一个BeanFactory,还是一个ResourceLoader资源加载器,同时它还是ApplicationContext,扩展了IOC容器初始化的过程,在其注册Bean时还是使用上文提到的DefaultListableBeanFactory这个BeanFactory,而ApplicationContext存在的意义就是完善(增添)了IOC容器的功能,使获取Bean更加灵活,功能更多样。

可以看到最底层有四种不同的ApplicationContext,它们各自有各自不同的方法加载Bean,从类名上也都可以看出来,AnnotationConfigWebApplicationContextXmlWebApplicationContext主要用于Web,一种是根据注解的方式加载Bean信息,一种是根据xml文件加载Bean信息。而FileSystemXmlApplicationContextClassPathXmlApplicationContext一种是从文件系统资源来加载Bean定义,一种是从路径获取加载Bean定义,其实这些ApplicationContext大同小异,他们都间接继承了AbstractApplicationContext与其子类,这两个类实现了大部分初始化IOC容器的方法,而那四种ApplicationContext区别只在读取Bean资源的方式上,与应用场景不同上,本质的IOC容器初始化原理都是相同的,所以,我们这里随便拿一种ApplicationContext做分析即可。

Spring容器(定位、加载、注册)

<beans>
	<bean id="demo" class="com.test.demo" />
</beans>
ClassPathXmlApplicationContext context = new 		ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo = context.getBean("demo");

以上短短的两行代码和一个配置文件,其底层其实做了很多很多操作,这段代码就是我们分析源码的入口。

首先看一下它的构造器做了什么事情:

public ClassPathXmlApplicationContext(
    String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
    throws BeansException {

    // 如果有父容器,先设置父容器
    super(parent);
    // 将配置路径存放在一个变量中,后面会解析这个路径的文件
    setConfigLocations(configLocations);
    if (refresh) {
        // 整个IOC容器初始化的入口方法
        refresh();
    }
}

而主要的入口方法refresh是在父类AbstractApplicationContext中实现的,在上面提到的四种ApplicationContext其实最终都会调用父类的refresh的方法,这里也就可以看出来,在初始化IOC容器的过程中它们都是一样的,都是由父类去实现,它们只负责扩展加载Bean方式的不同,Spring把它们的共性初始化IOC容器的过程都提取出来放在AbstractApplicationContext中,而子类只需负责扩展其他不同的地方,可见其面向对象的思想

@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.
        // 告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
        // 子类的refreshBeanFactory()方法启动
        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.
            // 为容器的某些子类指定特殊的BeanPost事件处理器
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            // 调用所有注册的BeanFactoryPostProcessor的Bean
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // 为BeanFactory注册BeanPost事件处理器.
            // BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            // 初始化信息源,和国际化相关.
            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.
            // 为事件传播器注册事件监听器.
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            // 初始化所有剩余的单例Bean
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            // 初始化容器的生命周期事件处理器,并发布容器的生命周期事件
            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
            destroyBeans();

            // Reset 'active' flag.
            // 取消refresh操作,重置容器的同步标识.
            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();
        }
    }
}

这个方法中,定义了初始化ApplicationContext的主要脉络(流程),在探求IOC初始化过程的定位、加载、注册只需要关注一行代码

// 告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
// 子类的refreshBeanFactory()方法启动
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

此方法完成了所有Bean的加载,并且把BeanDefinition注册进BeanFactory中(此时Bean还未实例化,只是读取了Bean的信息封装成BeanDefinition类而已)

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

refreshBeanFactory方法为抽象方法,具体定义是在子类AbstractRefreshableApplicationContext中完成,其会创建BeanFactory并且将其赋给父类变量beanFactory,所以下面一行可以将其get到并返回。

@Override
protected final void refreshBeanFactory() throws BeansException {
    //如果已经有容器,销毁容器中的bean,关闭容器
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        //创建IOC容器
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        //对IOC容器进行定制化,如设置启动参数,开启注解的自动装配等
        customizeBeanFactory(beanFactory);
        //调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

Spring容器在大部分地方都考虑到了所有的情况,可见其严谨性与健壮性,由于情况很多,所以有时候一些方法会显得比较复杂,晦涩难懂这也是很正常的。此方法执行开始判断是否之前就以及初始化容器,如有需要销毁容器的Bean再关闭容器。接着就new出上面提到的DefaultListableBeanFactory这个BeanFactory,很多对Bean的操作都是由DefaultListableBeanFactory完成的。这里loadBeanDefinitions 方法又是由不同子类定义的:
在这里插入图片描述

可以回过头回顾一下之前ApplicationContext中的类图结构,这里将有三种方式去加载Bean,这里也可以看出Spring框架的扩展性了,其利用抽象类的特性将功能细分到不同的子类,实现多态的方法去达到自己想要的目的,增加了扩展性。这里分析AbstractXmlApplicationContext读取Bean的方式:

//实现父类抽象的载入Bean定义方法
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    //创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // Configure the bean definition reader with this context's
    // resource loading environment.
    //为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的
    //祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    //为Bean读取器设置SAX xml解析器
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // Allow a subclass to provide custom initialization of the reader,
    // then proceed with actually loading the bean definitions.
    //当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制
    initBeanDefinitionReader(beanDefinitionReader);
    //Bean读取器真正实现加载的方法
    loadBeanDefinitions(beanDefinitionReader);
}

DefaultListableBeanFactory是一个BeanDefinitionRegistry,所以可以放入Reader构造器中初始化,这里将beanFactory放入Reader中初始化的原因是接下来会使用Reader这个类去读取Bean信息,然后Reader这个类会将信息注册进beanFactory会用到它,所以先封装进Reader之后方便将Bean信息放入beanFactory中。而正因为DefaultListableBeanFactory是一个BeanDefinitionRegistry所以拥有注册Bean的能力。

//Xml Bean读取器加载Bean定义资源
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    //获取Bean定义资源的定位
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位
        //的Bean定义资源
        reader.loadBeanDefinitions(configResources);
    }
    //如果子类中获取的Bean定义资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位
        //的Bean定义资源
        reader.loadBeanDefinitions(configLocations);
    }
}

在这里会进入第二个方法reader.loadBeanDefinitions(configLocations),还记得在ApplicationContext构造器中setConfigLocations方法吗?在这里就用到了此路径去解析Bean信息。

//重载方法,调用loadBeanDefinitions(String);
@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);
    }
    return counter;
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
    //获取在IoC容器初始化过程中设置的资源加载器
    ResourceLoader resourceLoader = getResourceLoader();
    if (resourceLoader == null) {
        throw new BeanDefinitionStoreException(
            "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
    }

    if (resourceLoader instanceof ResourcePatternResolver) {
        // Resource pattern matching available.
        try {
            //将指定位置的Bean定义资源文件解析为Spring IOC容器封装的资源
            //加载多个指定位置的Bean定义资源文件
            Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
            //委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
            int loadCount = loadBeanDefinitions(resources);
            if (actualResources != null) {
                for (Resource resource : resources) {
                    actualResources.add(resource);
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
            }
            return loadCount;
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                "Could not resolve bean definition resource pattern [" + location + "]", ex);
        }
    }
    else {
        // Can only load single resources by absolute URL.
        //将指定位置的Bean定义资源文件解析为Spring IOC容器封装的资源
        //加载单个指定位置的Bean定义资源文件
        Resource resource = resourceLoader.getResource(location);
        //委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
        int loadCount = loadBeanDefinitions(resource);
        if (actualResources != null) {
            actualResources.add(resource);
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
        }
        return loadCount;
    }
}

在这里,使用资源加载器去加载路径定位资源信息,使其封装为Resource对象,然后委派调用其子类XmlBeanDefinitionReader的方法loadBeanDefinitions(resource) 加载此资源。

//XmlBeanDefinitionReader加载资源的入口方法
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    //将读入的XML资源进行特殊编码处理
    return loadBeanDefinitions(new EncodedResource(resource));
}
//这里是载入XML形式Bean定义资源文件方法
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());
    }

    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的IO流
        InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
            //从InputStream中得到XML的解析源
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            //这里是具体的读取过程
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
        }
        finally {
            //关闭从Resource中得到的IO流
            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();
        }
    }
}

可以看到,这里会将资源对象先进行编码封装,然后将其转换成IO流对象(Resource中定义的方法),经过一系列封装,最终执行doLoadBeanDefinitions(inputSource, encodedResource.getResource()) 方法,真正的去加载Bean信息。在Spring中,真正做事的方法都是由do开头,Spring将方法封装的很深,有时候很容易迷路。

//从特定XML文件中实际载入Bean定义资源的方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    throws BeanDefinitionStoreException {
    try {
        //将XML文件转换为DOM对象,解析过程由documentLoader实现
        Document doc = doLoadDocument(inputSource, resource);
        //这里是启动对Bean定义解析的详细过程,该解析过程会用到Spring的Bean配置规则
        return registerBeanDefinitions(doc, resource);
    }
    //略...
}

这里将资源转换为一个DOM对象,方便之后Spring根据一些规则去解析Bean信息。

//按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //得到BeanDefinitionDocumentReader来对xml格式的BeanDefinition解析
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    //获得容器中注册的Bean数量
    int countBefore = getRegistry().getBeanDefinitionCount();
    //解析过程入口,这里使用了委派模式,BeanDefinitionDocumentReader只是个接口,
    //具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    //统计解析的Bean数量
    return getRegistry().getBeanDefinitionCount() - countBefore;
}
//根据Spring DTD对Bean的定义规则解析Bean定义Document对象
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    //获得XML描述符
    this.readerContext = readerContext;
    logger.debug("Loading bean definitions");
    //获得Document的根元素
    Element root = doc.getDocumentElement();
    doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
    // Any nested <beans> elements will cause recursion in this method. In
    // order to propagate and preserve <beans> default-* attributes correctly,
    // keep track of the current (parent) delegate, which may be null. Create
    // the new (child) delegate with a reference to the parent for fallback purposes,
    // then ultimately reset this.delegate back to its original (parent) reference.
    // this behavior emulates a stack of delegates without actually necessitating one.

    //具体的解析过程由BeanDefinitionParserDelegate实现,
    //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

	//略...

    //在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
    preProcessXml(root);
    //从Document的根元素开始进行Bean定义的Document对象
    parseBeanDefinitions(root, this.delegate);
    //在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
    postProcessXml(root);

    this.delegate = parent;
}

在这里会执行一些自定义解析,我将在之后的关于介绍Spring的扩展的一篇文章中介绍自定义标签的使用,这里只分析Spring自己的标签解析 -> parseBeanDefinitions(root, this.delegate);

	//使用Spring的Bean规则从Document的根元素开始进行Bean定义的Document对象
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		//Bean定义的Document对象使用了Spring默认的XML命名空间
		if (delegate.isDefaultNamespace(root)) {
			//获取Bean定义的Document对象根元素的所有子节点
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				//获得Document节点是XML元素节点
				if (node instanceof Element) {
					Element ele = (Element) node;
					//Bean定义的Document的元素节点使用的是Spring默认的XML命名空间
					if (delegate.isDefaultNamespace(ele)) {
						//使用Spring的Bean规则解析元素节点
						parseDefaultElement(ele, delegate);
					}
					else {
						//没有使用Spring默认的XML命名空间,则使用用户自定义的解//析规则解析元素节点
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			//Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的
			//解析规则解析Document根节点
			delegate.parseCustomElement(root);
		}
	}

这里进入Spring自定规则解析方法 -> parseDefaultElement(ele, delegate);

//使用Spring的Bean规则解析Document元素节点
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    //如果元素节点是<Import>导入元素,进行导入解析
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    //如果元素节点是<Alias>别名元素,进行别名解析
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    //元素节点既不是导入元素,也不是别名元素,即普通的<Bean>元素,
    //按照Spring的Bean规则解析元素
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        //如果是<Beans>标签则递归处理
        doRegisterBeanDefinitions(ele);
    }
}

可以看到,这里将解析<import><Alias><Bean><Beans>标签,这里看看是如何解析<Bean>标签的。

//解析Bean定义资源Document对象的普通元素
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类
    //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现
    // BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            //向Spring IOC容器注册解析得到的Bean定义,这是Bean定义向IOC容器注册的入口
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                                     bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        //在完成向Spring IOC容器注册解析得到的Bean定义之后,发送注册事件
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

这里就是主要封装Bean信息的方法了,这个方法做了两件事

  1. 委派模式,委派delegate去解析标签,并且它将其结果封装为一个BeanDefinitionHolder

    //解析<Bean>元素的入口
    @Nullable
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
        return parseBeanDefinitionElement(ele, null);
    }
    

    感兴趣可以去看看此方法,具体就是将标签中id、name、以及中信息,设置依赖对象与所需资源、配置作用域(默认Singleton单例)、构造方法设置等等等等信息,封装成Holder对象返回。

  2. 使用工具类BeanDefinitionReaderUtils的静态方法去注册Bean定义的信息,注意这里将holder注册进了之前提到的Registry中,此Registry即为一开始传入构造器的beanFactory。

    //将解析的BeanDefinitionHold注册到容器中
    public static void registerBeanDefinition(
        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
        throws BeanDefinitionStoreException {
    
        // Register bean definition under primary name.
        //获取解析的BeanDefinition的名称
        String beanName = definitionHolder.getBeanName();
        //向IOC容器注册BeanDefinition
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
        // Register aliases for bean name, if any.
        //如果解析的BeanDefinition有别名,向容器为其注册别名
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }
    

    这里还是回到了DefaultListableBeanFactory中的注册方法registerBeanDefinition

    //向IOC容器注册解析的BeanDefiniton
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {
        
        //略...
    
        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<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                if (this.manualSingletonNames.contains(beanName)) {
                    Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        }
        else {
            // Still in startup registration phase
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            this.manualSingletonNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }
    
        //检查是否有同名的BeanDefinition已经在IOC容器中注册
        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            //重置所有已经注册过的BeanDefinition的缓存
            resetBeanDefinition(beanName);
        }
    }
    

    这里省略了一大段判断的代码,只看主要注册的过程。到这里我们可以知道,真正注册其实是在一个ConcurrentHashMap中存放Bean信息,Key为BeanName ,Value为BeanDefinition

    /** Map of bean definition objects, keyed by bean name */
    //存储注册信息的BeanDefinition
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    

    并且会更新BeanName列表,在此会以List的形式存放所有Bean的名称:

    /** List of bean definition names, in registration order */
    private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
    

总结

到此为止,我们介绍完了IOC容器对资源的定位(根据路径定位资源)、加载(根据一定规则加载资源成为一个可解析的对象)、注册(将封装好了的Bean信息对象存放进BeanFactory中的Map里,并且使用List存放BeanName)。然而,这个过程只是一个开始,此时的Bean还未初始化,BeanFactory中只是存放了Bean的描述定义对象而已,真正初始化是在getBean()方法被调用。

读者是否感觉到很晕,经常不知道自己在哪里,我这里建议在了解大部分流程之后自己去画一张时序图,我以前研究Spring的时候真是看到哪里晕到哪里,都不知道我在哪我是谁了,但是只要根据流程自己去动手画一张时序图,再配合资料我相信你会清晰很多很多。同时还需要读者不断回顾主线脉络,一定要知道常用的几个类究竟是什么,干什么用的,这样才能跟着Spring的思路更容易看懂Spring在这里究竟想做什么。

猜你喜欢

转载自blog.csdn.net/qq_41737716/article/details/84942946