初学SpringBoot-自动配置

初学SpringBoot-自动配置,第1张

初学SpringBoot-自动配置 自动配置 1.1 自动配好Tomcat
  • 引入tomcat依赖
   

      org.springframework.boot
      spring-boot-starter-tomcat
      2.3.12.RELEASE
      compile

  • 配置Tomcat
1.2 自动配置spring-mvc
  • 引入springMVC 全套组件
  • 自动配好SPringleMVC常用组件

      org.springframework
      spring-web
      5.2.15.RELEASE
      compile
    

      org.springframework
      spring-webmvc
      5.2.15.RELEASE
      compile

  • 常用的功能
    • 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完成自动配置

 
      org.springframework.boot
      spring-boot-autoconfigure
      2.3.12.RELEASE
      compile
 
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就表明了方法会被代理
      }
      

    - 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
@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容器进行管理。

@AutoConfigurationPackage
@import({AutoConfigurationimportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class[] exclude() default {};

    String[] excludeName() default {};
}
  • 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]));
        }

        
        
        public Set determineimports(Annotationmetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.Packageimports(metadata));
        }
    }
}
 
  • @import({AutoConfigurationimportSelector.class})

重点在AutoConfigurationimportSelector.class->selectimports->this.getAutoConfigurationEntry(annotationmetadata),给容器中批量导入组件

protected AutoConfigurationimportSelector.AutoConfigurationEntry getAutoConfigurationEntry(Annotationmetadata annotationmetadata) {
        if (!this.isEnabled(annotationmetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationmetadata);
            List configurations = this.getCandidateConfigurations(annotationmetadata, attributes);
            //1.getCandidateConfigurations获取到需要导入到容器中的配置类(组件)
            //2.SpringFactoriesLoader.loadFactoryNames,spring的工厂加载器,来加载一些配置类
            //利用工厂加载器的private static Map> 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 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

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5686413.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)