Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界 (下)

简介: Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界

Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界 (上):https://developer.aliyun.com/article/1456573


Bean 的作用域和生命周期管理


解析 Bean 的作用域和生命周期概念


在Spring框架中,理解Bean的作用域和生命周期是至关重要的,它们决定了Bean的创建、管理及销毁方式。本篇博客将深入探讨这两个概念,并通过示例代码帮助读者更好地理解Spring提供的各种Bean生命周期回调方法。


一、Bean的作用域(Scope)


在Spring中,Bean的作用域决定了容器如何新建Bean实例的规则。Spring提供了几种作用域:


  • singleton:(默认作用域)容器中只存在一个共享的Bean实例,每次请求都返回同一个Bean实例。
  • prototype:每次请求都会创建一个新的Bean实例。
  • request:每次HTTP请求都会产生一个新的Bean,仅在Web应用中有效。
  • session:在一个HTTP Session中,一个Bean定义对应一个实例。仅在Web应用中有效。
  • application:在一个ServletContext生命周期内,一个Bean定义对应一个实例。仅在Web应用中有效。


示例代码:定义不同作用域的Bean

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
 
@Configuration
public class BeanScopeConfig {
 
    @Bean
    @Scope("singleton")
    public MyBean singletonBean() {
        return new MyBean();
    }
 
    @Bean
    @Scope("prototype")
    public MyBean prototypeBean() {
        return new MyBean();
    }
}


二、Bean的生命周期


Bean的生命周期指的是从Bean的初始化到销毁的整个过程。在这个过程中,Spring容器提供了多个扩展点,允许在Bean的创建和销毁过程中加入自定义逻辑。


Bean生命周期的主要阶段:


  1. 实例化Bean:Spring容器首先调用构造函数或工厂方法来实例化Bean。
  2. 填充属性:Spring容器注入Bean所需要的依赖。
  3. 调用BeanNameAware的setBeanName():如果Bean实现了BeanNameAware接口,Spring容器将Bean的ID传给setBeanName方法。
  4. 调用BeanFactoryAware的setBeanFactory():如果Bean实现了BeanFactoryAware接口,Spring容器将调用setBeanFactory方法,传入BeanFactory。
  5. 调用ApplicationContextAware的setApplicationContext():如果Bean实现了ApplicationContextAware接口,Spring容器将调用setApplicationContext方法,传入ApplicationContext。
  6. 前置处理器Before Initialization:BeanPostProcessor的postProcessBeforeInitialization方法将被调用。
  7. 初始化:如果Bean实现了InitializingBean接口,Spring容器将调用afterPropertiesSet方法。另外,可以通过@Bean注解的initMethod指定初始化方法。
  8. 后置处理器After Initialization:BeanPostProcessor的postProcessAfterInitialization方法将被调用。
  9. Bean准备就绪:此时,Bean已经准备好被应用使用了。
  10. 销毁:当容器关闭时,如果Bean实现了DisposableBean接口,Spring容器将调用destroy方法。也可以通过@Bean注解的destroyMethod指定销毁方法。


示例代码:自定义Bean生命周期回调方法

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
 
public class MyLifecycleBean implements InitializingBean, DisposableBean {
 
    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化逻辑
        System.out.println("MyLifecycleBean is initialized.");
    }
 
    @Override
    public void destroy() throws Exception {
        // 销毁逻辑
        System.out.println("MyLifecycleBean is destroyed.");
    }
}

通过实现InitializingBeanDisposableBean接口,我们可以在Bean的生命周期的特定时间点执行自定义逻辑。


Bean 的属性装配和自动装配


深入理解Spring Bean:属性、依赖与自动装配


在Spring框架中,Bean是构建应用程序的基石。它们不仅承载着数据和行为,还通过依赖关系与其他Bean相互作用。正确地管理Bean的属性和依赖关系,是实现高效、可维护Spring应用的关键。本篇博客将带你深入理解Bean的属性和依赖关系,并掌握Spring提供的属性配置和自动装配方式。


一、理解Bean的属性和依赖关系


Bean的属性


Bean的属性指的是Bean中的字段,这些字段可以通过XML配置、注解或JavaConfig来配置。


示例:通过XML配置Bean属性
<bean id="exampleBean" class="com.example.ExampleBean">
    <property name="beanProperty" value="Some Value"/>
</bean>


示例:通过注解配置Bean属性
@Component
public class ExampleBean {
    @Value("${some.value}")
    private String beanProperty;
}


Bean的依赖关系


Bean的依赖关系指的是一个Bean依赖于另一个Bean来完成其操作。例如,一个服务类(Service)可能依赖于一个数据访问对象(DAO)。


示例:通过XML配置Bean依赖
<bean id="myDao" class="com.example.MyDao"/>
 
<bean id="myService" class="com.example.MyService">
    <property name="myDao" ref="myDao"/>
</bean>


示例:通过注解配置Bean依赖
@Service
public class MyService {
    private final MyDao myDao;
 
    @Autowired
    public MyService(MyDao myDao) {
        this.myDao = myDao;
    }
}


二、掌握Spring提供的属性配置和自动装配方式


属性配置


Spring提供了多种方式来配置Bean的属性,其中最常用的是@Value注解。


使用@Value注解


@Value注解可以用来注入普通属性、系统属性、环境变量等。

@Component
public class ExampleBean {
    @Value("${app.name:defaultAppName}")
    private String appName;
}

自动装配


Spring的自动装配功能可以自动满足Bean之间的依赖,减少配置的工作量。最常用的自动装配注解是@Autowired


使用@Autowired进行自动装配


Spring会在容器中查找匹配类型的Bean,并注入到被@Autowired标注的字段、构造器或方法中。

@Service
public class MyService {
    private final MyDao myDao;
 
    @Autowired
    public MyService(MyDao myDao) {
        this.myDao = myDao; // 自动装配
    }
}


高级自动装配


对于更复杂的自动装配场景,Spring提供了@Qualifier@Primary注解来进一步控制自动装配的行为。


使用@Qualifier指定具体的Bean


当有多个同类型的Bean可供选择时,@Qualifier注解可以用来指定具体要装配的Bean。

@Autowired
@Qualifier("specificDao")
private MyDao myDao;


使用@Primary指定首选的Bean


通过在Bean定义上使用@Primary注解,可以指定当存在多个同类型Bean时,默认选择哪一个。

@Component
@Primary
public class PrimaryDao implements MyDao {
    // 实现细节
}


高级特性:BeanPostProcessor 和 FactoryBean


理解 BeanPostProcessor 和 FactoryBean 的作用和区别


在Spring框架中,BeanPostProcessor和FactoryBean是两个非常重要的接口,它们在Bean的生命周期管理和创建过程中扮演着关键角色。虽然它们的功能看似相近,但实际上各自的作用和应用场景大相径庭。


BeanPostProcessor:定制Bean的创建过程


BeanPostProcessor允许开发者插手Bean的初始化过程,在Bean的初始化前后执行一些自定义逻辑。


主要方法:


  • postProcessBeforeInitialization(Object bean, String beanName): 在任何Bean初始化回调方法(如InitializingBean的afterPropertiesSet或自定义的init方法)之前调用。
  • postProcessAfterInitialization(Object bean, String beanName): 在所有Bean初始化回调之后调用。


应用场景:


  • 修改或包装Bean的实例,例如用代理包装一个Bean以提供额外的功能。
  • 检查Bean属性的正确性或根据特定条件更改Bean的属性。


示例代码:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
 
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在初始化之前执行的逻辑
        return bean;
    }
 
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 在初始化之后执行的逻辑
        return bean;
    }
}


FactoryBean:专门用于生产对象的工厂Bean


与BeanPostProcessor不同,FactoryBean是用于生成其他Bean实例的特殊Bean。当配置的Bean实现了FactoryBean接口时,它将返回getObject()方法所返回的对象,而不是FactoryBean本身。


主要方法:


  • T getObject(): 返回由FactoryBean创建的Bean实例。
  • Class<?> getObjectType(): 返回FactoryBean创建的Bean类型。
  • boolean isSingleton(): 表明由FactoryBean创建的Bean是否为单例。


应用场景:


  • 创建复杂对象,当一个Bean的创建过程中涉及复杂逻辑时,可以使用FactoryBean封装这些逻辑。
  • 返回的Bean实例可以是接口的代理,也可以是需要复杂初始化的对象。


示例代码:

import org.springframework.beans.factory.FactoryBean;
 
public class MyFactoryBean implements FactoryBean<MyBean> {
    @Override
    public MyBean getObject() throws Exception {
        // 返回需要创建的Bean实例
        return new MyBean();
    }
 
    @Override
    public Class<?> getObjectType() {
        return MyBean.class;
    }
 
    @Override
    public boolean isSingleton() {
        // 控制该Bean是否为单例
        return true;
    }
}


BeanPostProcessor vs FactoryBean


虽然BeanPostProcessor和FactoryBean都可以影响Spring容器中Bean的创建,但它们的主要区别在于:


  • BeanPostProcessor是用于修改或包装已经存在的Bean实例的。
  • FactoryBean是用于创建新的Bean实例的。


Spring Boot 中的 Bean 管理和自动配置


探索Spring Boot:设计理念与自动配置深解


Spring Boot,作为现代Java开发中的一颗明星,以其“约定大于配置”的理念,极大地简化了Spring应用的开发、部署和运维。它不仅继承了Spring框架强大的依赖注入和面向切面编程的特性,还在此基础上提供了自动配置等功能,使得开发者可以更加专注于业务逻辑。本篇博客将带你深入理解Spring Boot的设计理念和主要特点,以及它在Bean管理和自动配置方面的实现原理。


Spring Boot的设计理念和主要特点


设计理念


Spring Boot遵循“约定大于配置”的原则,旨在减少项目搭建的复杂性和开发时的配置要求。它通过合理的默认配置,帮助开发者快速启动和开发Spring应用程序。


主要特点


  • 自动配置:自动配置Spring和第三方库,尽可能地减少配置文件的使用。
  • 独立运行:生成的应用程序可以直接运行,不需要外部的Servlet容器。
  • 运维友好:提供了丰富的监控和管理功能,支持健康检查、应用信息查看等。
  • 无代码生成和XML配置:不需要生成代码或进行XML配置,通过注解和自动装配完成配置。


深入掌握Spring Boot在Bean管理和自动配置方面的实现原理


Bean管理


Spring Boot利用Spring框架的依赖注入(DI)特性来管理Bean。开发者可以通过注解如@Component、@Service、@Repository等来声明Bean,并通过@Autowired或构造器注入依赖。


示例:定义和注入Bean
@Service
public class MyService {
    // 业务逻辑
}
 
@RestController
public class MyController {
    private final MyService myService;
 
    @Autowired
    public MyController(MyService myService) {
        this.myService = myService; // 自动装配
    }
}


自动配置原理


Spring Boot自动配置的魔法背后是@EnableAutoConfiguration注解,这个注解通过@Import引入了AutoConfigurationImportSelector类,该类负责读取META-INF/spring.factories文件中的配置,根据条件选择性地应用配置。


示例:自动配置的简化示例


假设我们有一个自动配置类MyAutoConfiguration,当classpath中存在某个特定类时,这个配置类就会被应用:

@Configuration
@ConditionalOnClass(SomeClass.class)
public class MyAutoConfiguration {
    @Bean
    public SomeBean someBean() {
        return new SomeBean();
    }
}


resources/META-INF/spring.factories文件中,我们声明这个自动配置类:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration


当Spring Boot应用启动时,如果classpath中存在SomeClass,那么SomeBean就会被自动配置。

相关文章
|
14天前
|
XML 安全 Java
|
12天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
29 2
|
1月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
12天前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
25 1
|
1月前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
24天前
|
前端开发 Java Docker
使用Docker容器化部署Spring Boot应用程序
使用Docker容器化部署Spring Boot应用程序
|
26天前
|
Java Docker 微服务
利用Docker容器化部署Spring Boot应用
利用Docker容器化部署Spring Boot应用
44 0
|
1月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
35 0
|
4月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
6月前
|
XML Java 数据格式
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
47 1