文档章节

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

Ilike_Java
 Ilike_Java
发布于 10/17 01:08
字数 887
阅读 17
收藏 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基于组建扫描和自动装配实现自动化装配,能将用户的显示配置降到最低。以下通过一段代码...

老韭菜
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
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
783
1
spring源码分析之IOC初始化

什么是IOC? IOC, 即控制反转(Inversion of Control), 它的主要作用是用来解耦。 举个例子来说: 古代的皇帝再临幸妃子的时候, 他不会自己去找妃子, 而是告诉太监, 今天要哪个妃子, 然...

xiaoqqq
2015/03/22
1K
1

没有更多内容

加载失败,请刷新页面

加载更多

docker部署springboot项目

安装docker 菜鸟教程 springboot项目 maven依赖 <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001......

yimingkeji
今天
10
0
ios多个target

1.建立3个target,分别为heroone,heroone test,heroone dev;分别为正式环境,test环境,dev环境 2.注意取消掉autocreate以防止名字不对,分别以Duplicate的方式建立另外两个scheme 3.创建...

HeroHY
今天
5
0
php获取客户端IP

php获取客户端IP 首先先阅读关于IP真实性安全的文章:如何正確的取得使用者 IP? 「任何從客戶端取得的資料都是不可信任的!」 HTTP_CLIENT_IP头是有的,但未成标准,不一定服务器都实现。 ...

DrChenXX
昨天
0
0
. The valid characters are defined in RFC 7230 and RFC 问题

通过这里的回答,我们可以知道: Tomcat在 7.0.73, 8.0.39, 8.5.7 版本后,添加了对于http头的验证。 具体来说,就是添加了些规则去限制HTTP头的规范性 参考这里 具体来说: org.apache.tom...

west_coast
昨天
1
0
刷leetcode第704题-二分查找

今天双十一买的算法书到货了,路上刷到有人说的这个题,借(chao)鉴(xi)一下别人的思路,这个是C++标准库里面的经典方法,思路精巧,优雅好品味 int search(int* nums, int numsSize, in...

锟斤拷烫烫烫
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部