Spring Boot @Configuration 详解
Jihongchang(讨论 | 贡献)2023年2月12日 (日) 08:15的版本 (→SpringBoot 2.x 使用的 spring-context-5.2 中为 @Configuration 新增的 proxyBeanMethods)
https://www.bilibili.com/video/BV19K4y1L7MT/?p=8
回顾旧版本通过 XML 配置文件进行 bean 配置
@Configuration 的作用
告诉 Spring Boot 添加了 @Configuration 注解的类,是一个配置类,作用等同于以前的 XML 配置文件。
使用 @Bean
往容器中注册组件
@Configuration //告诉 SpringBoot 这是一个配置类 == 配置文件
public class MyConfig {
/**
* 给容器中添加组件。
* 以方法名作为组件的id。
* 返回类型就是组件类型。
* 返回的值,就是组件在容器中的实例
*
* 外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
* @return
*/
@Bean
public User user01() {
return new User("zhangsan", 18);
}
@Bean
public Pet tomcatPet() {
return new Pet("tomcat");
}
}
运行 MainApplication:
/**
* 主程序类
* @SpringBootApplication:这是一个 Spring Boot 应用
*/
@SpringBootApplication(scanBasePackages = "io.github.jihch")
public class MainApplication {
public static void main(String[] args) {
//1、返回 IOC 容器
ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
//2、查看容器里面的组件
String[] beanDefinitionNames = context.getBeanDefinitionNames();
Arrays.sort(beanDefinitionNames);
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
}
……
spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties
spring.servlet.multipart-org.springframework.boot.autoconfigure.web.servlet.MultipartProperties
spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties
spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
standardJacksonObjectMapperBuilderCustomizer
stringHttpMessageConverter
taskExecutorBuilder
taskSchedulerBuilder
tomcatPet
tomcatServletWebServerFactory
tomcatServletWebServerFactoryCustomizer
tomcatWebServerFactoryCustomizer
user01
viewControllerHandlerMapping
viewResolver
webServerFactoryCustomizerBeanPostProcessor
websocketServletWebServerCustomizer
welcomePageHandlerMapping
worldController
……
可以观察到容器中多了 tomcatPet 和 user01 两个 bean,默认使用方法名作为组件名,也可以通过 @Bean("tom")
自定义组件名,再运行 MainApplication:
……
spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties
spring.servlet.multipart-org.springframework.boot.autoconfigure.web.servlet.MultipartProperties
spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties
spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
standardJacksonObjectMapperBuilderCustomizer
stringHttpMessageConverter
taskExecutorBuilder
taskSchedulerBuilder
tom
tomcatServletWebServerFactory
tomcatServletWebServerFactoryCustomizer
tomcatWebServerFactoryCustomizer
user01
viewControllerHandlerMapping
viewResolver
webServerFactoryCustomizerBeanPostProcessor
websocketServletWebServerCustomizer
welcomePageHandlerMapping
worldController
……
可以发现组件名就变成自定义的组件名了。
默认注册的组件是单实例的,无论从容器中获取多少次都是一样的
修改 MainApplication 并运行、验证
/**
* 主程序类
* @SpringBootApplication:这是一个 Spring Boot 应用
*/
@SpringBootApplication(scanBasePackages = "io.github.jihch")
public class MainApplication {
public static void main(String[] args) {
//1、返回 IOC 容器
ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
//2、查看容器里面的组件
String[] beanDefinitionNames = context.getBeanDefinitionNames();
Arrays.sort(beanDefinitionNames);
for (String name : beanDefinitionNames) {
System.out.println(name);
}
//3、从容器中获取组件
Pet tom01 = context.getBean("tom", Pet.class);
Pet tom02 = context.getBean("tom", Pet.class);
System.out.println("组件:" + (tom01 == tom02));
}
}
……
组件:true
……
@Configuration 注解的配置类也是容器中的一个组件
修改 MainApplication 运行、验证
/**
* 主程序类
* @SpringBootApplication:这是一个 Spring Boot 应用
*/
@SpringBootApplication(scanBasePackages = "io.github.jihch")
public class MainApplication {
public static void main(String[] args) {
//1、返回 IOC 容器
ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
//2、查看容器里面的组件
String[] beanDefinitionNames = context.getBeanDefinitionNames();
Arrays.sort(beanDefinitionNames);
for (String name : beanDefinitionNames) {
System.out.println(name);
}
//3、从容器中获取组件
Pet tom01 = context.getBean("tom", Pet.class);
Pet tom02 = context.getBean("tom", Pet.class);
System.out.println("组件:" + (tom01 == tom02));
//4、io.github.jihch.boot.config.MyConfig$$EnhancerBySpringCGLIB$$f0fca2ff@26c89563
MyConfig bean = context.getBean(MyConfig.class);
System.out.println(bean);
}
}
……
io.github.jihch.boot.config.MyConfig$$EnhancerBySpringCGLIB$$f0fca2ff@26c89563
……
SpringBoot 2.x 使用的 spring-context-5.2 中为 @Configuration 新增的 proxyBeanMethods
SpringBoot 2.x 使用的 spring-context-5.2 中为 @Configuration 新增了一个属性:proxyBeanMethods,默认值是 true
配置类里注册的方法,在外面调用多少遍获得的始终是容器中的实例
修改 MainApplication 运行、验证
@SpringBootApplication(scanBasePackages = "io.github.jihch")
public class MainApplication {
public static void main(String[] args) {
//1、返回 IOC 容器
ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
//2、查看容器里面的组件
String[] beanDefinitionNames = context.getBeanDefinitionNames();
Arrays.sort(beanDefinitionNames);
for (String name : beanDefinitionNames) {
System.out.println(name);
}
//3、从容器中获取组件
Pet tom01 = context.getBean("tom", Pet.class);
Pet tom02 = context.getBean("tom", Pet.class);
System.out.println("组件:" + (tom01 == tom02));
//4、io.github.jihch.boot.config.MyConfig$$EnhancerBySpringCGLIB$$f0fca2ff@26c89563
MyConfig bean = context.getBean(MyConfig.class);
System.out.println(bean);
//如果 @Configuration(proxyBeanMethods = true) 代理对象调用方法。
//SpringBoot 总会检查这个组件是否在容器中有,保持组件单实例
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1);
}
}
……
true
……