Spring启动流程(一)

本文使用springframework 5.3.20版本

demo

以java-config形式编写一个测试demo,新建一个 AnnotationConfigApplicationContext,如果是XML形式使用 ClassPathXmlApplicationContext

两者都继承了 AbstractApplicationContext 类,详细看下面的层次图。

注意:在new AnnotationConfigApplicationContext()时如果未指定参数,会报运行时异常:org.springframework.context.annotation.AnnotationConfigApplicationContext@6ebc05a6 has not been refreshed yet

    @Configuration
    public class BeanConfig {
        @Bean
        public User user(){
            User user = new User();
            user.setUsername("11111");
            return user;
        }
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext cfg = new AnnotationConfigApplicationContext(BeanConfig.class);
        User user = cfg.getBean(User.class);
        System.out.println(user.getUsername());
    }

AnnotationConfigApplicationContext的有参构造执行了3个方法,分别是自己的无参构造、register()、refresh();

在描述前先从网上找了一个总体流程图方便了解一下大致流程,理清思路。

无参构造

在执行AnnotationConfigApplicationContext的无参构造方法前会调用父类GenericApplicationContext的无参构造方法;

GenericApplicationContext中实例化一个DefaultListableBeanFactory,也就是说bean工厂实际上是应用上下文的一个属性;

从上面的类层次图可以看到:应用上下文和bean工厂又同时实现了BeanFactory接口。

  • DefaultListableBeanFactory中的beanDefinitionMap属性用来保存BeanName对应的BeanDefinition对象,beanDefinitionNames属性保存beanName。

    • private final Map<String, BeanDefinition> beanDefinitionMap;
    • private volatile List beanDefinitionNames;

前面讲到我们为了解IOC使用了Spring提供的AnnotationConfigApplicationContext作为入口展开,那Spring怎么对加了特定注解(如 @Service、@Repository)的类进行读取转化成 BeanDefinition 对象呢?

  • BeanDefinition 是 Spring 中极其重要的一个概念,它是一个描述bean的类,它存储了 bean 对象的所有特征信息,如该bean对应的类的全类名是什么,该bean的beanName(就是xml文件中那个id)是否单例,是否懒加载,factoryBeanName 等,我们最终实例化对象,就是跟据这个BeanDefinition中的描述信息进行的。

又如何对指定的包目录进行扫描查找 bean 对象呢?

所以我们需要new一个注解配置读取器和一个路径扫描器。

AnnotatedBeanDefinitionReader中执行了AnnotationConfigUtils中的registerAnnotationConfigProcessors(this.registry)方法,会向容器注册Sprign内置的处理器。

registerAnnotationConfigProcessors方法中通过 new RootBeanDefinition(XX.class) 新建一个RootBeanDefinition(BeanDefinition的一个实现),然后调用registerPostProcessor将内置bean对应的BeanDefinition保存到bean工厂中;

这里需要说明的是:我们刚刚一直在谈到注册bean,实际上就是将内置bean对应的beanDefinition保存到bean工厂中。那为什么要保存beanDefinition呢?因为Spring是跟据beanDefinition中对bean的描述,来实例化对象的,就算自己定义的bean也是要被解析成一个beanDefinition并注册的。

其中最主要的组件便是 ConfigurationClassPostProcessor 和 AutowiredAnnotationBeanPostProcessor ,前者是一个 beanFactory 后置处理器,用来完成 bean 的扫描与注入工作,后者是一个 bean 后置处理器,用来完成 @AutoWired 自动注入。

register

这个步骤主要是用来解析用户传入的 Spring 配置类,解析成一个 BeanDefinition 然后注册到容器中,主要源码如下:

通过生成AnnotatedGenericBeanDefinition,然后解析给BeanDefinition的其他属性赋值,然后将BeanDefinition和beanName封装成一个BeanDefinitionHolder对象注册到bean工厂中(就是将beanName与baenDefinition封装到Map中,将beanName放到list中。Map与list都是bean工厂DefaultListableBeanFactory所维护的属性),和前面内置bean的注册相同。

执行到这一步,register方法到此就结束了,通过断点观察BeanFactory中的beanDefinitionMap属性可以看出: this()和this.register(componentClasses)方法中就是将内置bean和我们传的配置bean的beanDefinition进行了注册,还没处理标记了@Component等注解的自定义bean。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值