• 【SpringBoot2 从0开始】底层注解


    一、配置类

    @Configuration这个注解作用就是告诉 springboot 这是一个配置类。

    这个配置已经不陌生了,在之前 spring 相关的使用全注解方式时,就使用到了配置类。

    在配置类里,可以使用@Bean标记在方法上,给容器注册组件,默认也是单实例的。

    @Configuration //告诉SpringBoot这是一个配置类 == 配置文件
    public class MyConfig {
    
        @Bean("user1") //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
        public User user01(){
            return new User("pingguo", 20);
        }
    
        @Bean("pet1")
        public Pet tomcatPet(){
            return new Pet("tomcat");
        }
    }
    

    主运行类还是之前示例中的,打印出所有组件的名称。

    可以看到,有上面注册的 2 个组件:user1、pet1

    二、配置类本身也是组件

    在主运行类的 main 方法里,加一个获取配置类的输出:

    @SpringBootApplication(scanBasePackages = "com.pingguo")
    public class MainApplication {
        public static void main(String[] args) {
            // 返回IOC容器
            final ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
    
            // 查看容器里的组件
            final String[] beanDefinitionNames = run.getBeanDefinitionNames();
    
            for (String name: beanDefinitionNames) {
                System.out.println(name);
            }
    
            // 从容器中获取组件
            MyConfig bean = run.getBean(MyConfig.class);
            System.out.println("配置类也是组件:" + bean);
        }
    }
    

    运行 main 方法,

    可以看到最后一个输出,说明配置类本身也是个组件。

    三、proxyBeanMethods 属性

    springboot2.0之后,@Configuration 中多了一个属性 proxyBeanMethods,用来代理 bean 的。

    默认值是true,也就是说该配置类会被代理(CGLIB),在同一个配置文件中调用其它被@Bean注解标注的方法获取对象时,springboot 总会检查容器中是否存在这个组件。

    如果容器中存在,直接取。不存在的话,才会去创建,保证单实例。

    现在看下false的情况。

    @Configuration(proxyBeanMethods = false) //改成 false
    public class MyConfig {
    
        @Bean("user1") //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
        public User user01(){
            return new User("pingguo", 20);
        }
    
        @Bean("pet1")
        public Pet tomcatPet(){
            return new Pet("tomcat");
        }
    }
    

    在主运行程序里多从调用方法获取对象,判断一下对象是否相等。

    @SpringBootApplication(scanBasePackages = "com.pingguo")
    public class MainApplication {
        public static void main(String[] args) {
            // 返回IOC容器
            final ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
    
            // 查看容器里的组件
            final String[] beanDefinitionNames = run.getBeanDefinitionNames();
    
            for (String name: beanDefinitionNames) {
                System.out.println(name);
            }
    
            // 从容器中获取组件
            MyConfig bean = run.getBean(MyConfig.class);
            System.out.println("配置类也是组件:" + bean);
    
            User user1 = bean.user01();
            User user2 = bean.user01();
            System.out.println(user1 == user2);
        }
    }
    

    看最后的输出,会是 false。

    这里引出 2 个名词:Full 全模式Lite 轻量级模式

    • Full (proxyBeanMethods = true) : 该模式下注入容器中的同一个组件无论被取出多少次都是同一个bean实例,即单实例对象,
      在该模式下 SpringBoot 每次启动都会判断检查容器中是否存在该组件。

    • Lite (proxyBeanMethods = false): 该模式下注入容器中的同一个组件无论被取出多少次都是不同的bean实例,即多实例对象,
      在该模式下 SpringBoot 每次启动会跳过检查容器中是否存在该组件。

    那么这个是用来解决什么场景的问题呢?答案:组件依赖

    有组件依赖的场景

    看下2个实体类:User、Pet。

    public class User {
        private String name;
        private Integer age;
        private Pet pet;
    ... ...
    

    固定代码部分:有参构造、无参构造、get和set方法、toString方法,就省去了。

    public class Pet {
        private String name;
    ... ...
    

    修改下配置类里的方法:

    @Configuration(proxyBeanMethods = true)
    public class MyConfig {
    
        @Bean("user1") 
        public User user01(){
            User pingguo = new User("pingguo",20);
            pingguo.setPet(tomcatPet());
            return pingguo;
        }
    
        @Bean("pet1")
        public Pet tomcatPet(){
            return new Pet("tomcat");
        }
    }
    

    到main方法测试一下:

        // 依赖关系
        User user01 = run.getBean("user1", User.class);
        Pet pet1 = run.getBean("pet1", Pet.class);
    
        System.out.println("依赖:" + (user01.getPet() == pet1));
    

    这里就是判断当proxyBeanMethods = true的情况下,User对象的 pet,是不是容器中的 pet。

    如果是,那么结果就是true

    此时再将proxyBeanMethods = false,重新运行一下,结果会是 false:

    那么这 2 个模式分别在什么时候用呢

    当在你的同一个Configuration配置类中,注入到容器中的 bean 实例之间有依赖关系时,建议使用 Full 全模式

    当在你的同一个Configuration配置类中,注入到容器中的 bean 实例之间没有依赖关系时,建议使用 Lite 轻量级模式,以提高 springboot 的启动速度和性能。

    --不要用肉体的勤奋,去掩盖思考的懒惰--
  • 相关阅读:
    YTU 2802: 判断字符串是否为回文
    YTU 2392: 求各位数字之和
    YTU 2391: 求素数
    HDU 2064:汉诺塔III
    HDU 2187:悼念512汶川大地震遇难同胞——老人是真饿了
    HDU 2036:改革春风吹满地
    HDU 1081:To The Max
    HDU 1257:最少拦截系统
    YTU 2425: C语言习题 输出月份
    YTU 2420: C语言习题 不等长字符串排序
  • 原文地址:https://www.cnblogs.com/pingguo-softwaretesting/p/15204039.html
Copyright © 2020-2023  润新知