初学SpringBoot-自动配置

自动配置

1.1 自动配好Tomcat

  • 引入tomcat依赖
   
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.3.12.RELEASE</version>
      <scope>compile</scope>
</dependency>
  • 配置Tomcat

1.2 自动配置spring-mvc

  • 引入springMVC 全套组件
  • 自动配好SPringleMVC常用组件
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.15.RELEASE</version>
      <scope>compile</scope>
    </dependency>
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.15.RELEASE</version>
      <scope>compile</scope>
</dependency>
  • 常用的功能
    • dispatchServlet(转发)
    • multipartResolver(文件上传)
    • ViewResolver(视图解决器)
    • characterEncodingFilter(文字过滤器)
  • 展示容器内 对应组件的方法
@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
//        springApplication.run(MainApplication.class,args);
        // 1.返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        // 2.查看容器里面的组件
        String[] names = run.getBeanDefinitionNames();
        for(String name : names){
            System.out.println(name);
        }
    }
}

1.3 默认包结构

  • 主程序所在包的所有子包组件都会被默认扫描进来

    ```
    

    com
    ± example
    ± myapplication
    ± Application.java
    |
    ± customer
    | ± Customer.java
    | ± CustomerController.java
    | ± CustomerService.java
    | ± CustomerRepository.java
    |
    ± order
    ± Order.java
    ± OrderController.java
    ± OrderService.java
    ± OrderRepository.java
    ```

  • 无需以前的包扫瞄

  • 如果要自己设置包扫描

@SpringBootApplication(scanBasePackages = "com.atguigu") //在主类上添加
@ComponentScan //在具体类上添加包扫描的注解
注意不能再包SpringBootApplication上添加包扫描注解,因为SpringBootApplication上已经有了componentScan注解了
  • *@SpringBootApplication是复合类
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

1.4 自动配置有很多的默认值

  • 默认配置都是最终映射到一个类的
  • 配置文件的值最终会绑定到每个类上,这个类在容器中创建对象

1.5 按需加载自动配置项

  • 非常多的starter
  • 引入了那些场景这个场景的自动配置才会开启
  • SpringBoot所有自动配置功能都依赖于spring-boot-autoconfigure
  1. springboot web项目需要引入spring-boot-starter-web依赖

  2. spring-boot-starter-web依赖于spring-boot-starter

  3. spring-boot-starter需要spring-boot-autoconfigure完成自动配置

 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>2.3.12.RELEASE</version>
      <scope>compile</scope>
 </dependency>

2. 容器功能

2.1 组件添加

  1. @Configuration(告诉IOC本类为配置类)

    @Configuration(proxyBeanMethods = false)
    			   //告诉SpringBoot 这是一个配置类 == 配置文件
                   //配置文件能完成的事情 配置类都可以完成
                   //同时@Configuration创建的组件也是被加载到容器中的
                   //默认创建的组件都是单实例的
    public class MyConfig {
    
        @Bean //给容器中添加组件,以方法名作为组件的id,返回类型就是组件的类型,返回值就是组件在容器中的实例
        public User user01(){
            return new User("张三");
        }
    
        @Bean("tomcat111")
        public Pet getPet(){
            return  new Pet("tomcat","12");
        }
    
    }
    
    • 在Configuration注解的类所注册的组件都是单例的原因

      // Configuration.class
      @Target({ElementType.TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      @Component
      public @interface Configuration {
       @AliasFor(
           annotation = Component.class
       )
       String value() default "";
       boolean proxyBeanMethods() default true; //默认是true就表明了方法会被代理
      }
      

    /*
    在容器Ioc中创建的对象:MyConfig E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIBd02ce854@13cda7c9
    是由容器增强过的代理的对象,当proxyBeanMethods默认为true时
    当代理对象调用user01方法的时候,首先会去容器中查找有没有对应组件
    1.有,则返回
    2.无,则创建
    总之,保持组件单实例
    */

    - proxyBeanMethods方法:代理bean方法
    
    ​```java
    Full(proxyBeanMethods = true) //使用代理的方法,单例,返回相同的对象,应用于组件依赖
    Lite(proxyBeanMethods = false) //多例每次返回不同对象,优点:跳过检查容器,springboot启动快
    
  2. @Bean,@Component,@Controller,@Service,@Repository

  3. @ComponentScan,@Import

@import必须写在包扫描范围中,导入的时一个数组,他导入组件的组件名字,是包名+类名

  1. @Conditional:条件装配,满足Conditional才装入容器
较为重要的
ConditionalOnBean() //容器中有这个类,才注册组件
ConditionalOnMissingBean //容器中没有这个组件,才注册组件
ConditionalOnMissingClass //容器中没有这个才注册组件
ConditionalOnClass //容器中有这个类才注册组件
ConditionalOnResource //文件中具有某个资源的时候才干什么
ConditionalOnJava     //默认某一java版本,才注册组件
ConditionalOnWebApplication  //是web应用的时候,才注册组件
ConditionalOnNotWebApplication //不是web应用的时候,才注册组件
ConditionalOnProperty //组件有了有个属性的时候,才注册组件

示例

@Configuration //告诉SpringBoot 这是一个配置类 == 配置文件
               //配置文件能完成的事情 配置类都可以完成
               //同时@Configuration创建的组件也是被加载到容器中的
               //默认创建的组件都是单实例的
public class MyConfig {

    @ConditionalOnMissingBean(name = "tomcat")
    @Bean //给容器中添加组件,以方法名作为组件的id,返回类型就是组件的类型,返回值就是组件在容器中的实例
    public User user01(){
        return new User("张三");
    }

    public Pet getPet(){
        return  new Pet("tomcat","12");
    }
}

2.2 原生配置文件的导入

  1. @ImportResource**:写在配置类上**

    用来将xml配置文件对象导入到springboot的IOC容器中

    @Configuration //告诉SpringBoot 这是一个配置类 == 配置文件
    
    @ImportResource("classpath:beans.xml")              
    
    public class MyConfig {
        @Bean //给容器中添加组件,以方法名作为组件的id,返回类型就是组件的类型,返回值就是组件在容器中的实例
        public User user01(){
            return new User("张三");
        } 
    }
    

2.3 配置绑定

  1. ConfigurationProperties
@Component  //一定要加入组件注释,让组件加入容器之中
@ConfigurationProperties(prefix = "mycar") //设置前缀,会在application.properties去查找
public class Car {
    private String brand;
    private  String price;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public String getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", price='" + price + '\'' +
                '}';
    }
}
  1. @EnableCofigurationProperties + @ConfigurationProperties
/*
配置文件类
*/
@Configuration
@EnableConfigurationProperties(Car.class) //使文件可以
public class MyConfig {
    @Bean //给容器中添加组件,以方法名作为组件的id,返回类型就是组件的类型,返回值就是组件在容器中的实例
    public User user01(){
        return new User("张三");
    }

    public Pet getPet(){
        return  new Pet("tomcat","12");
    }
}

/*
需要加入获取对应值的组件信息
*/
@ConfigurationProperties(prefix = "mycar") //设置前缀,会在application.properties去查找
public class Car {
    private String brand;
    private  String price;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public String getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", price='" + price + '\'' +
                '}';
    }
}

方法一主要用于自己编写的类,方法主要用于引入第三方的类的数据绑定

3. 自动配置原理入门

3.1 SpringBootApplication 完整签名(idea:ctrl+n进行搜索)

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(			//三个为其核心注解 或者说SpringbootApplication是他们三个的复合
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication
  1. @SpringBootConfiguration
/**
* 	SpringBootConfiguration.class源代码
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration	//代表当前是一个配置类,那么说明SpringBootApplication依然是个配置类,依然是核心配置类
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}
  1. @ComponentScan

指定扫描那些包,具体可以看Spring注解

  1. @EnableAutoConfiguration重点,指定默认的包规则)

作用:帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot,并创建对应配置类的Bean,并把该Bean实体交给IoC容器进行管理。

/*
* EnableAutoConfiguration源代码
*/
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}
  • AutoConfigurationPackage自动配置包
/*
*	AutoConfigurationPackage源代码
*/
@Import({AutoConfigurationPackages.Registrar.class})  //给容器中导入一个组件
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
}

使用import导入一个registrar的意义:批量导入一些组件

  • 查看AutoConfigurationPackages.Registrar.class,了解registrar注册了什么
public abstract class AutoConfigurationPackages {
    private static final Log logger = LogFactory.getLog(AutoConfigurationPackages.class);
    private static final String BEAN = AutoConfigurationPackages.class.getName();

    public AutoConfigurationPackages() {
    }

  	...
    ...
    ...

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }
/*
AnnotationMetadata:表示注解的源信息,又由于Springboot->EnableAutoConfiguration->AutoConfigurationPackage->AutoConfigurationPackages,则展示源信息时,展示的信息是MainApplication的信息,也就是包名
相当于将某一个@SpringBootApplication注解的主配置配所在包取到 得com.ruan.boot,register将某个包里面的组件进行批量注册
*/
        
        
        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
        }
    }
}
  • @Import({AutoConfigurationImportSelector.class})

重点在AutoConfigurationImportSelector.class->selectImports->this.getAutoConfigurationEntry(annotationMetadata),给容器中批量导入组件

/*
* this.getAutoConfigurationEntry(annotationMetadata) 方法实现
*/
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            //1.getCandidateConfigurations获取到需要导入到容器中的配置类(组件)
            //2.SpringFactoriesLoader.loadFactoryNames,spring的工厂加载器,来加载一些配置类
            //利用工厂加载器的private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)方法,获得所有组件
            //3.loadSpringFactories方法会在META-INF/spring.factories位置加载一个文件。
            //   扫描当前系统中所有META-INF/spring.factories
            //   核心jar包中 spring-boot-autoconfigure-2.3.12.RELEASE.jar 含有127个元素springboot一启动 就需要给容器加载的所有类。
            
            
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

3.2 按需配置

由上面知道了,springboot启动时,如何进行自动配置中找到相应其的组件,但是不是所有的组件都是必须加载到组件当中的,存在按需配置的情况(以上的autoconfigure中127个没有全部加载,需要导入相应的场景依赖,即条件装配规则)

换句话说:127个场景的所有自动配置启动的时候全部加载,但是并没有全部装配

3.3 修改默认配置

    @Bean
    @ConditionalOnBean({MultipartResolver.class}) //容器中有这类组件
    @ConditionalOnMissingBean(	//容器中没有这个名字
         name = {"multipartResolver"}
    )
    public MultipartResolver multipartResolver(MultipartResolver resolver) {
         //@Bean标注的方法传入了对象参数,这个参数值就会从容器中中找
         // SpringMvc multipartResolver,放置有些用户配置的文件上传解析器不符合规范
         return resolver;
    }
	//给容器中加入了文件上传解析器

4.总结

  • SpringBoot先加载所有的自动配置类
  • 每个自动配置类按照条件生效
  • 生效的配置类都会按照容器中装配很多组件
  • 只要让其中有这些组件,相当于这些功能就有了
  • 只要用户有自己的配置的,就以用户的优先

xxxxAutoConfiguration—>组件—>xxxxProperties里面哪值---->application.properties

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值