spring--AnnotationConfigApplicationContext扫描bean过程源码分析

AnnotationConfigApplicationContext

前言

AnnotationConfigApplicationContext 和 ClassPathXmlApplicationContext 与 FileSystemXmlApplicationContext 类似都是抽象类 AbstractApplicationContext 的子类,最终都调用父类的 refresh 方法开始 bean工厂的初始化等一系列操作,不同的是 AnnotationConfigApplicationContext 是通过注解进行bean扫描的,而另外两个是通过xml进行bean注册的,接下来我们看看 AnnotationConfigApplicationContext 是怎么扫描bean的,附结构图
在这里插入图片描述

使用说明

  1. 测试bean
    import org.springframework.stereotype.Component;
    
    @Component
    public class TestBean {
         
         
    
        public String test() {
         
         
            return "test";
        }
    }
    
  2. 启动类
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class DemoApplication {
         
         
    
        public static void main(String[] args) {
         
         
    
            AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext("com.example.demo");
            TestBean testBean = annotationConfigApplicationContext.getBean(TestBean.class);
            System.out.println(testBean.test());
        }
    }
    

源码解析

我们通过创建 AnnotationConfigApplicationContext 类并传入项目包名即可获取到这个包及子包下的bean了,我们看一下 的构造器方法

  1. 构造器

    	public AnnotationConfigApplicationContext(String... basePackages) {
         
         
    		this();
    		scan(basePackages);
    		refresh();
    	}
    

    主要分三部分,1、调用无参构造器,2、根据传入的包名进行bean扫描,3、调用父类的refresh方法,这里我们主要关注1、2两步

  2. 无参构造器

    	public AnnotationConfigApplicationContext() {
         
         
    		// 该类用于传入指定bean的类的时候使用,会直接进行beanDefinition注册
    		this.reader = new AnnotatedBeanDefinitionReader(this);
    		// 该类用于通过类路径进行扫描并将符合的bean进行beanDefinition注册
    		this.scanner = new ClassPathBeanDefinitionScanner(this);
    	}
    

    通过指定包名创建 AnnotationConfigApplicationContext 类时就是通过 scanner 进行扫描的,注意这里会传入 this 参数,不管是直接指定bean的类进行注册还是扫描注册,实际上是注册到类 DefaultListableBeanFactory 的 beanDefinitionMap(重要) 参数上,参数类型为
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    而 DefaultListableBeanFactory 是 this 的父类 GenericApplicationContext 进行初始化的,我们知道,子类初始化时会先初始化父类

    	public GenericApplicationContext() {
         
         
    		this.beanFactory = new DefaultListableBeanFactory();
    	}
    
  3. 扫描bean

    	@Override
    	public void scan(String... basePackages) {
         
         
    		Assert.notEmpty(basePackages, "At least one base package must be specified");
    		// 委托给 scanner 进行扫描
    		this.scanner.scan(basePackages);
    	}
    
    	public int scan(String... basePackages) {
         
         
    		// 1.先获取已注册的beanDefinition数量
    		int beanCountAtScanStart = this.registry.getBeanDefinitionCount()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值