序文
実は面接の質問です。百度に面接したときに聞いたのですが、当時は(本当に上手だったので)答えませんでした。後でインターネットで答えを探して混乱しました。 「実際に」では、Beanのライフサイクルの一般的な説明がありますが、コード分析がないため、インターネットにアクセスして自分で情報を見つけました。Beanのライフサイクルを理解する必要があります。
インターネット上のほとんどのBeanは、インタビューのライフサイクルで検証されます。実際、JDKを参照すると、完全なBeanライフサイクルがあります。これにより、本が一方的なものであることが検証されます。最も新鮮な情報は、元のJDKを参照してください!!!
1.Beanの完全なライフサイクル
従来のJavaアプリケーションでは、Beanのライフサイクルは非常に単純です。Javaキーワードnewを使用してBeanをインスタンス化すると、Beanを使用できるようになります。Beanが使用されなくなると、Javaによって自動的にガベージコレクションされます。
対照的に、Spring管理Beanのライフサイクルははるかに複雑です。SpringによるBeanの管理は非常に拡張可能であるため、Beanのライフサイクルを正しく理解することが非常に重要です。以下に、Beanの構築プロセスを示します。
上の図に示すように、Beanのライフサイクルは非常に複雑です。次の図の各ステップについて説明しましょう。
- Springが開始し、Springで管理する必要のあるBeanを検索してロードし、Beanをインスタンス化します。
- Beanがインスタンス化された後、Beanの導入と値がBeanの属性に注入されます
- BeanがBeanNameAwareインターフェースを実装している場合、SpringはBeanのIDをsetBeanName()メソッドに渡します。
- BeanがBeanFactoryAwareインターフェースを実装している場合、SpringはsetBeanFactory()メソッドを呼び出してBeanFactoryコンテナーインスタンスを渡します。
- BeanがApplicationContextAwareインターフェースを実装している場合、SpringはBeanのsetApplicationContext()メソッドを呼び出し、Beanが配置されているアプリケーションコンテキスト参照を渡します。
- BeanがBeanPostProcessorインターフェースを実装している場合、SpringはpostProcessBeforeInitialization()メソッドを呼び出します。
- BeanがInitializingBeanインターフェースを実装している場合、SpringはafterPropertiesSet()メソッドを呼び出します。同様に、Beanがinit-methodを使用して初期化メソッドを宣言する場合、メソッドも呼び出されます
- BeanがBeanPostProcessorインターフェースを実装している場合、SpringはpostProcessAfterInitialization()メソッドを呼び出します。
- この時点で、Beanはアプリケーションで使用できるようになります。それらは、アプリケーションコンテキストが破棄されるまで、アプリケーションコンテキストにとどまります。
- BeanがDisposableBeanインターフェースを実装している場合、Springはそのdestroy()インターフェースメソッドを呼び出します。同様に、Beanがdestroy-method宣言メソッドを使用している場合、このメソッドも呼び出されます。
上記は、SpringにおけるBeanのコアインターフェイスとライフサイクルです。上記のプロセスに答えるインタビューで十分です。ただし、JavaDocドキュメントを見ると、上記のインターフェイスに加えて、初期化プロセスに関係する他のインターフェイスがあります。
org.springframework.beans.factory.BeanFactoryから抜粋した、関連するすべてのインターフェースは次のとおりです。上記の既存のインターフェースを強調表示する必要はありません。追加の関連するインターフェースを以下に強調表示します。
Beanの完全なライフサイクル
テキストは次のように説明されています。
------------初期化------------
- BeanNameAware.setBeanName()は、このBeanを作成したBeanファクトリでBeanの名前を設定し、通常のプロパティ設定の後に呼び出され、InitializinngBean.afterPropertiesSet()メソッドの前に呼び出されます。
- BeanClassLoaderAware.setBeanClassLoader():通常のプロパティが設定された後、InitializingBean.afterPropertiesSet()の前に呼び出されます
- BeanFactoryAware.setBeanFactory():コールバックは、独自のBeanインスタンスファクトリを提供します。これは、通常のプロパティ設定の後、InitializingBean.afterPropertiesSet()またはカスタム初期化メソッドの前に呼び出されます。
- EnvironmentAware.setEnvironment():コンポーネントの使用中に呼び出される環境を設定します
- EmbeddedValueResolverAware.setEmbeddedValueResolver():StringValueResolverを設定して、埋め込み値の範囲の問題を解決します
- ResourceLoaderAware.setResourceLoader():通常のBeanオブジェクトの後、afterPropertiesSetまたはカスタムinitメソッドの前、およびApplicationContextAwareの前に呼び出されます。
- ApplicationEventPublisherAware.setApplicationEventPublisher():通常のBeanプロパティの後、初期化の前に、afterPropertiesSetまたはカスタム初期化メソッドを呼び出します。ApplicationContextAwareの前に呼び出されます。
- MessageSourceAware.setMessageSource():通常のBeanプロパティの後、afterPropertiesSetまたはカスタム初期化メソッドを初期化する前、およびApplicationContextAwareの前に呼び出されます。
- ApplicationContextAware.setApplicationContext():通常のBeanオブジェクトが生成された後、InitializingBean.afterPropertiesSetを呼び出す前、またはユーザー定義の初期化メソッドの前に呼び出されます。ResourceLoaderAware.setResourceLoader、ApplicationEventPublisherAware.setApplicationEventPublisher、MessageSourceAwareの後に呼び出されます。
- ServletContextAware.setServletContext():実行時にServletContextを設定し、通常のBeanの初期化後に呼び出し、InitializingBean.afterPropertiesSetの前に呼び出し、ApplicationContextAwareの後に呼び出します 注:WebApplicationContextが実行されているときです。
- BeanPostProcessor.postProcessBeforeInitialization():このBeanPostProcessorは、指定された新しいBeanインスタンスに適用され、Bean初期化コールバックメソッド(InitializingBean.afterPropertiesSetやカスタム初期化メソッドなど)の前に呼び出されます。このBeanは、プロパティの値を設定する準備ができています。返されるBeanの例は通常のオブジェクトでラップされ、デフォルトの実装はBeanを返します。
- BeanPostProcessor.postProcessAfterInitialization():このBeanPostProcessorは、指定された新しいBeanインスタンスに適用され、Bean初期化コールバックメソッド(InitializingBean.afterPropertiesSetやカスタム初期化メソッドなど)の後に呼び出されます。このBeanは、プロパティの値を設定する準備ができています。返されたBeanの例は、通常のオブジェクトでラップされている可能性があります
- InitializingBean.afterPropertiesSet():すべてのBeanプロパティを設定した後にBeanFactoryによって呼び出されます(そしてBeanFactoryとApplicationContextAwareを満たします)。
- - - - - - 破壊 - - - - - -
BeanFactoryが閉じられると、Beanのライフサイクルは次のメソッドを呼び出します。
DestructionAwareBeanPostProcessor.postProcessBeforeDestruction()
次に、Beanのライフサイクル検証
Beanのライフサイクルプロセスを検証するために、2つの形式があります。1つはインタビュー用に準備され、もう1つはプロセス全体を理解するために準備されています。以下のコードを見てみましょう。
- Book.class
public class Book implements BeanNameAware,BeanFactoryAware,
ApplicationContextAware,InitializingBean,DisposableBean {
private String bookName;
public Book(){
System.out.println("Book Initializing ");
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("Book.setBeanFactory invoke");
}
public void setBeanName(String name) {
System.out.println("Book.setBeanName invoke");
}
public void destroy() throws Exception {
System.out.println("Book.destory invoke");
}
public void afterPropertiesSet() throws Exception {
System.out.println("Book.afterPropertiesSet invoke");
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("Book.setApplicationContext invoke");
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
System.out.println("setBookName: Book name has set.");
}
public void myPostConstruct(){
System.out.println("Book.myPostConstruct invoke");
}
// 自定义初始化方法
@PostConstruct
public void springPostConstruct(){
System.out.println("@PostConstruct");
}
public void myPreDestory(){
System.out.println("Book.myPreDestory invoke");
System.out.println("---------------destroy-----------------");
}
// 自定义销毁方法
@PreDestroy
public void springPreDestory(){
System.out.println("@PreDestory");
}
@Override
protected void finalize() throws Throwable {
System.out.println("------inside finalize-----");
}
}
- BeanPostProcessorを実装するMyBeanPostProcessorをカスタマイズします。
public class MyBeanPostProcessor implements BeanPostProcessor {
// 容器加载的时候会加载一些其他的bean,会调用初始化前和初始化后方法
// 这次只关注book(bean)的生命周期
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Book){
System.out.println("MyBeanPostProcessor.postProcessBeforeInitialization");
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Book){
System.out.println("MyBeanPostProcessor.postProcessAfterInitialization");
}
return bean;
}
}
- resourcesディレクトリに新しいBean-Lifecycle.xmlを作成します
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描bean -->
<context:component-scan base-package="com.bean.lifecycle"/>
<!-- 实现了用户自定义初始化和销毁方法 -->
<bean id="book" class="com.bean.lifecycle.Book" init-method="myPostConstruct" destroy-method="myPreDestory">
<!-- 注入bean 属性名称 -->
<property name="bookName" value="thingking in java" />
</bean>
<!--引入自定义的BeanPostProcessor-->
<bean class="com.bean.lifecycle.MyBeanPostProcessor"/>
</beans>
- スタートアップクラスのテストを実行し、新しいSpringBeanLifecycleApplicationを作成します
public class SpringBeanLifecycleApplication {
public static void main(String[] args) throws InterruptedException {
// 为面试而准备的Bean生命周期加载过程
ApplicationContext context = new ClassPathXmlApplicationContext("Bean-Lifecycle.xml");
Book book = (Book)context.getBean("book");
System.out.println("Book name = " + book.getBookName());
((ClassPathXmlApplicationContext) context).destroy();
}
}
テストを開始すると、出力結果は次のようになります。
ブック初期化setBookName:ブック名が設定されました。Book.setBeanName invoke Book.setBeanFactory invoke Book.setApplicationContext invoke MyBeanPostProcessor.postProcessBeforeInitialization @PostConstruct Book.afterPropertiesSet invoke Book.myPostConstruct invoke MyBeanPostProcessor.postProcessAfterInitialization Book name = thingsking in java
@PreDestory Book.destory invoke Book.myPreDestory invoke --------------- destroy -----------------
- Beanの完全なライフサイクルを確認するには、Bookクラスを継承する新しいSubBookClassを作成する必要があります。
public class SubBookClass extends Book implements BeanClassLoaderAware,
EnvironmentAware,EmbeddedValueResolverAware,ResourceLoaderAware,
ApplicationEventPublisherAware,MessageSourceAware{
private String bookSystem;
public String getBookSystem() {
return bookSystem;
}
public void setBookSystem(String bookSystem) {
System.out.println("设置BookSystem 的属性值");
this.bookSystem = bookSystem;
}
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("SubBookClass.setBeanClassLoader() 方法被调用了");
}
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
System.out.println("SubBookClass.setApplicationEventPublisher() 方法被调用了");
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
System.out.println("SubBookClass.setEmbeddedValueResolver() 方法被调用了");
}
public void setEnvironment(Environment environment) {
System.out.println("SubBookClass.setEnvironment() 方法被调用了");
}
public void setMessageSource(MessageSource messageSource) {
System.out.println("SubBookClass.setMessageSource() 方法被调用了");
}
public void setResourceLoader(ResourceLoader resourceLoader) {
System.out.println("SubBookClass.setResourceLoader() 方法被调用了");
}
}
上記のSubBookClassとBookは補完的です。
- 新しいSubBean-Lifecycle.xmlを作成し、SubBookClassを挿入します
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="bookClass" class="com.bean.lifecycle.SubBookClass" init-method="myPostConstruct" destroy-method="myPreDestory">
<property name="bookSystem" value="Java System" />
</bean>
<bean class="com.bean.lifecycle.MyBeanPostProcessor"/>
</beans>
- 完全なSpringBeanLifecycleApplicationは次のとおりです。
public class SpringBeanLifecycleApplication {
public static void main(String[] args) throws InterruptedException {
// 为面试而准备的Bean生命周期加载过程
ApplicationContext context = new ClassPathXmlApplicationContext("Bean-Lifecycle.xml");
Book book = (Book)context.getBean("book");
System.out.println("Book name = " + book.getBookName());
((ClassPathXmlApplicationContext) context).destroy();
// 完整的加载过程,当然了解的越多越好
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SubBean-Lifecycle.xml");
SubBookClass subBookClass = (SubBookClass) applicationContext.getBean("bookClass");
System.out.println("BookSystemName = " + subBookClass.getBookSystem());
((ClassPathXmlApplicationContext) applicationContext).registerShutdownHook();
}
}
完全な結果を出力します。
ブック初期化setBookName:ブック名が設定されました。Book.setBeanName invoke Book.setBeanFactory invoke Book.setApplicationContext invoke MyBeanPostProcessor.postProcessBeforeInitialization @PostConstruct Book.afterPropertiesSet invoke Book.myPostConstruct invoke MyBeanPostProcessor.postProcessAfterInitialization Book name = thingking in java @PreDestory Book.destory invoke Book.myPreDestory invoke ------ - - - - -破壊 - - - - - - - - -
Book Initializingは、BookSystemのプロパティ値を設定します。Book.setBeanNameinvokeSubBookClass.setBeanClassLoader()メソッドはBook.setBeanFactoryを呼び出します。invokeSubBookClass.setEnvironment()メソッドはSubBookClass.setEmbeddedValueResolver()メソッドを呼び出します。SubBookClass.setResourceLoader()メソッドはSubBookClassと呼ばれます。 .setApplicationEventPublisher()メソッドが呼び出されます。SubBookClass.setMessageSource()メソッドが呼び出されます。Book.setApplicationContextinvokeMyBeanPostProcessor.postProcessBeforeInitializationBook.afterPropertiesSet invoke Book.myPostConstruct invoke MyBeanPostProcessor.postProcessAfterInitialization BookSystemName = Java System BookDestory invoke-myPreDestoryinvoke。---- - - - - - 破壊 - - - - - - - - -