1. 程式人生 > >Spring Boot自動配置註解@EnableAutoConfiguration解密

Spring Boot自動配置註解@EnableAutoConfiguration解密

  Spring boot為了自動配置,增加了註解@EnableAutoConfiguration。一般只需要配置@SpringBootApplication即可,為什麼呢?

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class
), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {

  很明顯的,這個註解就是三個常用在一起的註解@SpringBootConfiguration@EnableAutoConfiguration以及@ComponentScan的組合。
  @SpringBootConfiguration這個註解實際上和@Configuration有相同的作用,配備了該註解的類就能夠以JavaConfig的方式完成一些配置,可以不再使用XML配置。
  @ComponentScan

這個註解完成的是自動掃描的功能,相當於Spring XML配置檔案中的:<context:component-scan>,可以使用basePackages屬性指定要掃描的包,以及掃描的條件。如果不設定的話預設掃描@ComponentScan註解所在類的同級類和同級目錄下的所有類,所以對於一個Spring Boot專案,一般會把入口類放在頂層目錄中,這樣就能夠保證原始碼目錄下的所有類都能夠被掃描到。
  @EnableAutoConfiguration註解程式碼如下:

@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention
(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {

  這個註解是讓Spring Boot的配置能夠如此簡化的關鍵性註解。尤其是@Import註解中的那個EnableAutoConfigurationImportSelector.class。那麼這個註解到底是怎麼生效的呢?

  在SpringApplication的run方法中,會調context = createApplicationContext();在例項化這個ConfigurableApplicationContext時,不管是AnnotationConfigEmbeddedWebApplicationContextAnnotationConfigApplicationContext時(這兩個類是專門處理Spring註解方式配置的容器,直接依賴於註解作為容器配置資訊來源的IoC容器。 AnnotationConfigWebApplicationContextAnnotationConfigApplicationContext的web版本,兩者的用法以及對註解的處理方式幾乎沒有什麼差別),都會例項化一個AnnotatedBeanDefinitionReader。例如AnnotationConfigEmbeddedWebApplicationContext例項化程式碼:

    public AnnotationConfigEmbeddedWebApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

  這裡將構造AnnotatedBeanDefinitionReader,在AnnotatedBeanDefinitionReader例項化過程中,會向beanFactory註冊CommonAnnotationBeanPostProcessorAutowiredAnnotationBeanPostProcessorConfigurationClassPostProcessor等:

    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);
    }
    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, Object source) {

        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }

        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);

        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        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));
        }

        if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
        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));
        }

        // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
        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: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
            }
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        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));
        }
        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;
    }

  也就是說createApplicationContext()完後,beanFactory的beanDefinitionMap會有6個值。

  SpringApplication的run方法中,在呼叫createApplicationContext();後會呼叫prepareContext(context, environment, listeners, applicationArguments,printedBanner)

    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        // ….
        // Load the sources
        Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[sources.size()]));
        listeners.contextLoaded(context);
    }

  getSources()返回的就是new SpringApplication(Application.class)傳入的引數,即我們的主類,然後呼叫了load()方法,在load()中會生成BeanDefinitionLoader例項,並把主類註冊到IOC容器中。
  OK,到這裡即在呼叫我們熟悉的AbstractApplicationContext#refresh()前,beanFactory有7個定義好的beanDefinition。

  ConfigurationClassPostProcessorBeanFactoryPostProcessor的子類,會在Spring容器refresh時,invokeBeanFactoryPostProcessors(beanFactory)方法中呼叫到。ConfigurationClassPostProcessor會解析到我們的主類,把@Import中的類拿出來,呼叫它的selectImports()方法。
  selectImports方法在EnableAutoConfigurationImportSelector 的父類AutoConfigurationImportSelector類中:

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        try {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                    .loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            List<String> configurations = getCandidateConfigurations(annotationMetadata,
                    attributes);
            configurations = removeDuplicates(configurations);
            configurations = sort(configurations, autoConfigurationMetadata);
            Set<String> exclusions = getExclusions(annotationMetadata, attributes);
            checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = filter(configurations, autoConfigurationMetadata);
            fireAutoConfigurationImportEvents(configurations, exclusions);
            return configurations.toArray(new String[configurations.size()]);
        }
        catch (IOException ex) {
            throw new IllegalStateException(ex);
        }
    }

  getCandidateConfigurations方法就會在META-INF/spring.factories中找到獲取約定好的自動配置類(key為EnableAutoConfiguration的value)。然後Spring容器會對這些配置類進行處理。
  到此,一目瞭然,由ConfigurationClassPostProcessor來處理。@ComponentScan註解也是在ConfigurationClassPostProcessor中處理的。