文档章节

Spring5对比Spring3.2源码之容器的基本实现

Ilike_Java
 Ilike_Java
发布于 2018/10/17 01:08
字数 887
阅读 28
收藏 6

最近看了《Spring源码深度解析》,该书是基于Spring3.2版本的,其中关于第二章容器的基本实现部分,目前spring5的实现方式已有较大改变。

Spring3.2的实现:

public void testSimpleLoad(){

    BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring/application-context.xml"));

    UserService userService = (UserService)beanFactory.getBean("userService");

}

容器的基础XmlBeanFactory已经被废弃(@Deprecated)。

Spring5.0的实现方式有两种:

第一种是通过ClassPathXmlApplicationContext实现的,也是常用的一种。

public void classPath(){

    ApplicationContext context = new ClassPathXmlApplicationContext("spring/application-context.xml");

    UserService userService = (UserService) context.getBean("userService");

    userService.update();

}

第二种是通过FileSystemXmlApplicationContext实现的。

public void fileSystem(){

    ApplicationContext context = new FileSystemXmlApplicationContext("target/classes/spring/application-context.xml");

    UserService userService = (UserService) context.getBean("userService");

    userService.update();

}

两种方式的区别在于寻找配置文件的根路径的不同。下面我就以ClassPathXmlApplicationContext对比Spring3.2的XmlBeanFactory是如何加载配置文件xml中我们的Bean的。

ClassPathXmlApplicationContext的构造函数:

public ClassPathXmlApplicationContext(

      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)

      throws BeansException {



   super(parent);

   setConfigLocations(configLocations);

   if (refresh) {

      refresh();

   }

}

关键方法refresh()的源码

@Override

public void refresh() throws BeansException, IllegalStateException {

   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      prepareRefresh();
      // 告诉子类刷新内部bean工厂
      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) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + 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();
      }
   }
}

构建Bean容器的步骤就在这个refresh()方法中。其中obtainFreshBeanFactory();刷新Bean工厂。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

   refreshBeanFactory();

   ConfigurableListableBeanFactory beanFactory = getBeanFactory();

   if (logger.isDebugEnabled()) {

      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);

   }

   return beanFactory;

}
protected final void refreshBeanFactory() throws BeansException {

   if (hasBeanFactory()) {

      destroyBeans();

      closeBeanFactory();

   }

   try {

      DefaultListableBeanFactory beanFactory = createBeanFactory();

      beanFactory.setSerializationId(getId());

      customizeBeanFactory(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了吗?Spring3.2的实现方式的XmlBeanFactory就是继承自DefaultListableBeanFactory,是整个bean加载的核心部分,具体可以参考《Spring源码深度解析》。

进入loadBeanDefinitions(beanFactory);

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {

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



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

   }

   String[] configLocations = getConfigLocations();

   if (configLocations != null) {

      reader.loadBeanDefinitions(configLocations);

   }

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

   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 {

         Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);

         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.

      Resource resource = resourceLoader.getResource(location);

      int loadCount = loadBeanDefinitions(resource);

      if (actualResources != null) {

         actualResources.add(resource);

      }

      if (logger.isDebugEnabled()) {

         logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");

      }

      return loadCount;

   }

}
@Override

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {

   return loadBeanDefinitions(new EncodedResource(resource));

}

到此这个方法就和《Spring源码深度机械》一书加载Bean的介绍一致了,后续加载过程可参考此书。

© 著作权归作者所有

共有 人打赏支持
Ilike_Java
粉丝 0
博文 3
码字总数 2062
作品 0
私信 提问
《Spring5学习》 01 装配Bean之自动化装配

Spring的自动化装配就便利性方面远远优于其他装配方法,这也是业界目前主要采用的Bean装配机制。Spring基于组建扫描和自动装配实现自动化装配,能将用户的显示配置降到最低。以下通过一段代码...

老韭菜
2018/08/05
0
0
Spring3.2 MVC 分析

Spring3.2 MVC 分析: SpringMVC现在应该用得很广泛了,其配置清晰,灵活度,定制能力等都是很强的,相比Struts2也是胜过一筹,还是从源码来分析一下,SpringMVC为我们做了什么。 先从配置文...

ihaolin
2014/02/03
0
2
spring-ioc分析

BeanFactory和ApplicationContext BeanFactory和ApplicationContext都是容器,BeanFactory是最基础的容器,里面定义了一些最基本的方法: 而Application也同样是容器,对比与BeanFactory来说...

sendo
2018/01/23
0
0
Spring Security OAuth 2.2.1 发布,常规维护版本

Spring Security OAuth 2.2.1 已发布,该版本是一个维护版本,包括错误修复和小的改进。具体如下: 改进 Improve logging in TokenEndpoint OAuth2AccessTokenSupport.OAuth2AuthTokenCallb...

局长
2017/11/22
865
1
Spring Boot 静态资源文件配置

Spring Boot 静态资源文件配置 说在前面的话: 创建SpringBoot应用,选中我们需要的模块 SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来 自己编写业务...

胖先森
2018/12/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

阿里强制要求的21条Java开发规范,可以避免很多坑

1. 【强制】避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可。 2. 【强制】所有的覆写方法,必须加@Override注解。 说明:getObject...

天王盖地虎626
11分钟前
1
0
oracle dg 备库未设置convert参数导致ORA-01111,ORA-01110

查看trace 文件: MRP0: Background Managed Standby Recovery process started (amls) started logmerger process Sun Jan 20 07:55:53 2019 Managed Standby Recovery starting Real Time ......

hnairdb
31分钟前
2
0
乱入Linux界的我是如何学习的

欢迎来到建哥学Linux,咳!咳!咳!开个玩笑哈,我是一个IT男,IT界的入门选手,正在学习Linux。 在之前,一直想进军IT界,学习IT技术,但是苦于没有人指导,也不知道学什么,最开始我自己在...

linux-tao
今天
1
0
乱入Linux界的我是如何学习的

欢迎来到建哥学Linux,咳!咳!咳!开个玩笑哈,我是一个IT男,IT界的入门选手,正在学习Linux。 在之前,一直想进军IT界,学习IT技术,但是苦于没有人指导,也不知道学什么,最开始我自己在...

linuxprobe16
今天
9
0
OSChina 周日乱弹 —— 没时间 没头发 但有钱

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @开源中国总经办主任 :分享齐一的单曲《这个年纪》 《这个年纪》- 齐一 手机党少年们想听歌,请使劲儿戳(这里) @肿肿卷 :我真的可以睡一天...

小小编辑
今天
135
6

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部