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就会被自动配置。

相关文章
|
26天前
|
缓存 Java Spring
Spring 框架中 Bean 的生命周期
Spring 框架中 Bean 的生命周期
33 1
|
1天前
|
XML Java 数据格式
手写spring第八章-定义标记类型Aware接口,实现感知容器对象
手写spring第八章-定义标记类型Aware接口,实现感知容器对象
4 0
|
1天前
|
XML Java 数据格式
手写spring第七章-完成便捷实现bean对象初始化和销毁方法
手写spring第七章-完成便捷实现bean对象初始化和销毁方法
6 0
|
1天前
|
Java uml Spring
手写spring第四章-完善bean实例化,自动填充成员属性
手写spring第四章-完善bean实例化,自动填充成员属性
8 0
|
1天前
|
设计模式 存储 Java
手写spring第二章-运用设计模式编写可扩展的容器
手写spring第二章-运用设计模式编写可扩展的容器
7 0
|
2天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
3天前
|
XML Java 数据格式
【spring】01 Spring容器研究
【spring】01 Spring容器研究
7 0
|
10天前
|
Java 数据库连接 开发者
浅谈Spring的Bean生命周期
浅谈Spring的Bean生命周期
18 1
|
15天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
21 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
24天前
|
XML Java 数据格式
Spring(一)IOC小案例
Spring(一)IOC小案例