前言

spring作为一个容器,可以管理对象的生命周期、对象与对象之间的依赖关系。可以通过配置文件,来定义对象,以及设置其与其他对象的依赖关系。

main测试类

  1. public static void main(String[] args) {
  2. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
  3. Bean bean = applicationContext.getBean(Bean.class);
  4. System.out.println(bean);
  5. }

ClassPathXmlApplicationContext类

  • application建立以后,可以通过refresh()进行重建,这样会将原来的application销毁,然后重新执行初始化

  • 构造方法

    1. public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
    2. throws BeansException {
    3. super(parent);
    4. //设置配置文件
    5. setConfigLocations(configLocations);
    6. if (refresh) {
    7. //核心方法
    8. refresh();
    9. }
    10. }

AbstractApplicationContext类

refresh方法

  1. @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3. // 同步,防止你在初始化的过程中被打断
  4. synchronized (this.startupShutdownMonitor) {
  5. // 准备工作
  6. prepareRefresh();
  7. // 配置文件被拆分成Bean定义,注册在BeanFactory中。
  8. // 也就是Map<beanName, beanDefinition>
  9. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  10. // Prepare the bean factory for use in this context.
  11. prepareBeanFactory(beanFactory);
  12. try {
  13. // 到这一步,所有的Bean加载和注册都已经完成,但是还没开始初始化
  14. // 如果实现了 BeanFactoryPostProcessor 接口,可以在初始化的时候做点事情
  15. postProcessBeanFactory(beanFactory);
  16. // Invoke factory processors registered as beans in the context.
  17. // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
  18. invokeBeanFactoryPostProcessors(beanFactory);
  19. // Register bean processors that intercept bean creation.
  20. // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
  21. // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
  22. // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
  23. registerBeanPostProcessors(beanFactory);
  24. // Initialize message source for this context.
  25. // 初始化当前 ApplicationContext 的 MessageSource, 国际化等
  26. initMessageSource();
  27. // Initialize event multicaster for this context.
  28. // 初始化当前 ApplicationContext 的事件广播器
  29. initApplicationEventMulticaster();
  30. // Initialize other special beans in specific context subclasses.
  31. // 从方法名就可以知道,典型的模板方法(钩子方法),
  32. // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
  33. onRefresh();
  34. // Check for listener beans and register them.
  35. // 注册监听,监听器需要实现 ApplicationListener 接口
  36. registerListeners();
  37. // Instantiate all remaining (non-lazy-init) singletons.
  38. // 初始化所有的singletons , non-lazy除外
  39. // 主要方法
  40. finishBeanFactoryInitialization(beanFactory);
  41. // Last step: publish corresponding event.
  42. // 最后一步,发布事件广播
  43. finishRefresh();
  44. }
  45. catch (BeansException ex) {
  46. if (logger.isWarnEnabled()) {
  47. logger.warn("Exception encountered during context initialization - " +
  48. "cancelling refresh attempt: " + ex);
  49. }
  50. // Destroy already created singletons to avoid dangling resources.
  51. destroyBeans();
  52. // Reset 'active' flag.
  53. cancelRefresh(ex);
  54. // Propagate exception to caller.
  55. throw ex;
  56. }
  57. finally {
  58. // Reset common introspection caches in Spring's core, since we
  59. // might not ever need metadata for singleton beans anymore...
  60. resetCommonCaches();
  61. }
  62. }
  63. }

obtainFreshBeanFactory()方法

1、初始化 BeanFactory-》DefaultListableBeanFactory.class

  1. DefaultListableBeanFactory beanFactory = createBeanFactory();

2、定义工厂的属性: 是否允许 Bean 覆盖、是否允许循环引用

3、加载 Bean 到 BeanFactory 中 -》 loadBeanDefinitions()方法

​ 3.1 读取xml配置文件,检查,解析

  1. preProcessXml(root); //钩子
  2. parseBeanDefinitions(root, this.delegate); //主要代码:将信息放在Factory的相关map中
  3. postProcessXml(root); //钩子

​ 3.2 将xml配置文件的信息放到工厂的map里。

​ parseBeanDefinitions() => DefaultListableBeanFactory.class的registerBeanDefinition()方法

  1. this.beanDefinitionMap.put(beanName, beanDefinition);
  2. // beanName的集合,和Map的key(beanName)对应
  3. this.beanDefinitionNames.add(beanName);

具体不细讲,简述一下过程,就是factory有几个map,这里将xml里读出来的对象以Map<beanName, beanDefinition>的形式存储。

以及一个list保存了所有的beanName。

beanDefinition只是一个类的描述而已,和我们需要的对象还差了一大截。

4、返回携带各种信息的factory

finishBeanFactoryInitialization()方法

根据factory初始化所有的singletons , non-lazy除外

1、初始化特殊类,不展开啦。

2、缓存。还是DefaultListableBeanFactory.class。把之前我们上面讲到的带beanName的List转为数组保存到frozenBeanDefinitionNames里。

  1. public void freezeConfiguration() {
  2. this.configurationFrozen = true;
  3. this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
  4. }

3、初始化。

​ 3.1 拿到带beanName的List,遍历循环

  1. List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

​ 3.2 特殊类FactoryBean等特殊处理,不展开了。

​ 3.3 进入对象实例化。

AbstractBeanFactory类的doGetBean()方法

AbstractAutowireCapableBeanFactory类的doCreateBean()

  1. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
  2. throws BeanCreationException {
  3. ...
  4. if (instanceWrapper == null) {
  5. // 这里实例化 Bean,
  6. instanceWrapper = createBeanInstance(beanName, mbd, args);
  7. }
  8. ...
  9. }

AbstractAutowireCapableBeanFactory类的createBeanInstance()

  1. protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
  2. // Make sure bean class is actually resolved at this point.
  3. // 确保已经加载了此 class
  4. Class<?> beanClass = resolveBeanClass(mbd, beanName);
  5. // 校验一下这个类的访问权限
  6. if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
  7. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
  8. "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
  9. }
  10. if (mbd.getFactoryMethodName() != null) {
  11. // 采用工厂方法实例化,注意,不是 FactoryBean
  12. return instantiateUsingFactoryMethod(beanName, mbd, args);
  13. }
  14. // Shortcut when re-creating the same bean...
  15. // 如果不是第一次创建,比如第二次创建 prototype bean。
  16. // 这种情况下,我们可以从第一次创建知道,采用无参构造函数,还是构造函数依赖注入 来完成实例化
  17. boolean resolved = false;
  18. boolean autowireNecessary = false;
  19. if (args == null) {
  20. synchronized (mbd.constructorArgumentLock) {
  21. if (mbd.resolvedConstructorOrFactoryMethod != null) {
  22. resolved = true;
  23. autowireNecessary = mbd.constructorArgumentsResolved;
  24. }
  25. }
  26. }
  27. if (resolved) {
  28. if (autowireNecessary) {
  29. // 构造函数依赖注入
  30. return autowireConstructor(beanName, mbd, null, null);
  31. }
  32. else {
  33. // 无参构造函数
  34. return instantiateBean(beanName, mbd);
  35. }
  36. }
  37. // Candidate constructors for autowiring?
  38. // 判断是否采用有参构造函数
  39. Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
  40. if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
  41. mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
  42. // 构造函数依赖注入
  43. return autowireConstructor(beanName, mbd, ctors, args);
  44. }
  45. // No special handling: simply use no-arg constructor.
  46. // 调用无参构造函数
  47. return instantiateBean(beanName, mbd);
  48. }

AbstractAutowireCapableBeanFactory类的instantiateClass()

  1. protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
  2. try {
  3. Object beanInstance;
  4. final BeanFactory parent = this;
  5. if (System.getSecurityManager() != null) {
  6. beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
  7. @Override
  8. public Object run() {
  9. return getInstantiationStrategy().instantiate(mbd, beanName, parent);
  10. }
  11. }, getAccessControlContext());
  12. }
  13. else {
  14. // 实例化
  15. beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
  16. }
  17. // 包装一下,返回
  18. BeanWrapper bw = new BeanWrapperImpl(beanInstance);
  19. initBeanWrapper(bw);
  20. return bw;
  21. }
  22. catch (Throwable ex) {
  23. throw new BeanCreationException(
  24. mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
  25. }
  26. }
  1. public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
  2. Assert.notNull(ctor, "Constructor must not be null");
  3. try {
  4. ReflectionUtils.makeAccessible(ctor);
  5. return ctor.newInstance(args); //构造函数初始化对象
  6. }
  7. ...
  8. }

最后

感谢你看到这里,文章有什么不足还请指正,觉得文章对你有帮助的话记得给我点个赞,每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!

面试官:就问个Spring容器初始化和Bean对象的创建,你讲一小时了的更多相关文章

  1. Spring 中初始化一个Bean对象时依赖其他Bean对象空指针异常

    1. Bean依赖关系 一个配置类的Bean,一个实例Bean: 实例Bean初始化时需要依赖配置类的Bean: 1.1 配置类Bean @ConfigurationProperties(prefix ...

  2. Spring管理Filter和Servlet(在servlet中注入spring容器中的bean)

    在使用spring容器的web应用中,业务对象间的依赖关系都可以用context.xml文件来配置,并且由spring容器来负责依赖对象 的创建.如果要在servlet中使用spring容器管理业务对 ...

  3. 【String注解驱动开发】面试官让我说说:如何使用FactoryBean向Spring容器中注册bean?

    写在前面 在前面的文章中,我们知道可以通过多种方式向Spring容器中注册bean.可以使用@Configuration结合@Bean向Spring容器中注册bean:可以按照条件向Spring容器中 ...

  4. 厉害!这份阿里面试官 甩出的Spring源码笔记,GitHub上已经爆火

    前言 时至今日,Spring 在 Java 生态系统与就业市场上,面试出镜率之高,投产规模之广,无出其右.随着技术的发展,Spring 从往日的 IoC 框架,已发展成 Cloud Native 基础 ...

  5. JVM工作原理和特点(一些二逼的逼神面试官会问的问题)

    作为一种阅读的方式了解下jvm的工作原理 ps:(一些二逼的逼神面试官会问的问题) JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.exe来完毕,通过以下4步来完毕JVM环境. ...

  6. spring容器初始化执行某个方法

    在做web项目开发中,尤其是企业级应用开发的时候,往往会在工程启动的时候做许多的前置检查. 比如检查是否使用了我们组禁止使用的Mysql的group_concat函数,如果使用了项目就不能启动,并指出 ...

  7. 当spring 容器初始化完成后执行某个方法

    在做web项目开发中,尤其是企业级应用开发的时候,往往会在工程启动的时候做许多的前置检查. 比如检查是否使用了我们组禁止使用的Mysql的group_concat函数,如果使用了项目就不能启动,并指出 ...

  8. 当spring 容器初始化完成后执行某个方法 防止onApplicationEvent方法被执行两次

    在做web项目开发中,尤其是企业级应用开发的时候,往往会在工程启动的时候做许多的前置检查. 比如检查是否使用了我们组禁止使用的Mysql的group_concat函数,如果使用了项目就不能启动,并指出 ...

  9. spring容器初始化bean和销毁bean之前进行一些操作的定义方法

    关于在spring  容器初始化 bean 和销毁前所做的操作定义方式有三种:        第一种,通过在xml中定义init-method和destory-method方法        第二种, ...

随机推荐

  1. Helium文档6-WebUI自动化-S用于通过id\name\classname\xpth定位元素

    前言 S方法可以灵活定位元素特别注意,比如to_left_of参数的使用是查找在某个元素左侧的元素,但是默认只会找第一个S方法可以灵活运用,特别是没有id,没有name,只有classname的情况, ...

  2. Django采坑日志(django2.0)

    使用Mariadb时出现的问题 "Unknown system variable 'transaction_isolation'" 解决办法:修改django/db/backend ...

  3. Spring笔记(5) - 声明式事务@EnableTransactionManagement注解源码分析

    一.背景 前面详解了实现Spring事务的两种方式的不同实现:编程式事务和声明式事务,对于配置都使用到了xml配置,今天介绍Spring事务的注解开发,例如下面例子: 配置类:注册数据源.JDBC模板 ...

  4. Graph-to-ID task

    首先图像是一个二维的结构,CNN提取图片的特征,但是是local的,通过kenel的形式,不断的图上移动,通过卷积的形式, 无论移动到哪个位置,内部的结构都是不变的,这就是参数共享. 这个所说的图像显 ...

  5. window.open浏览器弹出新窗口被拦截—原因分析和解决方案

    最近在做项目的时候碰到了使用window.open被浏览器拦截的情况,在本机实验没问题,到了服务器就被拦截了,火狐有拦截提示,360浏览器拦截提示都没有,虽然在自己的环境可以对页面进行放行,但是对用户 ...

  6. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

  7. centos8 curl: (35) error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small

    centos8操作系统,curl -k https:/www.xxx.com 报错  curl: (35) error:141A318A:SSL routines:tls_process_ske_dh ...

  8. 4G DTU模块和串口设备连接的方式

    首先说下解决思路: 由于考虑到串口开发很麻烦,所以后来买了一个4g模块的dtu. 所以最后的解决方案是,plc串口设备与dtu相连,由于dtu是透传模式,使用java与4g模块进行通信就完事了. 虽然 ...

  9. TCP/IP 基础知识

    我把自己以往的文章汇总成为了 Github ,欢迎各位大佬 star https://github.com/crisxuan/bestJavaer 已提交此篇文章 要说我们接触计算机网络最多的协议,那 ...

  10. websocket报400错误

    解决方案看了下讨论区说的方案,问题出现在nginx的配置文件,需要修改nginx.conf文件.在linux终端中敲入vim /etc/nginx/nginx.conf,找到location这个位置, ...