自动配置[源码分析] - 自动配置包原理

自动配置[源码分析] - 自动配置包


这里的自动配置包就是指的启动类所在包, 为什么我们会将该包下的所有类进行一个扫描?

首先我们要看自动配置原理, 肯定是从@SpringBootApplication注解开始:

这个注解就会为我们一步一步解开SpringBoot的自动配置原理

  • 所有的特性都是在源码中有体现的, 都是程序员写的

@SpringBootApplication注解源码:

/*
 * Copyright 2012-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;
import org.springframework.data.repository.Repository;

/**
 * Indicates a {@link Configuration configuration} class that declares one or more
 * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration
 * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience
 * annotation that is equivalent to declaring {@code @Configuration},
 * {@code @EnableAutoConfiguration} and {@code @ComponentScan}.
 *
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @author Andy Wilkinson
 * @since 1.2.0
 */
@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 {
 ...
}

可以看到我们的@SpringBootApplication注解是一个合成注解

那么除了元注解, 我们就看以下的几个注解:

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
1. @SpringBootConfiguration注解

该注解点入到源码中可以发现其实就是一个@Configuration注解, 那么也就时标记为一个配置类, 也就是将当前类标记为主配置类

  • @SpringBootConfiguration注解源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
    ...
}
2.@ComponentScan (excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
	@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

该注解就配置了一个包扫描, 只不过是一个比较特殊的包扫描, 特殊在是使用了TypeFilter指定了一个包扫描规则

  • 细心的人可以发现这里并没有指明包扫描的位置, 那么报扫描的位置是在哪里指定的?
  • 其实是在@EnableAutoConfiguration注解中:
3.@EnableAutoConfiguration注解

@EnableAutoConfiguration注解源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ...
}

可以看到@EnableAutoConfiguration注解也是一个合成注解

我们先来看:

  1. @AutoConfigurationPackage注解:

    • 根据名称我们就能推导出这个注解的功能, 就是自动配置包, 那么就是我们本篇文章的核心了, 那么是如何自动配置包的? 我们就来看一下这个注解的源码:

    • @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      @Inherited
      @Import(AutoConfigurationPackages.Registrar.class)
      public @interface AutoConfigurationPackage {
          ...
      }
      

      可以看到该注解其实是一个@Import注解, 那么这个Import注解的功能又是什么?

      • 我们知道@Import注解的功能是导入一个组件, 那么这里导入的组件是什么?

      • 我们点入到AutoConfigurationPackages.Registrar.class类中查看一下

        • 这里其实是@Import注解的一个高级用法, @Import高级 : 使用@ImportBeanDefinitionRegister, 这就是我们自定义了一个类, 使用该类中的方法可以手动完成对组件的注册, 我们点击到源码中可以看到:

        • static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
          
          		@Override
          		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
          			register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
          		}
          
          		@Override
          		public Set<Object> determineImports(AnnotationMetadata metadata) {
          			return Collections.singleton(new PackageImports(metadata));
          		}
          
          	}
          

          可以看到有一个registerBeanDefinitions()方法, 该方法中使用registry对象注册了对应的一些组件, 那么是注册了哪些组件?

          • new PackageImports(metadata).getPackageNames().toArray(new String[0])其实就是获取的注解所在的类的元信息, 通过这些元信息, 就可以获取到该类所在的包, 然后直接对这个包中的所有组件都进行了注册, 也就是导入到了容器中
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值