当前位置: 首页 > news >正文

Spring Boot 中 Bean 的机制详解

Spring Boot 的魔力在于其自动配置和 Bean 管理,它极大地简化了 Spring 应用的开发。本文将结合之前的内容,更加全面、深入地解释 Spring Boot 如何管理 Bean、自动装配的底层原理以及相关的使用细节,并提供更丰富的示例。

1. Bean 管理核心机制

Spring 容器是 Bean 的生命周期管理中心,负责 Bean 的创建、配置、组装和销毁。Spring Boot 通过自动化配置简化了 Bean 的管理过程,开发者只需少量配置即可拥有一个功能完善的 Spring 应用。

  • @SpringBootApplication: 这个注解是 Spring Boot 的核心,它整合了三个关键注解:

    • @SpringBootConfiguration: 标明该类是一个 Spring Boot 配置类,等同于 @Configuration,允许在该类中定义 Bean。

    • @EnableAutoConfiguration: 启用 Spring Boot 的自动配置机制。它利用 Spring Factories 机制加载 META-INF/spring.factories 文件中定义的自动配置类,根据 classpath 中的依赖自动配置 Bean,例如数据库连接、Web 服务器等。

    • @ComponentScan: 自动扫描指定包及其子包,查找带有 @Component、@Service、@Repository、@Controller 等 stereotype 注解的类,并将它们注册为 Spring Bean。可以自定义扫描的包路径。

  • Bean 定义: Bean 定义是 Spring 容器创建 Bean 的蓝图,包含了 Bean 的所有信息,例如类名、作用域、初始化方法、销毁方法、依赖关系等。

  • Bean 的生命周期:

    • 实例化: Spring 容器根据 Bean 定义创建 Bean 实例,可以使用构造器注入、工厂方法等方式创建。

    • 属性赋值 (Populate): 注入 Bean 的依赖和其他属性值,可以使用 setter 注入、字段注入等方式。

    • Bean 后置处理器 (BeanPostProcessor): BeanPostProcessor 接口允许开发者在 Bean 初始化前后执行自定义逻辑。Spring 内置了许多 BeanPostProcessor,例如 AutowiredAnnotationBeanPostProcessor 负责处理 @Autowired 注解。

      • Aware 接口: Spring 提供了一系列 Aware 接口,例如 BeanFactoryAware、ApplicationContextAware 等,允许 Bean 获取 Spring 容器相关的对象。

    • 初始化 (Initialize): 调用初始化方法,例如 @PostConstruct 注解的方法、InitializingBean 接口的 afterPropertiesSet() 方法或 XML 配置中的 init-method。

    • 使用: Bean 可以被应用程序使用。

    • 销毁 (Destroy): 调用销毁方法,例如 @PreDestroy 注解的方法、DisposableBean 接口的 destroy() 方法或 XML 配置中的 destroy-method。

2. 自动装配核心原理

Spring Boot 的自动装配机制是其魔法所在,能够根据 classpath 中的依赖自动配置 Bean,大大减少了配置工作。

  • @EnableAutoConfiguration 深入解读: 该注解会触发 Spring Boot 的自动配置机制,它导入 AutoConfigurationImportSelector,该选择器利用 Spring Factories 机制加载 META-INF/spring.factories 文件中定义的自动配置类。

  • Spring Factories 机制详解: META-INF/spring.factories 文件是一个 key-value 映射文件,key 是接口的全限定名,value 是实现类的全限定名列表。Spring Boot 通过读取这个文件,加载所有自动配置类。

  • 条件化注解精细控制: 自动配置类通常使用条件化注解,例如:

    • @ConditionalOnClass:当 classpath 中存在指定的类时生效。

    • @ConditionalOnMissingClass:当 classpath 中不存在指定的类时生效。

    • @ConditionalOnBean:当 Spring 容器中存在指定的 Bean 时生效。

    • @ConditionalOnMissingBean:当 Spring 容器中不存在指定的 Bean 时生效。

    • @ConditionalOnProperty:当指定的配置属性存在且值为 true 时生效。

  • 自动装配流程 (更详细):

    • Spring Boot 启动时,AutoConfigurationImportSelector 读取 META-INF/spring.factories 文件,获取所有自动配置类。

    • 对于每个自动配置类,Spring 容器会检查其条件化注解,判断是否满足条件。

    • 如果满足条件,则该自动配置类生效,其中定义的 @Bean 方法会被调用,创建 Bean 并注册到 Spring 容器中。

    • AutowiredAnnotationBeanPostProcessor 会处理 @Autowired 注解,根据类型、名称或 qualifier 查找匹配的 Bean,并进行注入。

3. 获取 Bean 的场景化应用

  • @Autowired (推荐): 简洁方便,适用于大多数场景。

  • @Resource: 灵活,可以根据名称或类型注入。

  • ApplicationContext: 功能强大,可以获取任何 Bean,但代码略显繁琐。 适用于需要动态获取 Bean 的场景。

4. Bean 作用域

在Spring中支持五种作用域,后三种在web环境才生效:

作用域说明
singleton容器内同名称的bean只有一个实例(单例)(默认)
prototype每次使用该bean时会创建新的实例(非单例)
request每个请求范围内会创建新的实例(web环境中)
session每个会话范围内会创建新的实例(web环境中)
application每个应用范围内会创建新的实例(web环境中)

5. 第三方 Bean 集成策略

  • @Bean 注解: 最常用的方式,灵活控制 Bean 的创建过程。

  • @Import 注解: 方便导入其他配置类。

  • 手动注册 BeanDefinition: 更高级的用法,可以动态注册 Bean。

6. 示例

@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}@Component
class MyBean {private String message = "Hello from MyBean";public String getMessage() {return message;}
}@Service
class MyService {private final MyBean myBean;private final ApplicationContext context;@Autowiredpublic MyService(MyBean myBean, ApplicationContext context) {this.myBean = myBean;this.context = context;}public void doSomething() {System.out.println(myBean.getMessage());MyBean anotherBean = context.getBean(MyBean.class);System.out.println(anotherBean.getMessage());  //获取同一个bean}
}@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
class PrototypeBean {private int counter = 0;public int getCounter() {return ++counter;}
}@Service
class AnotherService {@Autowiredprivate PrototypeBean prototypeBean; // 注入代理对象public void testPrototype(){System.out.println("Prototype Bean 1: " + prototypeBean.getCounter());System.out.println("Prototype Bean 2: " + prototypeBean.getCounter());  // 每次调用都会增加}
}@RestController
class MyController {private final MyService service;private final AnotherService anotherService;@Autowiredpublic MyController(MyService service, AnotherService anotherService) {this.service = service;this.anotherService = anotherService;service.doSomething();anotherService.testPrototype();}@GetMapping("/")public String hello() {anotherService.testPrototype();//每次调用都会生成新的prototype beanreturn "Hello from Spring Boot!";}
}

代码解释:(以上代码为了解释方便就写在了一起,仅供参考)

  • PrototypeBean:

    • @Scope 注解指定了 prototype 作用域,确保每次请求都会创建一个新的实例。

    • proxyMode = ScopedProxyMode.TARGET_CLASS 至关重要。它创建了一个 CGLIB 代理来包装 PrototypeBean。 因为 AnotherService 是 singleton 的,它只会在启动时注入一次 PrototypeBean。如果没有代理,注入的就是启动时创建的那个 PrototypeBean 实例,之后每次调用 getCounter() 都是同一个实例。 使用代理后,每次调用 prototypeBean.getCounter() 时,代理都会从 Spring 容器获取一个新的 PrototypeBean 实例,从而实现了预期的行为.

  • AnotherService:

    • @Autowired 注入的 prototypeBean 现在是代理对象。

  • MyController:

    • 注入了 AnotherService 并在构造函数和 hello() 方法中调用了 testPrototype() 方法,演示了代理的效果. 在 hello() 方法中每次调用都会生成新的 prototype bean.

现在,运行应用并多次访问 / 端点,你会看到 PrototypeBean 的计数器每次都会增加,证明每次都注入了新的实例. 这体现了代理模式在处理不同作用域 Bean 注入时的重要作用.

这个完整的示例演示了 prototype 作用域的正确用法,并解释了代理模式如何解决在 singleton bean 中注入 prototype bean 的问题。 这对于理解 Spring Bean 的作用域和依赖注入至关重要。

总结:

本文更加深入地解释了 Spring Boot 的 Bean 管理和自动装配机制,并提供了更丰富的示例和最佳实践。 理解这些核心概念和细节,可以更好地利用 Spring Boot 构建更强大、更灵活的应用程序。 建议深入学习 Spring Boot 的文档和源码,以掌握更多高级特性。希望对各位看官有所帮助,感谢各位看官的观看,谢谢,下期见~


http://www.mrgr.cn/news/48103.html

相关文章:

  • Pytorch | 利用I-FGSSM针对CIFAR10上的ResNet分类器进行对抗攻击
  • 电脑缺失msvcp120.dll怎么弄?msvcp120.dll丢失的多个解决方法
  • 近实时”(NRT)搜索、倒排索引
  • [OpenGL]使用TransformFeedback实现粒子效果
  • QT--信号与槽机制
  • 使用Amazon Bedrock的无服务器的智能工作流
  • QInputDialog Class
  • 364_C++_通过类型定义、数组、指针、std::vector和内存复制来管理多个通道的记录数据
  • 养宠人崩溃的季节又到了,有什么吸浮毛宠物空气净化器推荐?
  • 多个pdf怎么合并成一个pdf?几个方法教你快速进行pdf合并不求人
  • V神应被提名诺贝尔经济学奖?以太坊对货币经济学的贡献无可取代?
  • Linux云计算 |【第四阶段】RDBMS2-DAY5
  • redis概述
  • MIDIPLUS 50周年丨中国国际乐器展览会首日盛况
  • 【笔记】Day1.1.24代码debug测试
  • 高可用之限流-04-fixed window 固定窗口
  • MES系统中人机接口设计和开发研究
  • Pyke学习系列(pyke基础执行)(一)
  • Spring Boot 日志打印配置详解
  • 【C语言】自定义类型:联合体和枚举
  • C++编程:利用ARM硬件加速CRC32计算
  • vue基础语法的用法(API组合式风格)
  • maven
  • 小白萌新 JSAR 开发者工具之初体验——好用!
  • 《市场营销学》PPT课件.ppt
  • SAP S/4HANA 迁移:IT 高管实用指南