【SpringBoot2 从0开始】底层注解 - @Configuration

简介: 【SpringBoot2 从0开始】底层注解 - @Configuration

一、配置类


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


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


1268169-20210829225823108-2132174323.png


可以看到,有上面注册的 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 方法,


1268169-20210829230448832-1582133845.png


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


三、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。


1268169-20210830223519585-632301509.png


这里引出 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


1268169-20210830230338156-1907453948.png


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


1268169-20210830230529570-1670451730.png


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


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


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

相关文章
|
2月前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
60 0
|
16天前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
146 73
|
11天前
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
45 21
|
16天前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
16天前
|
Java Spring
【Spring配置】idea编码格式导致注解汉字无法保存
问题一:对于同一个项目,我们在使用idea的过程中,使用汉字注解完后,再打开该项目,汉字变成乱码问题二:本来a项目中,汉字注解调试好了,没有乱码了,但是创建出来的新的项目,写的注解又成乱码了。
|
2月前
|
XML JSON Java
SpringBoot必须掌握的常用注解!
SpringBoot必须掌握的常用注解!
84 4
SpringBoot必须掌握的常用注解!
|
2月前
|
前端开发 Java Spring
Spring MVC核心:深入理解@RequestMapping注解
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的核心,它将HTTP请求映射到控制器的处理方法上。本文将深入探讨`@RequestMapping`注解的各个方面,包括其注解的使用方法、如何与Spring MVC的其他组件协同工作,以及在实际开发中的应用案例。
49 4
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
159 2
|
2月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
67 2
|
2月前
|
消息中间件 Java 数据库
解密Spring Boot:深入理解条件装配与条件注解
Spring Boot中的条件装配与条件注解提供了强大的工具,使得应用程序可以根据不同的条件动态装配Bean,从而实现灵活的配置和管理。通过合理使用这些条件注解,开发者可以根据实际需求动态调整应用的行为,提升代码的可维护性和可扩展性。希望本文能够帮助你深入理解Spring Boot中的条件装配与条件注解,在实际开发中更好地应用这些功能。
47 2