この記事を読む前に、Spring Bean のライフサイクルとは何なのかについて考えてみましょう。これは面接の際に面接官からよく聞かれる質問でもあります。
Spring 以前は、オブジェクトを作成するときは新しいメソッドを使用し、オブジェクトが使用されていないときは Java のガベージ コレクション メカニズムによってリサイクルされていました。
Spring のオブジェクトは Bean です。Bean と通常の Java オブジェクトの間に大きな違いはありませんが、Spring はそれ自体で新しいオブジェクトを作成しなくなりましたが、IoC コンテナはオブジェクトのインスタンス化と管理に役立ちます。どのオブジェクトが必要ですか? , IoC コンテナに問い合わせるだけです。IoC は実際にはオブジェクト間の結合問題を解決するものであり、Spring Bean のライフサイクルは完全にコンテナによって制御されます。
ここでは主に Bean のシングルトン スコープに焦点を当てますが、プロトタイプ Bean の場合、Spring は作成されてユーザーに渡された後のライフサイクルを管理しません。
それでは、Bean のスコープとは何なのか、確認してみましょう。
singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
prototype : 每次请求都会创建一个新的 bean 实例。
request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
global-session: 全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经被删除。
Spring Bean のライフサイクルの中核は、次のステップに分かれています。
- インスタンス化
- 属性の割り当て
- 初期化 初期化
- 破壊 破壊
インスタンス化 -> 属性の割り当て -> 初期化 -> 破棄
次に、Bean の作成を使用して Spring Bean のライフサイクルを体験します。
まず、FactoryBean とは何かについてご紹介します。
FactoryBean は BeanFactory と区別する必要があります。BeanFactory は、Bean を作成および管理する Bean ファクトリです。トップレベルのインターフェイスです。FactoryBean は、Bean 作成プロセスをカスタマイズし、複雑な Bean の定義を完了するために使用されます。
Spring には主に 2 種類の Bean があり、1 つは通常の Bean を定義するもの、もう 1 つはファクトリー Bean (FactoryBean) です。FactoryBean は、特定の種類の Bean インスタンスを生成し、このインターフェイスを実装することで Bean をインスタンス化するロジックをカスタマイズできるファクトリ Bean です。
FactoryBean は Spring フレームワークで非常に重要です。Spring 自体は、FactoryBean インターフェイスの 70 以上の実装を提供します。getBean() メソッドによって返されるのは、FactoryBean 自体ではなく、FactoryBean#getObject() メソッドによって返されるオブジェクトです。 FactoryBean#getObject () プロキシ getBean () メソッドと同等です。
FactoryBean インターフェイスのソース コード:
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
//返回由FactoryBean 创建的Bean实例,如果isSingleton()返回true,该实例会被放到Spring容器的单里缓存池中
@Nullable
T getObject() throws Exception;
//返回FactoryBean创建的Bean的类型
@Nullable
Class<?> getObjectType();
//判断Bean的作用域是singleton还是prototype
default boolean isSingleton() {
return true;
}
}
事件戦闘
- 設定ファイルの<bean>のclass属性で設定した実装クラスがFactoryBeanの場合、getBean()メソッドで返されるのはFactoryBeanそのものではありません
- 取得されるのは、FactoryBean#getObject() メソッドによって返されるオブジェクトであり、FactoryBean#getObject() による getBean() メソッドのプロキシに相当します。
- Order エンティティ クラスを作成する
@Data
public class Order {
//订单ID
private int orderId;
//订单名称
private String orderName;
//订单价格
private int price;
}
- OrderFactoryBean を作成する
public class OrderFactoryBean implements FactoryBean<Order> {
public OrderFactoryBean() {
System.out.println("FactoryBean构造方法执行");
}
private String orderInfo;
//设置orderInfo
public void setOrderInfo(String orderInfo) {
this.orderInfo = orderInfo;
}
// 11@测试订单@7999
@Override
public Order getObject() throws Exception {
String[] split = orderInfo.split("@");
Order order = new Order();
order.setOrderId(Integer.parseInt(split[0]));
order.setOrderName(split[1]);
order.setPrice(Integer.parseInt(split[2]));
return order;
}
//返回当前bean类型
@Override
public Class<?> getObjectType() {
return Order.class;
}
//返回当前bean是否为单例
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
- XML設定ファイル
<bean id="order" class="com.lixiang.factory.OrderFactoryBean">
<property name="orderInfo" value="11@测试订单@7999"/>
</bean>
- メインクラスのテスト
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:application.xml");
Order order = (Order) context.getBean("order");
System.out.println(order);
Object obj = context.getBean("&order");
System.out.println(obj);
}
次に、BeanFactoryPostProcessor を見てみましょう。
BeanFactoryPostProcessor は Spring フレームワークの重要な拡張インターフェイスであり、Spring Bean が作成される前に、Bean の定義プロパティを変更したり、サードパーティ データを挿入したりできます。これは、Spring コンテナが Bean を定義する XML ファイルをロードした後、Bean がインスタンス化される前に実行され、Bean に対して後処理を実行します。その実行ロジックは、BeanFactory の初期化時に、BeanFactory のポストプロセッサ (BeanPostProcessor) の前に実行されます。
効果:
- アプリケーション コンテキスト (ApplicationContext) 内のすべての Bean 定義を読み取ります。
- 定義内の属性値などの情報を変更します。
- 変更した定義を処理して、目的の効果が得られるようにします。
- 変更したBean定義をコンテナにフィードバックすると、コンテナはBeanの作成と初期化の処理を再実行します。
インターフェースコード
//ConfigurableListableBeanFactory 可以获取bean定义信息,里面进行修改bean定义
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
事件戦闘
- 1 つを定義し
OrderBeanFactoryPostProcessor
、Bean を単一インスタンスから複数インスタンスに変更してから、init メソッドをトリガーします。
public class OrderBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public OrderBeanFactoryPostProcessor(){
System.out.println("OrderBeanFactoryPostProcessor构造方法执行");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanStr = beanFactory.getBeanDefinitionNames();
for (String beanName : beanStr) {
if ("order".equals(beanName)) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
beanDefinition.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);
}
}
}
//testInit 初始化方法
public void testInit(){
System.out.println("OrderBeanFactoryPostProcessor testInit 方法被调用,执行初始化逻辑");
}
}
- 構成xml
<bean id="customFactoryPostProcessor" class="com.lixiang.factory.OrderBeanFactoryPostProcessor" init-method="testInit"></bean>
- テストのメインクラスを作成する
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:application.xml");
Object obj1 = context.getBean("&order");
Object obj2 = context.getBean("&order");
System.out.println(obj1);
System.out.println(obj2);
}
さて、BeanFactoryPostProcessor について話した後、もう一度 BeanPostProcessor を見てみましょう。
BeanPostProcessor は、Bean オブジェクトのインスタンス化プロセスをインターセプトおよび変更するために Spring IOC コンテナによって提供される拡張メカニズムです。デフォルトでは Spring コンテナ全体の [すべての Bean] を処理しますが、特定の Bean を処理したい場合はメソッドのパラメータで判断できます。コンテナが Bean オブジェクトをインスタンス化 (コンストラクターを実行) した後、初期化メソッドによって [前後] コールバック メソッドが実行され、Bean インスタンスの初期化中に追加されたカスタム ロジックが提供されます。
事件戦闘
- OrderBeanPostProcessor の作成
public class OrderBeanPostProcessor implements BeanPostProcessor {
public OrderBeanPostProcessor() {
System.out.println("BeanPostProcessor构造方法执行");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor postProcessAfterInitialization 调用 beanName="+beanName);
if(beanName.equalsIgnoreCase("order")){
Order order = (Order)bean;
order.setOrderName("修改后的订单名称");
return BeanPostProcessor.super.postProcessAfterInitialization(order, beanName);
}
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
- XML 構成の書き込み オブジェクトのプロパティの注文
<bean id="orderBeanPostProcessor" class="com.lixiang.factory.OrderBeanPostProcessor"></bean>
<bean id="order" class="com.lixiang.domain.Order">
<property name="orderId" value="113726"/>
<!-- 这里我们将订单名称设置为测试订单 -->
<property name="orderName" value="测试订单"/>
<property name="price" value="2131213"/>
</bean>
- テストコードを書く
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:application.xml");
Order order = (Order) context.getBean("order");
System.out.println(order);
}
-
知らせ
-
BeanPostProcessor は、Spring コンテナが Bean 定義ファイルをロードし、Bean をインスタンス化した後に実行されます。
-
BeanPostProcessor の実行順序は BeanFactoryPostProcessor の後にあります
-
BeanFactoryPostProcessor と BeanPostProcessor は両方とも、Bean 処理のライフサイクルにおける拡張ポイントであり、使用シナリオが異なります。
- BeanFactoryPostProcessor はインスタンス化の前に Bean に作用し、構成メタデータ BeanDefinition を読み取り、変更できます。
- BeanPostProcessor は Bean インスタンス化プロセスに作用し、Bean インスタンスの値を変更できます。
-
まだいくつかのインターフェイスがあります。簡単に見てみましょう。すぐにデモは行いません。
- BeanNameAware
BeanNameAware接口是为了让自身Bean能够感知到,获取到自身在Spring容器中的id或name属性。让Bean获取自己在BeanFactory配置中的名字(根据情况是id或者name)。
Spring自动调用。并且会在Spring自身完成Bean配置之后,且在调用任何Bean生命周期回调(初始化或者销毁)方法之前就调用这个方法。换言之,在程序中使用BeanFactory.getBean(String beanName)之前,Bean的名字就已经设定好了。
- BeanFactoryAware
BeanFactoryAware接口是Spring框架中的一个接口,用于在Bean实例化后,将BeanFactory实例注入到Bean中。通过实现该接口,Bean可以获取到BeanFactory实例,从而可以在运行时动态获取其他Bean的实例。
具体来说,BeanFactoryAware接口的作用是让Bean能够感知到所在的BeanFactory,从而可以在需要时获取其他Bean的实例。这对于需要动态获取其他Bean的实例的情况非常有用,例如在AOP中需要获取代理对象等。
- アプリケーションコンテキスト認識
在spring项目中,类之间的关系是spring容器来管理的,但是一个项目中有些类不受spring容器管理,缺需要使用受spring管理的bean,这时候不能通过正常的方式注入bean,这时候spring给我们提供了ApplicationContextAware接口,我们可以编写一个工具类来实现ApplicationContextAware,当一个类实现ApplicationContextAware接口后,当这个类被spring加载后,就能够在这个类中获取到spring的上下文操作符ApplicationContext,通过ApplicationContext 就能够轻松的获取所有的spring管理的bean。
- beanの初期化中
Initializingbean接口只有一个afterPropertiesSet方法,实现了这个接口的类在初始化Bean时会执行这个方法。所以这个接口的用途就是用来实现初始化数据用的。
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
- 使い捨てビーン
该接口的作用是:允许一个bean在它的所有必须属性被BeanFactory设置后,来执行初始化的工作,该接口中只有一个方法,afterPropertiesSet。
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
さて、ここで Order を使用して上記のインターフェイスを実装します。
public class Order implements BeanNameAware, BeanFactoryAware,
ApplicationContextAware, InitializingBean, DisposableBean {
private int orderId;
private String orderName;
private int price;
public Order() {
System.out.println("Order - 构造方法执行,创建对象");
}
public Order(int orderId, String orderName, int price) {
this.orderId = orderId;
this.orderName = orderName;
this.price = price;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Order{" +
"orderId=" + orderId +
", orderName='" + orderName + '\'' +
", price=" + price +
'}';
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("Order - BeanFactoryAware - setBeanFactory 方法被调用");
}
@Override
public void setBeanName(String s) {
System.out.println("Order - BeanNameAware - setBeanName 方法被调用");
}
@Override
public void destroy() throws Exception {
System.out.println("Order - DisposableBean - destroy 方法被调用");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Order - InitializingBean - afterPropertiesSet 方法被调用");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("Order - ApplicationContextAware - setApplicationContext 方法被调用");
}
}
Order オブジェクトを作成し、メソッド実行呼び出しチェーンを表示します。
メソッド呼び出しチェーン図
ソース コード分析の目標は、AbstractApplicationContext クラスの更新メソッドにあります。
OK, リフレッシュのソース コード分析を見てみましょう。基本的に、Spring ライフ サイクル全体がこのメソッドで実行されます。このコア メソッドで何が行われるかを見てみましょう。
public void refresh() throws BeansException, IllegalStateException {
//采用对象锁,保证多线程环境下,在容器正在启动/关闭时, 另一个启动/关闭操作会被阻塞
synchronized (this.startupShutdownMonitor) {
//统计Spring应用程序的启动时间,并输出到log
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
//1.调用子类覆盖的方法prepareRefresh(),为当前的工厂进行启动数据准备工作
prepareRefresh();
/**
* 2.调用子类覆盖的方法obtainFreshBeanFactory(),创建新的BeanFactory, 默认实现是DefaultListableBeanFactory
* 解析xml, 生成BeanDefinition 并注册到 BeanDefinitionRegistry
*
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//3.beanFactory准备工作,调用子类覆盖的方法prepareBeanFactory(),对新的BeanFactory进行各种后置处理
prepareBeanFactory(beanFactory);
try {
//4.beanFactory准备工作完成后,继续进行的【后置处理】
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
//5.BeanFactoryPostProcessor
//Spring 启动时查找所有实现 BeanFactoryPostProcessor 接口的类,并逐一调用其 postProcessBeanFactory 方法
invokeBeanFactoryPostProcessors(beanFactory);
//6.BeanPostProcessor
//注册 BeanPostProcessor,负责为该 Bean 对象创建代理对象
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
//7.初始化信息源,用来支持国际化
initMessageSource();
//8.初始化事件广播器,用来支持了Spring事件机制
initApplicationEventMulticaster();
//9.留给子类实现的初始化操作,即调用自定义的回调方法
onRefresh();
//10.注册实现了ApplicationListener接口的类
registerListeners();
/**
* 11.实例化所有剩余的单例Bean(非懒加载的单例bean),注意这里要区分单例和非单例Bean,主要下面的工作
* 填充属性
* 调用初始化方法 afterPropertiesSet、init-method方法
* 调用BeanPostProcessor 后置处理器 postProcessBeforeInitialization和postProcessAfterInitialization执行
*/
finishBeanFactoryInitialization(beanFactory);
//12.事件发布,发送ContextRefreshedEvent事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
// 销毁已经创建的单例bean
destroyBeans();
// 将 context 的 active 属性重置为 false
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
// 重置Spring IOC中的共享缓存,避免单例bean的引用问题
resetCommonCaches();
//更新contextRefresh的状态
contextRefresh.end();
}
}
}
要約する
-
まず、Bean コンストラクターまたはファクトリ メソッドを呼び出し、構成に従って Bean をインスタンス化します。
-
次に、リフレクションを使用して、Bean 内のすべてのプロパティ値の構成インジェクションを設定するオブジェクトを作成します。
-
Bean が BeanNameAware インターフェースを実装している場合、Spring は Bean の setBeanName() メソッドを呼び出して、現在の Bean の ID 値を渡します。
-
Bean が BeanFactoryAware インターフェースを実装している場合、Spring は setBeanFactory() メソッドを呼び出し、現在のファクトリ インスタンスへの参照を渡します。
-
Bean が ApplicationContextAware インターフェースを実装している場合、Spring は setApplicationContext() メソッドを呼び出して、現在の ApplicationContext インスタンスへの参照を渡します。
-
BeanPostProcessor が Bean に関連付けられている場合、Spring はインターフェースの初期化前メソッド postProcessBeforeInitialzation() を呼び出して Bean を処理します。これはここで非常に重要であり、これを使用することで Spring の AOP が実現されます。
-
Bean が InitializingBean インターフェースを実装している場合、Spring は afterPropertiesSet() メソッドを呼び出します。初期化メソッドが構成ファイルの init-method 属性で指定されている場合、初期化メソッドが呼び出されます。
-
BeanPostProcessor が Bean に関連付けられている場合、Spring はインターフェースの初期化メソッド postProcessAfterInitialization() を呼び出します。この時点で、Bean はアプリケーション システムで使用できるようになります。
-
Bean のスコープがscope=“singleton”として指定されている場合、Bean のロールが「スコープがスコープの場合」で指定されている場合、Bean は Spring IoC キャッシュ プールに配置され、Spring による Bean のライフサイクル管理がトリガーされます。 ="prototype" の場合、Bean は呼び出し元に渡され、呼び出し元が Bean のライフサイクルを管理し、Spring は Bean を管理しなくなります。
-
Bean が DisposableBean インターフェースを実装している場合、Spring は destroy() メソッドを呼び出して Spring で Bean を破棄します; Bean の破棄メソッドが構成ファイルの destroy-method 属性で指定されている場合、Spring はこのメソッドを呼び出して Bean を破棄します。
OK、これまでのところ、Spring Bean のライフサイクル全体が解決されました。