java学习基地

微信扫一扫 分享朋友圈

已有 1160 人浏览分享

通过Debug带你详细了解Spring创建Bean的过程,一清二楚!

[复制链接]
1160 2
本帖最初由 进修派 于 2020-12-3 21:22 编纂

目次
  • Spring流程Debug

  • 办法1:prepareRefresh() => 筹办事情

  • 办法2:obtainFreshBeanFactory() => 得到一个革新的bean容器

  • 办法3:prepareBeanFactory(beanFactory) => 筹办(初初化)Bean工场

  • 办法4:postProcessBeanFactory(beanFactory) => 后置加强Bean(扩大完成)

  • 办法5:invokeBeanFactoryPostProcessors(beanFactory) => 施行BFPP

  • 办法6:registerBeanPostProcessors(beanFactory) => 注册BPP

  • 办法7:initMessageSource() => 国际化设置

  • 办法8:initApplicationEventMulticaster() => 初初化使用法式的多波器战播送器

  • 办法9:onRefresh() => 预留给子类做扩大

  • 办法10:registerListeners() => 注册监听器

  • 办法11:finishBeanFactoryInitialization(beanFactory) => 真例化一切单例工具

  • 办法12:finishRefresh() => 完成革新

  • 办法13:resetCommonCaches() => 缓存重置

  • 1.1 Spring测试情况拆建

  • 1.2 Debug容器创立历程

  • 1.3 AbstractApplicationContext的refresh()包罗的13个办法阐发


Spring流程Debug1.1 Spring测试情况拆建

Spring模块概览,绿色是模块,Spring终年夜模块,玄色暗示该模块包罗的jar包(组件)。比方我们念要用IOC容器,也便是绿色的CoreContainer,我们需求导进Beans,Core,Context,SpEL(spring-expression)四个包。

Spring模块概览
  • Test:测试相干

  • Core Container:IOC容器

  • AOP:里背切里编程

  • Aspects:切里

  • Instrumenttation:跟JDK联系关系,普通不消

  • Messaging?息效劳,普通不消

  • Data Access/Integration:数据会见取散成(JDBC会见,Transaction事件,ORM工具干系映照,OXM战XML映照普通不消,JMS为Java动静效劳Java-message-service普通不消)

  • Web:Web效劳(WebSocket收集通讯和谈,Servlet, Web,Portlet普通不消)


最徒擦的方法,是间接导进Spring-Framework。可是能够导进没必要要的包,招致项目挨包后比力年夜

因为Spring-Content中的ApplicationContent是全部IOC的进口。我们导进Spring-context包便可

  1. <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
  2. <dependency>
  3.     <groupId>org.springframework</groupId>
  4.     <artifactId>spring-context</artifactId>
  5.     <version>5.2.3.RELEASE</version>
  6. </dependency>
赶钙代码
我们导进spring-content后,默许会导进该组件的依靠jar,spring-content蹬鲢的依靠能够看到,实践上我们是导进了Core Container模块
  1.   <dependencies>
  2.     <dependency>
  3.       <groupId>org.springframework</groupId>
  4.       <artifactId>spring-aop</artifactId>
  5.       <version>5.2.3.RELEASE</version>
  6.       <scope>compile</scope>
  7.     </dependency>
  8.     <dependency>
  9.       <groupId>org.springframework</groupId>
  10.       <artifactId>spring-beans</artifactId>
  11.       <version>5.2.3.RELEASE</version>
  12.       <scope>compile</scope>
  13.     </dependency>
  14.     <dependency>
  15.       <groupId>org.springframework</groupId>
  16.       <artifactId>spring-core</artifactId>
  17.       <version>5.2.3.RELEASE</version>
  18.       <scope>compile</scope>
  19.     </dependency>
  20.     <dependency>
  21.       <groupId>org.springframework</groupId>
  22.       <artifactId>spring-expression</artifactId>
  23.       <version>5.2.3.RELEASE</version>
  24.       <scope>compile</scope>
  25.     </dependency>
  26.   </dependencies>
赶钙代码
新建Spring设置文件spring.xml:



  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.     <!--注册一个工具,spring回主动创立那个工具-->
  6.     <!--
  7.     一个bean标签便暗示一个工具
  8.     id:那个工具的独一标识
  9.     class:注册工具的完整限制名
  10.     -->
  11.     <bean id="hello" class="com.xiaodai.service.Hello">
  12.         <!--利用property标签给工具的属性赋值
  13.         name:暗示属性的称号
  14.         value:暗示属性的值
  15.         -->
  16.         <property name="id" value="1"></property>
  17.         <property name="name" value="zhangsan"></property>
  18.         <property name="age" value="18"></property>
  19.     </bean>
  20. </beans>
赶钙代码
编写测试类:

  1. import com.xiaodai.service.Hello;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. public class Test {
  5.     public static void main(String[] args) {
  6.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
  7.         Hello hello = applicationContext.getBean("hello", Hello.class);
  8.         System.out.println(hello.getName());
  9.     }
  10. }
赶钙代码
1.2 Debug容器创立历程

从测试类的new ClassPathXmlApplicationContext("spring.xml")开端debug,进进ClassPathXmlApplicationContext,能够看到:

  1. public ClassPathXmlApplicationContext(
  2.    String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
  3.    throws BeansException {
  4.   super(parent);
  5.   // 设置设置文件途径
  6.   setConfigLocations(configLocations);
  7.   if (refresh) {
  8.           // 中心步调
  9.    refresh();
  10.   }
  11. }
赶钙代码

减载设置文件后,进进refresh()办法,该办法是容器初初化的中心步调。该办法包罗十三个办法:

  1.         @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3.   synchronized (this.startupShutdownMonitor) {
  4.    // Prepare this context for refreshing.
  5.    /**
  6.     * 筹办革新,做一些最根本的筹办化事情
  7.    **/
  8.    prepareRefresh();
  9.    // Tell the subclass to refresh the internal bean factory.
  10.    /**
  11.     * 得到一个革新的bean容器,本质便是获得工场。
  12.     * 减载xml等设置文件,用该文件发生的BeanDefinition去创立一个工场
  13.    **/
  14.    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  15.    // Prepare the bean factory for use in this context.
  16.    /**
  17.     * 筹办bean工场
  18.    **/
  19.    prepareBeanFactory(beanFactory);
  20.    try {
  21.     // Allows post-processing of the bean factory in context subclasses.
  22.     // 后置加强,便利扩大
  23.     postProcessBeanFactory(beanFactory);
  24.     // Invoke factory processors registered as beans in the context.
  25.     // 真例化而且施行BeanFactoryPostProcessors
  26.     invokeBeanFactoryPostProcessors(beanFactory);
  27.     // Register bean processors that intercept bean creation.
  28.     // 真例化而且注册一切的BeanPostProcessor
  29.     registerBeanPostProcessors(beanFactory);
  30.     // Initialize message source for this context.
  31.     // 国际化设置,普通用没有到
  32.     initMessageSource();
  33.     // Initialize event multicaster for this context.
  34.     // 初初化使用法式的多波器战播送器
  35.     initApplicationEventMulticaster();
  36.     // Initialize other special beans in specific context subclasses.
  37.     // 空办法,预留给子类做扩大
  38.     onRefresh();
  39.     // Check for listener beans and register them.
  40.     // 注册监听器
  41.     registerListeners();
  42.     // Instantiate all remaining (non-lazy-init) singletons.
  43.     // 事情中经常使用,口试常问。真例化一切非懒减载的真例工具
  44.     finishBeanFactoryInitialization(beanFactory);
  45.     // Last step: publish corresponding event.
  46.     // 完成革新
  47.     finishRefresh();
  48.    }
  49.    catch (BeansException ex) {
  50.     if (logger.isWarnEnabled()) {
  51.      logger.warn("Exception encountered during context initialization - " +
  52.        "cancelling refresh attempt: " + ex);
  53.     }
  54.     // Destroy already created singletons to avoid dangling resources.
  55.     destroyBeans();
  56.     // Reset 'active' flag.
  57.     cancelRefresh(ex);
  58.     // Propagate exception to caller.
  59.     throw ex;
  60.    }
  61.    finally {
  62.     // Reset common introspection caches in Spring's core, since we
  63.     // might not ever need metadata for singleton beans anymore...
  64.     resetCommonCaches();
  65.    }
  66.   }
  67. }
赶钙代码
1.3 AbstractApplicationContext的refresh()包罗的13个办法阐发

分离概览图一个一个办法阐发:

Bean工场真例化Bean概览图办法1:prepareRefresh() => 筹办事情

筹办革新,做一些最根本的筹办化事情

  1. protected void prepareRefresh() {
  2.   // Switch to active.
  3.   // 设置开端工夫
  4.   this.startupDate = System.currentTimeMillis();
  5.   // 封闭形态设置为false
  6.   this.closed.set(false);
  7.   // 活泼形态设置为true
  8.   this.active.set(true);
  9.         // 挨印日记
  10.   if (logger.isDebugEnabled()) {
  11.    if (logger.isTraceEnabled()) {
  12.     logger.trace("Refreshing " + this);
  13.    }
  14.    else {
  15.     logger.debug("Refreshing " + getDisplayName());
  16.    }
  17.   }
  18.   // Initialize any placeholder property sources in the context environment.
  19.   // 初初化属性资本
  20.   initPropertySources();
  21.   // Validate that all properties marked as required are resolvable:
  22.   // see ConfigurablePropertyResolver#setRequiredProperties
  23.   // 获得情况疑息,考证属性疑息
  24.   getEnvironment().validateRequiredProperties();
  25.   // Store pre-refresh
  26.   // 存储预革新的一些使用疑息的监听器
  27.   ApplicationListeners...
  28.   if (this.earlyApplicationListeners == null) {
  29.    this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
  30.   }
  31.   else {
  32.    // Reset local application listeners to pre-refresh state.
  33.    this.applicationListeners.clear();
  34.    this.applicationListeners.addAll(this.earlyApplicationListeners);
  35.   }
  36.   // Allow for the collection of early ApplicationEvents,
  37.   // to be published once the multicaster is available...
  38.   // 创立一些监听器变乱的汇合
  39.   this.earlyApplicationEvents = new LinkedHashSet<>();
  40. }
赶钙代码

总结:1.设置启动变乱 2.设置封闭活泼的形态 3.获得情况工具并设置属性值 4.设置监听器和需求公布变乱的汇合。搜刮公家号 Java条记虾,复兴“后端口试“收您一份口试题宝典.pdf

主要的面:

  • 获得情况疑息,考证属性疑息,getEnvironment().validateRequiredProperties();

  • 存储预革新的一些使用疑息的监听器,正在Spring中是空完成,可是SpringBoot中,是有详细的值的









本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

举报 使用道具

回复

评论 2

冰封  vip终身会员  发表于 2020-12-22 19:06:01 | 显示全部楼层
看帖要回,回帖才健康,在踩踩,楼主辛苦了!

举报 使用道具

回复
星光大道  vip终身会员  发表于 2020-12-22 19:28:55 | 显示全部楼层
求沙发

举报 使用道具

回复
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

0

粉丝

138

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Archiver|手机版|java学习基地 |网站地图

GMT+8, 2021-2-28 23:17 , Processed in 0.750000 second(s), 32 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.