深入分析Spring的自动配置

            背景:最近在研究Spring源码,那么当然要研究一下SpringBoot的自动配置的模块,那么SpringBoot的自动配置到底是怎么做的呢?

正文:SpringBoot的自动配置聊起来大家都并不陌生,都知道SpringBoot想对于SpringMvc来说是可以不用配置web.xml,application.xml

也就是说不用配置servlet的信息,不用配置一些引入的依赖的配置信息,那么这些其实都是依赖SpringBoot的自动配置,那么SpringBoot的

自动配置主要是依赖于DI,IOC就是Spring的容器原理以及注解的功能,那么重SpringBoot源码的入口开始看起,SpringBoot的入口当然就是

SpringBootApplication了,一个简单的代码如下:

@SpringBootApplication
public class MyApplication {

   public static void main(String[] args) {
      SpringApplication.run(MyApplication.class, args);
   }

}

这是一个最简单的SpringBoot的入口,配置好最小的配置的pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.4.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>geektime.spring.cloud</groupId>
   <artifactId>config-server</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>config-server</name>
   <description>Demo project for Spring Boot</description>

   <properties>
      <java.version>1.8</java.version>
      <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
   </dependencies>
   
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

</project>

后通过运行SpringApplication的run方法就可以启动一个SpringBoot的web程序,在国内大多的SpringBoot的程序都是为了作为web服务器,因此我们也分析作为web服务器的SpringBoot,因此SpringBoot的进程启动的入口就是对应的这个main方法,当然里面启动了Tomcat的容器,Tomcat也查找了SpringBoot的某个特定路径下的配置文件来制定启动配置类用来加载替代web.xml的配置,这里我们先来分析

@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 {

   /**
    * Exclude specific auto-configuration classes such that they will never be applied.
    * @return the classes to exclude
    */
   @AliasFor(annotation = EnableAutoConfiguration.class)
   Class<?>[] exclude() default {};

   /**
    * Exclude specific auto-configuration class names such that they will never be
    * applied.
    * @return the class names to exclude
    * @since 1.3.0
    */
   @AliasFor(annotation = EnableAutoConfiguration.class)
   String[] excludeName() default {};

另外一个注解就是@EnableConfiguration

这个注解内容如下

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

   String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

   /**
    * Exclude specific auto-configuration classes such that they will never be applied.
    * @return the classes to exclude
    */
   Class<?>[] exclude() default {};

   /**
    * Exclude specific auto-configuration class names such that they will never be
    * applied.
    * @return the class names to exclude
    * @since 1.3.0
    */
   String[] excludeName() default {};

重点的内容是@Import注解

我们为了能继续的向下看先来学习一下注解@Import顾名思义引入类加载到SpringBean的容器里面去,这个注解主要的功能是,作用在类上,通过快速导入的方式把实例加入到Spring的IOC容器中去,@Bean的方式也可以,但是@Bean的注解可以用于导入第三方的包,@Impoet的注解快速导入方式更便捷,主要分为如下三种方法

  1. 直接填写class数组方式
  2. ImportSelector方式【重点】
  3. ImportBeanDefinitionRegistrar方式

第一种方法


@Import({ 类名.class , 类名.class... })
public class TestDemo {
    
}

第二种方法

引入一个ImportSelector的实现类

public class Myclass implements ImportSelector {
//既然是接口肯定要实现这个接口的方法
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[0];
    }
}

第三种方法

public class Myclass2 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        //指定bean定义信息(包括bean的类型、作用域...)
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestDemo4.class);
        //注册一个bean指定bean名字(id)
        beanDefinitionRegistry.registerBeanDefinition("TestDemo4444",rootBeanDefinition);
    }
}

总结如下

第一种用法:@Import({ 要导入的容器中的组件 } ):容器会自动注册这个组件,id默认是全类名

第二种用法:ImportSelector:返回需要导入的组件的全类名数组,springboot底层用的特别多【重点 】

第三种用法:ImportBeanDefinitionRegistrar:手动注册bean到容器

 

好了 接下来我们要来进行自动配置的理解啦

了解自动配置

自动配置:

  • 基于添加的JAR依赖自动对Spring Boot应用程序进行配置
  • spring-boot-autoconfiguration

开启自动配置:

  • @EnableAutoConfiguration
  • exclude = Class<?>[]
  • @SpringBootApplication

详细解读:

SpringBoot的自动配置的开启是需要配置@EnableAutoConfiguration的但是你如果细看自己的工程项目的时候会没有在Application.class启动类上面看到对应的代码处看到这个注解的,那是因为这个注解已经被@SpringBootApplication给引入了。

@SpringBootApplication这个注解的exclude这个参数可以主动的控制忽略一些配置类的自动加载,利用@AliasFor(annotation = EnableAutoConfiguration.class)来进行参数值传递

@Import(AutoConfigurationImportSelector.class)是@EnableAutoConfiguration这个注解的,会帮我们自动加载META-INF/spring.factories

自定义配置其实就三步

  • 编写 Java Config

@Configuration
@ConditionalOnClass(GreetingApplicationRunner.class)
public class GreetingAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(GreetingApplicationRunner.class)
    @ConditionalOnProperty(name = "greeting.enabled", havingValue = "true", matchIfMissing = true)
    public GreetingApplicationRunner greetingApplicationRunner() {
        return new GreetingApplicationRunner();
    }
}
@Slf4j
public class GreetingApplicationRunner implements ApplicationRunner {

    public GreetingApplicationRunner() {
        log.info("Initializing GreetingApplicationRunner.");
    }

    public GreetingApplicationRunner(String param) {
        log.info("Initializing GreetingApplicationRunner." + param);
    }

    public void run(ApplicationArguments args) throws Exception {
        log.info("Hello everyone! We all like Spring! ");
    }
}
  • 定位自动配置

处理在配置类的classpath下面的META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
geektime.spring.hello.greeting.GreetingAutoConfiguration

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值