• 04.SpringBoot容器功能


    SpringBoot容器

    1.@Configuration

    告诉SpringBoot这是配置文件

    @Configuration(proxyBeanMethods = true)
    public class MyConfig {
        @Bean//默认也是单实例的
        public User user1()
        {
            return  new User("ylc",22);
        }
    }
    

    里面包含默认值proxyBeanMethods参数

    proxyBeanMethods:代理bean的方法

    • Full模式:proxyBeanMethods = true,通过方法调用依然指向原来的bean
    • Lite模式:proxyBeanMethods = false,直接返回新实例对象

    组件依赖(有二次调用)必须使用Full模式默认。其他默认是否Lite模式

    /*这是一个Springboot应用*/
    @SpringBootApplication(scanBasePackages = "com.ylc")
    public class MainApplication {
        public static void main(String[] args) {
            //返回IOC容器
           ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class,args);
    
            //从容器中获取组件
            User user1 = context.getBean("user1", User.class);
            User user2 = context.getBean("user1", User.class);
            System.out.println(user1==user2);
        }
    }
    

    最后为结果为true

    不需要创建新组件时使用Lite模式,创建新组件时使用Full模式保证取得的组件为ioc中同一组件

    2.@Import

    @Import(DBHelper.class)//给容器中自动创建出这类型的组件、默认组件的名字就是全类名
    

    image-20210727000956712

    3.@Condictional

    条件装配:满足Conditional指定的条件才可以注入

    image-20210727210355861

    例如@ConditionalOnBean,在有某个bean的时候才会注入

    如果注入b的时候需要依赖a那么它们直接就可以使用条件装配,这个发生在bean的注入之前

    如果把该注解放在类上,不满足条件整个类里面包含的东西都不会注册到,存在先后顺序

    4.@ImportResource

    用于导入外部资源文件

    @ImportResource("classpath:beans.xml")
    

    5.@ConfigurationProperties

    用于配置文件绑定

    user.name="小明"
    user.age=12
    

    5.1@Component+@ConfigurationProperties

    只有这个组件是容器中的组件,才能使用容器提供的@ConfigurationProperties功能

    @Component
    @ConfigurationProperties(prefix = "user")//user为配置文件的前缀名
    public class User {
        public  String name;
        public  int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public User() {
        }
    }
    
    @RestController
    public class HelloWorldController {
        @Autowired
        User user;
    
        @RequestMapping("/GetUser")
        public User GetUser()
        {
            return  user;
        }
    }
    

    image-20210727225838255

    5.2 @EnableConfigurationProperties+@ConfigurationProperties

    @EnableConfigurationProperties(Car.class)
    //1、开启Car配置绑定功能
    //2、把这个Car这个组件自动注册到容器中
    public class MyConfig {
    }
    
    @ConfigurationProperties(prefix = "mycar")
    public class Car {
        public  String CarType;
        public  int Price;
    
        public Car(String carType, int price) {
            CarType = carType;
            Price = price;
        }
    
        public String getCarType() {
            return CarType;
        }
    
        public void setCarType(String carType) {
            CarType = carType;
        }
    
        public double getPrice() {
            return Price;
        }
    
        public void setPrice(int price) {
            Price = price;
        }
    
        public Car() {
        }
    }
    

    6.@SpringBootApplication

    @SpringBootApplication是一个合成注解,实际由以下注解组成

    image-20210728223140345

    6.1 @SpringBootConfiguration

    @SpringBootConfiguration包含@Configuration注解表明这是一个配置类

    6.2 @EnableAutoConfiguration(重要)

    自动载入应用程序所需的所有Bean

    @EnableAutoConfiguration包含以下注解

    image-20210728224437864

    6.2.1@AutoConfigurationPackage

    将指定包下的所有组件导入进来,默认MainApplication类所在的包下

    里面包含@Import({Registrar.class})

    利用Registrar给容器中导入一系列组件

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
            public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
                AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
            }
        }
    

    metadata把注解源信息拿出来,然后通过getPackageNames获取包名,把包名封装到数组里面,最后注册信息

    6.2.2 @Import({AutoConfigurationImportSelector.class})

    给容器中导入一个组件

    AutoConfigurationImportSelector类里面包含selectImports方法,String[]最后用于存储要导入的包

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }
    

    其中getAutoConfigurationEntry方法,获取所有自动配置的集合

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

    image-20210728215350725

    //获取所有候选的配置

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }
    

    其中loadFactoryNames方法,利用工厂加载得到的所有组件

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }
    
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }
    

    loadSpringFactories这里搜索所有META-INF/spring.factories配置文件,将根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类,存储再Map中

    private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");
                }
    

    从META-INF/spring.factories的位置来加载一个配置文件,默认扫描当前系统里面所有的信息

    在spring-boot-autoconfigure-2.5.3.jar 包中的spring.factories文件中写死了SpringBoot启动要加载的所有配置

    image-20210728222453584

    虽然所有自动配置启动的时候默认全部加载

    xxxxAutoConfiguration 按照条件装配规则(@Conditional),最终会按需配置

    6.3 @ComponentScan

    @ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中

  • 相关阅读:
    4月21日Java作业
    5.14 Java作业
    第十周java作业
    4月30号作业
    第七周上机
    4.9Java
    通宵看剧有感
    error: pathspec 'xxxxxxxxx' did not match any file(s) known to git
    markdown格式测试
    博客申请通过啦
  • 原文地址:https://www.cnblogs.com/cg-ww/p/15126709.html
Copyright © 2020-2023  润新知