Spring初始化Ioc源码分析以及Aop原理分析(三)

一.Spring Ioc 高级实现ApplicationContext的运行分析

ApplicationContext 这个Ioc的实现通常是在web应用中出现的,也是我们最常用的方式。启动项目,就开始初始化这个容器了。
Ioc容器的实现,都是通过三个步骤:定位资源文件,解析资源文件,对容器进行一些初始化操作。 前面对XmlBeanFactory的分析,只做到了前两步。

1.1 定位资源文件

// 这行代码,不会显示调用,在web项目启动的时候,通过在监听器中调用这行代码。
ApplicationContext beanFactory = new ClassPathXmlApplicationContext("spring/springmvc.xml");

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    // 直接调用重载的方法
        this(new String[]{configLocation}, true, (ApplicationContext)null);
    }

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
        super(parent);
        //存储Springmvc.xml 路径 
        this.setConfigLocations(configLocations);
        if (refresh) {
        // 初始化的时候refresh==true,核心逻辑的开始 
            this.refresh();
        }
    }

上面的代码说明,主要是获取到所有Spring相关的xml文件。例如ApplicationContext.xml 和 SpringMvc.xml 等。

// AbstractRefreshableConfigApplicationContext 类
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) {
           // 把xml路径放入到 String[] configLocations 中,支持多个配置文件以数组方式同时传入。
                this.configLocations[i] = this.resolvePath(locations[i]).trim();
            }
        } else {
            this.configLocations = null;
        }

    }

1.2 资源解析和对容器进行一些初始化操作

refresh()方法是包括了ApplicationContext 容器的全部操作

public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
        // 准备刷新上下文环境 
            this.prepareRefresh();
            /* 加载BeanFactory,ApplicationContext是对BeanFactory功能的扩展,这个方法就是用来获取BeanFactory */
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //为BeanFactory配置容器特性,例如类加载器、事件处理器等 
            this.prepareBeanFactory(beanFactory);
            try {
            // 注册后处理BeanFactoryPostPorcessor
                this.postProcessBeanFactory(beanFactory);   
                //调用BeanFactoryPostPorcessor this.invokeBeanFactoryPostProcessors(beanFactory);
                //为BeanFactory注册BeanPost事件处理器. 
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                // 为了管理容器注册一些监听器
                this.registerListeners();
                //这是对BeanDefinition 进行实例化的方法。
          this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } 
         }
                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

refresh()方法主要分两部分:

  • 资源的解析:
 // 准备刷新上下文环境 
            this.prepareRefresh();
            /* 加载BeanFactory,ApplicationContext是对BeanFactory功能的扩展,这个方法就是用来获取BeanFactory */
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

经过上面两个方法,其实已经完成了前面XmlBeanFactory的所有功能了。
下面的方法,就是对容器进行功能的扩展和实例化所有的非懒加载的Bean了。

  • 容器功能扩展和初始化
        //为BeanFactory配置容器特性,例如类加载器、事件处理器等 
            this.prepareBeanFactory(beanFactory);
            try {
            // 注册后处理BeanFactoryPostPorcessor
                this.postProcessBeanFactory(beanFactory);   
                //调用BeanFactoryPostPorcessor this.invokeBeanFactoryPostProcessors(beanFactory);
                //为BeanFactory注册BeanPostPorcessor事件处理器. 
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                // 为了管理容器注册一些监听器
                this.registerListeners();
                //这是对BeanDefinition 进行实例化的方法。
          this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } 

1.2.1 资源解析得到Ioc容器

// 实际这一段并没有做任何事,主要是为了扩展用的,spring本身并没有做任何事情
protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
        if (this.logger.isInfoEnabled()) {
            this.logger.info("Refreshing " + this);
        }
        // 留给子类覆盖
        this.initPropertySources();
        // 验证需要的属性文件是否都已经放入环境中
        this.getEnvironment().validateRequiredProperties();
        this.earlyApplicationEvents = new LinkedHashSet();
    }

obtainFreshBeanFactory()具体实现 AbstractApplicationContext类

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 调用相同类下的 refreshBeanFactory()方法 
        this.refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

refreshBeanFanctory() 在 AbstractRefreshableApplicationContext类中

protected final void refreshBeanFactory() throws BeansException {
    // 判断是否有BeanFactory,初始化的时候,是没有的,false
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }
        try {
        // 创建DefaultListableBeanFactory, 
        // new DefaultListableBeanFactory(this.getInternalParentBeanFactory());
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            // 定制BeanFactory 
            this.customizeBeanFactory(beanFactory);
            // 初始化 DocumetReader ,并进行XML文件读取及解析 
            // 这里就和XmlBeanFactory中一样了。
            this.loadBeanDefinitions(beanFactory);
            Object var2 = this.beanFactoryMonitor;
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

初始化 DocumetReader ,并进行XML文件读取及解析 在AbstractXmlApplicationContext类

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        // 初始化BeanFactoryReader ,实际上就是加如一个验证位
        this.initBeanDefinitionReader(beanDefinitionReader);
        // 这里XmlBeanFactory创建时一样,通过一个XmlBeanDefinitionReader来读取Xml
        this.loadBeanDefinitions(beanDefinitionReader);
    }

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    // 检查ClassPathXmlApplicationContext中的 Resource[] configResources; 是否有资源,有就加载。
        Resource[] configResources = this.getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
    /* 检查AbstractRefreshableConfigApplicationContext中的String[] configLocations 中是否有资源 前面在 this.setConfigLocations(configLocations); 中我们把传入的 spring\mvc.xml 路径存入进去了。 */
        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
        // 根据路径加载 BeanDefinition 到 DefaultListableBeanFactory中去了,
        // 具体实现参考 XmlBeanFactory的初始化
            reader.loadBeanDefinitions(configLocations);
        }
    }

1.2.2 对Ioc容器进行功能扩展
在这之前,已经完成了对配置的解析。 ApplicationContext的功能扩展正式展开。



 //为BeanFactory配置容器特性,例如类加载器、事件处理器等  this.prepareBeanFactory(beanFactory); try { // 注册后处理BeanFactoryPostPorcessor this.postProcessBeanFactory(beanFactory); //调用BeanFactoryPostPorcessor this.invokeBeanFactoryPostProcessors(beanFactory); //为BeanFactory注册BeanPostPorcessor事件处理器.  this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); // 为了管理容器注册一些监听器 this.registerListeners(); //这是对BeanDefinition 进行实例化的方法。(重点) this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } 

prepareBeanFactory() 在 AbstractApplicationContext
这个方法主要是对容器进行一些扩展。

 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
      // 设置beanFactory的classLoader为当前context的classLoader
        beanFactory.setBeanClassLoader(this.getClassLoader());
        // 设置beanFactory的表达式语言
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        /* 增加对属性编辑器的支持,例如在SpringDI注入的时候,可以把普通属性注入进来,但是像Date类型就无法识别, 就需要这个转换了,不过一般时间 */
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
        // 添加BeanPostProcessor ,添加ApplicationContextAwareProcessor处理器
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        // 设置几个忽略自动装配的接口
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);
        // 可以看到有很多addBeanPostProcessor
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
        // 增加对AspectJ的支持
        if (beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    // 添加默认的系统环境bean
        if (!beanFactory.containsLocalBean("environment")) {
            beanFactory.registerSingleton("environment", this.getEnvironment());
        }

        if (!beanFactory.containsLocalBean("systemProperties")) {
            beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
        }

        if (!beanFactory.containsLocalBean("systemEnvironment")) {
            beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
        }
    }

下面两个方法,主要是向容器中添加BeanFactoryPostPorcessor
和调用其中的方法。在运行过程中,所有的 BeanFactoryPostPorcessor实现类 的后置方法在 Ioc 容器生成后,执行。

 this.postProcessBeanFactory(beanFactory);   
        //调用BeanFactoryPostPorcessor this.invokeBeanFactoryPostProcessors(beanFactory);

下面的方法,是添加注册一些BeanPostProcessor,主要分两类:

  • 一类是实现了BeanPostProcessor接口的类,它的作用是Bean对象再属性注入完成后,执行init()初始化方法的前后,进行拦截执行前置方法和后置方法。
  • 一类是继承了了InstantiationAwareBeanPostProcessorAdapter 类,它的作用是Bean对象实例化,还没有属性注入前, 在实例化前后进行拦截。

具体可以看Spring初始化Ioc源码分析以及Aop原理分析(一) 中的分析

下面来分析是怎么注册 BeanPostProcessor 的

public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
        int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
        beanFactory.addBeanPostProcessor(new PostProcessorRegistrationDelegate.BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
        // 使用priorityOrderedPostProcessors 保证顺序。
        List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList();
        List<BeanPostProcessor> internalPostProcessors = new ArrayList();
        List<String> orderedPostProcessorNames = new ArrayList();
        List<String> nonOrderedPostProcessorNames = new ArrayList();
        String[] var8 = postProcessorNames;
        int var9 = postProcessorNames.length;

        String ppName;
        BeanPostProcessor pp;
        for(int var10 = 0; var10 < var9; ++var10) {
            ppName = var8[var10];
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            // 这里可以看出,已经对BeanPostProcessor实例化了。
                pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);
                priorityOrderedPostProcessors.add(pp);
                if (pp instanceof MergedBeanDefinitionPostProcessor) {
                    internalPostProcessors.add(pp);
                }
            } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            } else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }

        ...
    }

上面的方法,非常复杂,但核心思想就是,把BeanPostProcessor类的BeanDefinition给实例化成真正的对象,存储在容器中,供后面普通类初始化的时候去使用。

接下来的方法就是重点了

// 初始化所有剩下的非延迟加载类。
finishBeanFactoryInitialization(beanFactory)

前面也讲到了 ApplicationContext相对于XmlBeanFactory的区别就在于ApplicationContext会在初始化容器的时候,把bean顺带也加载了,而XmlBeanFactory不会,只有用到的时候才会加载。 具体来分析这个方法

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        ......
        beanFactory.setTempClassLoader((ClassLoader)null);
        beanFactory.freezeConfiguration();
        // 实例化对象的方法
        beanFactory.preInstantiateSingletons();
    }

实际加载bean的方法, 在 DefaulistableBeanFactory中。 这里和XmlBeanFactory一样,

// 通过getBean(beanName) 来实例化bean。
 public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }
    // 获取beanDefinitionNames 中 所有的beanName,为初始化准备
        List<String> beanNames = new ArrayList(this.beanDefinitionNames);
        Iterator var2 = beanNames.iterator();

        .....

        // 如果是FactoryBean,那就得到这个对象。
                if (this.isFactoryBean(beanName)) {
                    final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName);
                    boolean isEagerInit;
                    ......  // 这其中都是一堆的判断

                    if (isEagerInit) {
                        this.getBean(beanName);
                    }
                } else {
                // 前面都是各种判断,这里才是真正的实例化bean 的地方。
                    this.getBean(beanName);
                }
            }
        }
    }

通过这个方法,最后,还是通过getBean(beanName)去实例化对象,在Bean的生命周期那里已经对此进行分析了。

    原文作者:AOP
    原文地址: https://blog.csdn.net/Mooneal/article/details/79716806
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞