7.AnnotatedBeanDefinitionReader的作用


highlight: arduino-light

```java Appconfig.java @ComponentScan("com.yuanma.beanDefinition") @Configuration public class Appconfig { }

X.java @Component public class X { public X(){ System.out.println("X Constructor"); } }

Y.java public class Y { }

Test.java public class Test{ public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); ac.register(Appconfig.class); ac.refresh(); } } ```

java public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); applicationContext.register(Appconfig.class); applicationContext.refresh(); }

首先通过一张图简单的理解一下spring容器启动的时候执行调用BeanFactoryPostProcessor后置处理器的大概的方法执行顺序:

image.png

上图大概分为④步(这里只是讨论spring如何调用BeanFactoryPostProcessor,在调用之前到底执行了那些方法,上图并不是spring容器启动的所有步骤)

步骤1:启动main方法

①启动main方法。

步骤2:实例化Context,注册内置处理器

②在main方法里面调用AnnotationConfigApplicationContext的无参构造方法。

```java public AnnotationConfigApplicationContext() {

//调用构造方法时需要首先调用父类GenericApplicationContext的构造方法 //在父类的构造方法里会初始化一个DefaultListableBeanFactory //this.beanFactory = new DefaultListableBeanFactory();     //创建一个BeanDefinition读取器 可以根据注解读取BeanDefinition this.reader = new AnnotatedBeanDefinitionReader(this);

//创建一个BeanDefinition扫描器 能够扫描一个类或者包 转换成bd
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

```

2.1实例化DefaultListableBeanFactory

AnnotationConfigApplicationContext继承自GenericApplicationContext,所以调用自己之前会先调用父类GenericApplicationContext的构造方法。

java public GenericApplicationContext() {   this.beanFactory = new DefaultListableBeanFactory(); }

2.2实例化AnnotatedBeanDefinitionReader

java this.reader = new AnnotatedBeanDefinitionReader(this);

java public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { //registry 代表的是AnnotationConfigApplicationContext this(registry, getOrCreateEnvironment(registry)); }

2.2.1构造方法注册了2个BFPP2个BPP

这里很重要,因为ConfigurationClassPostProcessor就是在这里被注入的,当前只是先看一下,后面细讲!

```java public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry,Environment environment){ Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(environment, "Environment must not be null"); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);

/*
    这里很重要 因为ConfigurationClassPostProcessor就是在这里被注入的!
    这里很重要 因为ConfigurationClassPostProcessor就是在这里被注入的!
    这里很重要 因为ConfigurationClassPostProcessor就是在这里被注入的!
    //BeanFactoryPostProcessor
    RootBeanDefinition def = new                                    
            RootBeanDefinition(ConfigurationClassPostProcessor.class);

    //BeanPostProcessor
    RootBeanDefinition def = new 
            RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);

    //BeanPostProcessor
    RootBeanDefinition def = new 
            RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);

    //EventListenerMethodProcessor
    RootBeanDefinition def = new 
                RootBeanDefinition(EventListenerMethodProcessor.class);

    RootBeanDefinition def = new 
                RootBeanDefinition(DefaultEventListenerFactory.class);
    */
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

```

2.3实例化了ClassPathBeanDefinitionScanner

这个对象顾名思义就是能够用来完成spring的classpath的扫描功能。

java //创建一个BeanDefinition扫描器 能够扫描一个类或者包 转换成bd this.scanner = new ClassPathBeanDefinitionScanner(this);

在这里创建了但是并没有用到,只有使用下面的构造方法才能用到。

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

这里提一句:在扫描我们指定的包路径的时候用的是AnnotationConfigApplicationContext的构造方法中构造的ClassPathBeanDefinitionScanner。但是spring内部完成扫描功能并不是用的这个对象,而是在扫描的时候会new新的ClassPathBeanDefinitionScanner对象。

换言之,这里在AnnotationConfigApplicationContext的构造方法中new的对象我们假设他为a,但是spring在真正完成扫描的时候会new一个b,它们是同一个类都是ClassPathBeanDefinitionScanner,为什么需要两个?

1.每个scaner的includeFilter和excludeFilter属性不相同,扫描的包的路径也不同。所以需要不同的参数构造不同的ClassPathBeanDefinitionScanner

2.每个@ConponentScan的包含过滤器和排除过滤器不一样,是独一无二的 需要把每个@ConponentScan的包含过滤器和排除过滤器 复制到对应的ClassPathBeanDefinitionScanner扫描器中

步骤3:注册配置类为BeanDefintion

java applicationContext.register(Appconfig.class);

java @Override public void register(Class<?>... componentClasses) { Assert.notEmpty(componentClasses, "At least one component class must be specified"); //使用AnnotatedBeanDefinitionReader 读取器 注册bd this.reader.register(componentClasses); }

可以看到会把Appconfig类解析成为一个beanDefintion对象。

这里其实涉及到AnnotatedBeanDefinitionReader对象的意义,给解析出来的beanDefinition对象设置一些默认属性,继而put到beanDefintionMap当中。

为什么需要put到beanDefintionMap呢?

在上一篇我们已经解释过这个map就是单纯用来存储beanDefinition的,spring后面会遍历这个map根据map当中的beanDefinition来实例化bean,如果Appconfig类的beanDefintion存在map当中那么他必然会被spring容器实例化成为一个bean。

为什么Appconfig会需要实例化呢?

因为Appconfig当中有很多加了@Bean的方法,这些方法需要被调用,故而需要实例化,但是Appconfig类的实例化很复杂比一般类实例化过程复杂很多,涉及到代理涉及到cglib等等,这个我们后面文章解释。

为什么Appconfig类是通过register(Appconfig.class);手动put到map当中呢?为什么不是扫描出来的呢?

其实也很简单,普通的类都是通过扫描出来的。但是因为Appconfig无法扫描自己,普通的类是spring通过解析Appconfig上的@ComponentScan注解然后被扫描到,但是配置类无法扫描自己,相当于是1个入口方法。

也就是Spring需要扫描哪些包是通过配置类来配置的,所以配置类相当于是1个入口。通过扫描配置类配置的扫描包扫描出来的类就是普通类。当然这些普通类上面也可能配置了扫描包或者导入了其他的xml配置。这个时候这些普通类也会被当做配置类处理,这是1个递归的过程。

步骤4:后面分析

接下来便是第④步,④-1到④-4以后分析。

步骤5:执行spring中的bean工厂后置处理器

④-5便是我们上篇文章说的执行spring当中的bean工厂后置处理器,也是本文重点讨论的;下图是对上述文字的一个说明——spring容器启动的执行顺序:

24117616-0ab4ad768d97945a.gif

AnnotatedBeanDefinitionReader作用

先看一下这个类的javadoc,看看作者怎么来解释这个类的,这个类作用分为以下两个。

作用一:动态注册带注解的bean

可用于编程式动态注册一个带注解的bean,什么意思呢?

比如我们有一个类A存在com.shadow包下面,并且是一个加注解的类。比如加了@Component,正常情况下这个类A是可以被spring扫描出来的,但是有不正常情况,比如spring并没有扫描到com.shadow包,那么类A就无法被容器实例化。

有人可能会问为什么没有扫描到com.shadow包?什么情况下不会扫描到?

1.假设这个类是动态生成,在容器实例化的时候不存在那么肯定不存在.

2.包下有N多类但是只有一个类加了注解,那么其实你不需要去扫描,只需要使用AnnotatedBeanDefinitionReader去注册这个类即可。

3.某个类是你和第三方系统交互后得到的。那么这个时候我们可以把这个类通过AnnotatedBeanDefinitionReader的register(Class clazz)方法把一个带注解的类注册给spring。

这里的注册其实就是上一篇文章中说的把一个类解析成BeanDefintion对象,然后把这个对象put到beanDefinitionMap当中。

作用二:注册配置类

AnnotatedBeanDefinitionReader可以代替ClassPathBeanDefinitionScanner这个类,具备相同的注解解析功能。

ClassPathBeanDefinitionScanner是spring完成扫描的核心类,这个我后面会分析。

简而言之,spring完成扫描主要是依靠ClassPathBeanDefinitionScanner这个类的对象,但是AnnotatedBeanDefinitionReader可以替代他完成相同的注解解析,意思就是通过ClassPathBeanDefinitionScanner扫描出来的类A和通过AnnotatedBeanDefinitionReader显式注册的类A在spring内部会一套相同的解析规则。

那么AnnotatedBeanDefinitionReader除了动态显示注册一些spring扫描不到的类之外还有什么功能?

在初始化spring容器的过程中他主要干了什么事情呢?

或者这么说:假设程序中没有需要动态显示注册的类他就没用了吗?

再或者AnnotatedBeanDefinitionReader这个类的对象除了注册一些自己的类还有什么应用场景呢?

答案是作为读取器,注册我们的配置类,所谓的配置类就是那个加了@Configuration和@ComponentScan的那个类。也就是Appconfig.java。

那么问题来了,为什么配置类需要手动注册呢?

很简单,因为配置类无法扫描出来,所以需要我们手动注册。为什么无法扫描呢?

比如spring完成扫描是需要解析Appconfig.java当中的@ComponentScan注解的值(一般是一个包名),得到这个值之后去扫描这个值所代表的包下面的所有bean。

简单的说就是spring如果想要完成扫描。必须先提供Appconfig.java,所以Appconfig.java要在一开始就手动注册给spring,spring得到Appconfig.class之后把他解析成BeanDefintion对象,继而去获取@ComponentScan的值然后才能开始扫描其他bean。

```java public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Appconfig.class); }

//可以发现构造方法里已经帮我们做了register和refresh和文章开头的并无区别。 public AnnotationConfigApplicationContext(Class>... componentClasses) { this(); this.register(componentClasses); this.refresh(); } ```

除了使用上面这种方式,也可以通过以下方式指定扫描的包名。

```java @Configuration public class AppConfig { public AppConfig() { System.out.println("AppConfig开始被构造"); }

@Bean
    public Object getObject(){
        return new Object();
    }
}

```

```java AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("指定扫描的包名");

//我们可以看到也可以使用扫描器扫描到AppConfig
public AnnotationConfigApplicationContext(String... basePackages) {
        this();
        scan(basePackages);
        refresh();
    }

```

如何注册

针对AnnotatedBeanDefinitionReader应用场景的第2点,我在啰嗦几句,一般程序员在初始化spring容器的时候代码有很多种写法,但都是换汤不换药的,我这里举2个例子:

第一种写法

java AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); //动态注册一个配置类 通过配置类来进行扫描包配置 ac.register(Appconfig.class); //调用refresh方法 //这里很多资料都叫做刷新spring容器 //但是我觉得不合适,这是硬核翻译,比较生硬 //笔者觉得理解为初始化spring容器更加精准 //至于为什么以后慢慢更新再说 ac.refresh();

第二种写法

java AnnotationConfigApplicationContext ac =        new AnnotationConfigApplicationContext(Appconfig.class);

这两种写法都初始化spring容器,代码上的区别无非就是:

第一种写法是调用AnnotationConfigApplicationContext()的无参构造方法。

第二种写法是调用了AnnotationConfigApplicationContext(Class\>... annotatedClasses)有参构造方法。

但是你如果翻阅源码,第二种写法的内部也是首先调用无参构造方法的,内部继续调用register(Appconfig.class)方

法,最后调用refresh()方法。和第一种写法的区别是register和refresh是程序员调用的。

笔者更推荐第一种写法,因为第一种写法可以在初始化spring容器之前得到AnnotationConfigApplicationContext的对象也就是代码里面的ApplicationContext对象。

其实第一种方法和第二种方法都可以得到ApplicationContext对象,那么为什么第一种写法笔者推荐呢?

首先第二种方法是在spring容器完成初始化之后的到的ac对象,容器已经初始化了,这个时候得到这个对象能干了事情少了很多,第一种方法在初始化之前得到的,那么能干的事情可多了。

①比如我们可以在容器初始化之前动态注册一个自己的bean,就是上文提到的 AnnotatedBeanDefinitionReader的应用场景,

②再比如可以利用ApplicationContext对象来关闭或者开启spring的循环依赖,

③还比如程序员可以在容器初始化之前注册自己实例化的BeanDefinition对象。如果你精通spring源码你会发觉提前得到这个ApplicationContext对象可以做的事情太多了,笔者这里说的三个比如都必须在spring容器初始化之前做才有意义,简而言之就是需要在spring调用refresh方法之间做才有意义。

AnnotatedBeanDefinitionReader源码

ConfigurationClassPostProcessor对应的BeanDefinition就是在AnnotatedBeanDefinitionReader构造的。

我们看下AnnotatedBeanDefinitionReader具体做了什么,看这个构造方法,传入的是一个BeanDefinitionRegistry类型,就是可以注册BeanDefinition的,内部要注册就需要用到:

java public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { //registry 代表的是AnnotationConfigApplicationContext this(registry, getOrCreateEnvironment(registry)); }

getOrCreateEnvironment获得或者创建环境,如果BeanDefinitionRegistry是EnvironmentCapable的话就可以直接获取,否则就创建一个标准环境,其实就是获取一些系统的变量。

比如可以配置dev环境,test环境,pro环境等等。

java private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry){ Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); if (registry instanceof EnvironmentCapable) { return ((EnvironmentCapable) registry).getEnvironment(); } return new StandardEnvironment(); }

接下来执行的是这一句代码:this(registry, getOrCreateEnvironment(registry));

继续看AnnotatedBeanDefinitionReader另一个构造方法:

java public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment){ Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(environment, "Environment must not be null"); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); //关键代码 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); }

前面4句代码是在断言判空和赋值。对BeanDefinitionRegistry进行了保存和把environment封装进了ConditionEvaluator,ConditionEvaluator可以理解成一个条件过滤器,与@Conditional有关,如果有了这个注解,就先判断条件成不成立,不成立的话有些操作就不做了。

registerAnnotationConfigProcessors

最重要的操作是registerAnnotationConfigProcessors。registerAnnotationConfigProcessors一看方法就知道要加一些处理器,来处理我们的注解配置,也就是说,spring有些内部的处理器需要注册进来,这里可以想到spring应该是为了统一处理处理器,所以也是按注册,处理这样的流程来,无论是自己内部的,还是用户自定义的,我们来看看里面是怎么做的,我们跟进这个方法的源码:

```java public static Set registerAnnotationConfigProcessors(            BeanDefinitionRegistry registry, @Nullable Object source) {

// 获取beanFactory也就是DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = 
                                unwrapDefaultListableBeanFactory(registry);
    
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() 
                                instanceof AnnotationAwareOrderComparator)) {
                /**
                 * AnnotationAwareOrderComparator主要能解析@Order和@Priority
                 */
                beanFactory.setDependencyComparator
                            (AnnotationAwareOrderComparator.INSTANCE);
            }
            if (!(beanFactory.getAutowireCandidateResolver() 
                        instanceof ContextAnnotationAutowireCandidateResolver)) {
                /**
                 * ContextAnnotationAutowireCandidateResolver提供处理延迟加载的功能
                 */
                beanFactory.setAutowireCandidateResolver
                                (new ContextAnnotationAutowireCandidateResolver());
            }
        }
​
        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
        /**
         *  下面非常非常重要
         *  spring默认的BeanDefinition的注册,很重要,需要理解每个bean的类型
        */
    
        /*  
         *  1.注册ConfigurationClassPostProcessor对应的bd
         *  注册的bd的名字是internalConfigurationAnnotationProcessor
         *  ConfigurationClassPostProcessor是一个工厂后置处理器
         *  这个后置处理器非常重要,基本上类上面的注解都在这里面判断并解析
         *  spring的包扫描也在里面完成
         */
   if(!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)){
            RootBeanDefinition def = new 
                        RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            //添加ConfigurationClassPostProcessor对应的bd
            beanDefs.add(registerPostProcessor(
                    registry,                 
                    def,                                   
                    CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));                         }
        // 2.注册AutowiredAnnotationBeanPostProcessor
        //顾名思义就是处理@Autowired的,它是一个bean的后置处理器,在bean的属性注入的时候会用到
       if(!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new            
                    RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def,   
                                               AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }


        //3.注册CommonAnnotationBeanPostProcessor
        //顾名思义就是处理一些公共注解的,它是一个bean的后置处理器
        //可以处理@PostConstruct和@PreDestroy还有@Resource等
        //提示: 这里有一个jsr250Present校验
        if (jsr250Present && 
          !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)){
            RootBeanDefinition def = new 
                    RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def,   
                                               COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        // 4.注册PersistenceAnnotationProcessor
        if (jpaPresent &&    !registry.containsBeanDefinition
                                    (PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition();
            try {
            def.setBeanClass
            (ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                                    AnnotationConfigUtils.class.getClassLoader()));
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Cannot load optional framework class: ");
            }
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def,
                                            PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        // 5.注册EventListenerMethodProcessor
        if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new 
                        RootBeanDefinition(EventListenerMethodProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, 
                                               EVENT_LISTENER_PROCESSOR_BEAN_NAME));
        }
        // 6.注册DefaultEventListenerFactory
        if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
            RootBeanDefinition def = new 
                        RootBeanDefinition(DefaultEventListenerFactory.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, 
                                               EVENT_LISTENER_FACTORY_BEAN_NAME));
        }
        return beanDefs;
    }

```

主要流程就是获取DefaultListableBeanFactory。

1.注册AnnotationAwareOrderComparator顺序比较器,排序用的。

2.注册ContextAnnotationAutowireCandidateResolver自动装配解析器,解析自动装配相关配置用。

3.注册CommonAnnotationBeanPostProcessor 顾名思义就是处理一些公共注解的,它是一个bean的后置处理器 可以处理@PostConstruct和@PreDestroy还有@Resource等

3.注册ConfigurationClassPostProcessor,他是前面配置类处理的关键,所以这里先添加bean定义。

4.AutowiredAnnotationBeanPostProcessor,处理自动装配的。

5.EventListenerMethodProcessor和DefaultEventListenerFactory。

6.注册CommonAnnotationBeanPostProcessor。

我们再来看看AnnotatedBeanDefinitionReader的重要属性:

private final BeanDefinitionRegistry registry;
    //类名生成器
    private BeanNameGenerator beanNameGenerator = 
                                        AnnotationBeanNameGenerator.INSTANCE;
    //socpe注解解析器
    private ScopeMetadataResolver scopeMetadataResolver = new 
                                        AnnotationScopeMetadataResolver();
    //条件评估器
    private ConditionEvaluator conditionEvaluator;

可以看到,内部的bean定义全部都是用RootBeanDefinition。

至此读取器创建完成,其实就是注册了需要处理注解的处理器bean定义,此时还没有创建bean哦。后面ConfigurationClassPostProcessor发挥着很大的作用,用来解析配置类。

ClassPathBeanDefinitionScanner为什么要2个?

因为每个@ConponentScan的包含过滤器和排除过滤器不一样,是独一无二的 需要把每个@ConponentScan的包含过滤器和排除过滤器 复制到ClassPathBeanDefinitionScanner扫描器中

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值