Spring's Road to God 第 55 章: Spring コンテキストのライフサイクル
この記事の主な内容: Spring アプリケーション コンテキストのライフ サイクルを全員でマスターします。
なぜこれをマスターする必要があるのでしょうか?
1. 面接中によく聞かれる質問に答える
2. プロジェクトの春を拡張したい場合は、コンテンツのこの部分をマスターする必要があります
3. ソースコードが読みやすくなる
1. Spring アプリケーション コンテキストとは何ですか?
このインターフェイスはorg.springframework.context.ApplicationContext
Spring コンテキストと次の 2 つの実装クラスを表します。
org.springframework.context.support.ClassPathXmlApplicationContext
org.springframework.context.annotation.AnnotationConfigApplicationContext
2.上記のライフサイクルを適用(14段階)
1. Spring アプリケーション コンテキストを作成する
2. コンテキスト起動準備フェーズ
3. BeanFactory 作成フェーズ
4. BeanFactoryの準備段階
5. BeanFactory の後処理段階
6. BeanFactory は BeanPostProcessor ステージを登録します
7. 組み込みBean: MessageSourceを初期化します。
8. 組み込み Bean の初期化: Spring イベント ブロードキャスター
9. Spring アプリケーション コンテキストの更新フェーズ
10. 春のイベントリスナー登録フェーズ
11. シングルトン Bean のインスタンス化フェーズ
12. BeanFactory初期化完了段階
13. Springアプリケーションコンテキスト起動完了フェーズ
14. Spring アプリケーション コンテキストの終了フェーズ
3. Spring アプリケーション コンテキストの使用
このコードを見てください。見覚えがありますか? これは、Spring コンテキストの最も一般的な使用法です。後で、このコードを例として取り上げ、Spring のソース コードを結合して、各段階の詳細を詳しく説明します。
@Configuration
@ComponentScan
public class MainConfig {
public static void main(String[] args) {
//1.创建spring上下文
AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext();
//2.上下文中注册bean
configApplicationContext.register(MainConfig.class);
//3.刷新spring上下文,内部会启动spring上下文
configApplicationContext.refresh();
//4.关闭spring上下文
System.out.println("stop ok!");
}
}
4. フェーズ 1: Spring アプリケーション コンテキストを作成する
このコードに対応します
AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext();
そのクラス図を見てください。ここには主にAnnotationConfigApplicationContext
2 つの親クラスがリストされています。
GenericApplicationContext
サブクラスのコンストラクタを呼び出すと、デフォルトでは親クラスのコンストラクタが自動的に最初に呼び出されます まずコンストラクタのソースコードを見てみますと、以下のようにbeanFactoryが作成されます。
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
AnnotationConfigApplicationContext
次のように、コンストラクターのソース コードを見てみましょう。
public AnnotationConfigApplicationContext() {
//创建AnnotatedBeanDefinitionReader:用来读取及注册通过注解方式定义的bean
this.reader = new AnnotatedBeanDefinitionReader(this); //@1
//创建ClassPathBeanDefinitionScanner:bean定义扫描器,可以扫描包中的类,对满足条件的类,会将其注册到spring容器中
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
@1:new AnnotatedBeanDefinitionReader(this)
このメソッドの内部に入ると、最終的に次の非常に重要なメソッドに進み、Spring コンテナーに 5 つのキー Bean を登録します。これらの Bean は非常に重要です。
org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
//1、注册ConfigurationClassPostProcessor,这是个非常关键的类,实现了BeanDefinitionRegistryPostProcessor接口
// ConfigurationClassPostProcessor这个类主要做的事情:负责所有bean的注册,如果想看bean注册源码的,可以在其postProcessBeanDefinitionRegistry方法中设置断点
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//2、注册AutowiredAnnotationBeanPostProcessor:负责处理@Autowire注解
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//3、注册CommonAnnotationBeanPostProcessor:负责处理@Resource注解
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//4、注册EventListenerMethodProcessor:负责处理@EventListener标注的方法,即事件处理器
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
//5、注册DefaultEventListenerFactory:负责将@EventListener标注的方法包装为ApplicationListener对象
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
上記のコードをもう一度見てみましょう。主に 5 つのキー Bean を Spring コンテナーに登録します。
1. ConfigurationClassPostProcessor : これは非常に重要なクラスです。ソース コードを確認することをお勧めします。基本的に、カスタム Bean はこのクラスを通じて登録されます。次のアノテーションはすべてこのクラスで処理されます。
@Configuration
@Component
@PropertySource
@PropertySources
@ComponentScan
@ComponentScans
@Import
@ImportResource
@Bean
2. AutowiredAnnotationBeanPostProcessor : @Autowire アノテーションの処理を担当します
3. CommonAnnotationBeanPostProcessor を登録します: @Resource アノテーションの処理を担当します
4. EventListenerMethodProcessor を登録します。 @EventListener でマークされたメソッド、つまりイベント プロセッサの処理を担当します。
5. DefaultEventListenerFactory を登録します。 @EventListener でマークされたメソッドを ApplicationListener オブジェクトにパッケージ化します。
4. ステージ2~ステージ13
ステージ 2 からステージ 13 まで、中間の 12 ステージはすべてリフレッシュ メソッドに位置するため、リフレッシュ メソッドは非常に重要であり、このメソッドを学習するにはさらに時間がかかります。
リフレッシュメソッドのソースコードは以下のとおりです。
org.springframework.context.support.AbstractApplicationContext#refresh
@Override
public void refresh() throws BeansException, IllegalStateException {
// 阶段2:Spring应用上下文启动准备阶段
prepareRefresh();
// 阶段3:BeanFactory创建阶段
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 阶段4:BeanFactory准备阶段
prepareBeanFactory(beanFactory);
try {
// 阶段5:BeanFactory后置处理阶段
postProcessBeanFactory(beanFactory);
// 阶段6:BeanFactory注册BeanPostProcessor阶段
invokeBeanFactoryPostProcessors(beanFactory);
// 阶段7:注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 阶段8:初始化内建Bean:MessageSource
initMessageSource();
// 阶段9:初始化内建Bean:Spring事件广播器
initApplicationEventMulticaster();
// 阶段10:Spring应用上下文刷新阶段,由子类实现
onRefresh();
// 阶段11:Spring事件监听器注册阶段
registerListeners();
// 阶段12:实例化所有剩余的(非lazy init)单例。
finishBeanFactoryInitialization(beanFactory);
// 阶段13:刷新完成阶段
finishRefresh();
}
}
フェーズ 2: Spring アプリケーション コンテキストの起動準備フェーズ
protected void prepareRefresh() {
// 标记启动时间
this.startupDate = System.currentTimeMillis();
// 是否关闭:false
this.closed.set(false);
// 是否启动:true
this.active.set(true);
// 初始化PropertySource,留个子类去实现的,可以在这个方法中扩展属性配置信息,丢到this.environment中
initPropertySources();
// 验证环境配置中是否包含必须的配置参数信息,比如我们希望上下文启动中,this.environment中必须要有某些属性的配置,才可以启动,那么可以在这个里面验证
getEnvironment().validateRequiredProperties();
// earlyApplicationListeners用来存放早期的事件监听器
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// earlyApplicationEvents用来存放早期的事件
this.earlyApplicationEvents = new LinkedHashSet<>();
}
ここでの初期イベントとは何ですか?初期イベント リスナーとは何ですか?
Spring コンテキストを使用してイベントを発行する場合、次のコード
applicationContext.publishEvent(事件对象)
最終的には次の属性を使用してAbstractApplicationContext
イベントを公開しますが、applicationEventMulticaster
現時点では作成されていない可能性があります。空のオブジェクトであるため、現時点ではイベントをブロードキャストできません。この時点でのリリース時間は早い時間です。に一時的に保存されthis.earlyApplicationEvents
、ブロードキャスターがapplicationEventMulticaster
作成されると、初期のイベントがブロードキャストされます
private ApplicationEventMulticaster applicationEventMulticaster;
同様に、applicationEventMulticaster
Spring コンテキストの準備ができていないときに次のコードを呼び出して Spring コンテキストにイベント リスナーを追加すると、この時点で追加されるリスナーが初期のイベント リスナーになります。
applicationContext.addApplicationListener(事件监听器对象)
ここまでは述べましたが、理解するのは非常に簡単です。つまり、イベント ブロードキャスターのapplicationEventMulticaster
準備ができていない場合、この時点でコンテキストに追加されるイベントは初期のイベントであり、中央に配置され、this.earlyApplicationEvents
このイベントを追加することはできません。現時点では臨時で放送します。
フェーズ 3: BeanFactory 作成フェーズ
このステージは、BeanFactory を作成し、それを Spring アプリケーション コンテキストに返す役割を果たします。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
obtainFreshBeanFactory
ソースコード:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新BeanFactory,由子类实现
refreshBeanFactory();
//返回spring上下文中创建好的BeanFacotry
return getBeanFactory();
}
フェーズ 4: BeanFactory の準備フェーズ
prepareBeanFactory(beanFactory);
ソースコードは次のとおりです
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 设置spel表达式解析器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 设置属性编辑器注册器
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// @1:添加一个BeanPostProcessor:ApplicationContextAwareProcessor,当你的bean实现了spring中xxxAware这样的接口,那么bean创建的过程中,将由ApplicationContextAwareProcessor来回调这些接口,将对象注入进去
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// @2:自动注入的时候,下面这些接口定义的方法,将会被跳过自动注入,为什么?因为这部分接口将由ApplicationContextAwareProcessor来回调注入
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// @3:注册依赖注入的时候查找的对象,比如你的bean中想用ResourceLoader,那么可以写:@Autowire private ResourceLoader resourceLoader,那么spring容器会将spring容器上下文注入进去
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// @4:注入一个beanpostprocessor:ApplicationListenerDetector
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// @5:将Environment注册到spring容器,对应的bena名称是environment
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
// @6:将系统属性注册到spring容器,对应的bean名称是systemProperties
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
// @7:将系统环境变量配置信息注入到spring容器,对应的bean名称是systemEnvironment
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
まず @1 のコードを見てみましょう
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
ApplicationContextAwareProcessor は、BeanPostProcessor (Bean プロセッサ) である Spring コンテナに注入されます。多くのメソッドがこのインターフェイスで定義されており、Bean 作成のさまざまな段階で呼び出され、Bean 作成プロセスを拡張するためによく使用されます。さらに詳しく知りたい場合は、まずこの記事を読んでください: Bean のライフサイクル。
このインターフェースに戻ってApplicationContextAwareProcessor
そのソース コードを見ると、それが何をするのかが誰でもわかります。次のように、Bean が Aware などのインターフェースを実装すると、インターフェース内のメソッドがコールバックされ、カスタム Bean で使用されます。 Bean で使用するような Spring コンテキストは、インターフェイスをEnvironment
実装するだけで済み、自動的に挿入されます。EnvironmentAware
Environment
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
**@3** のコードを見てみましょう
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
これは依存関係参照のオブジェクトを Spring コンテナに追加するために使用されます。上記のコードの最初の行は BeanFactory を追加することです。Bean で BeanFactory を使用したい場合は、次のように記述するだけで、自動的に追加されます上記のコードの最初の行によって BeanFactory が依存関係ルックアップ リストに追加された場合でも、
@Autowire
private BeanFactory beanFactory;
もう一度@4
コードを見てください
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
ApplicationListenerDetector も BeanPostProcessor ですが、このクラスは何のためにあるのでしょうか? カスタム イベント リスナーを処理します。
Bean がApplicationListener
インターフェースを実装し、イベント リスナーである場合、Bean 作成プロセスは ApplicationListenerDetector によって処理され、Bean は Spring コンテキスト コンテナーのイベント リスナー リストに追加されます。
@5のコードをもう一度見てください
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
SpringコンテナのシングルトンリストにEnvironmentをシングルトンとして登録し、対応するbena名をenvironmentとする Bean内でEnvironmentを使用する必要がある場合、以下のような書き方ができる この時点でBeanを作成する過程でSpring コンテナーでは、環境のみがシングルトン Bean リストから検索され、次のプロパティに挿入されます。
@Autowire
private Environment environment
environment
次のように、Spring コンテナから環境オブジェクトを名前で検索することもできます。
applicationContext.getBean("environment", Environment.class)
@6、@7 のコードをもう一度見てください。
これは @5 と同じコードです。ここで説明します。
getEnvironment().getSystemProperties() -- 对应 --> System.getProperties()
getEnvironment().getSystemEnvironment() -- 对应 --> System.getenv()
System.getProperties() と System.getenv() が何を行うかについて話しましょう。
誰もが次のコマンドを使用したことがあります。-D を見てみましょう。これにより、いくつかの起動パラメータを設定できます。-D に続くパラメータは、System.getProperties() に配置されます。
java -jar -D参数=值
System.getenv() は、環境変数情報を取得するために使用されます。
フェーズ 5: BeanFactory の後処理フェーズ
postProcessBeanFactory(beanFactory);
このメソッドの実装はサブクラスに任されています。この時点では、beanFactory は作成されていますが、コンテナ内の Bean はまだインスタンス化されていません。サブクラスはこのメソッドを実装でき、カスタム メソッドの追加など、BeanFactory でいくつかの特別な構成を実行できます。 BeanPostProcessor などは、主にサブクラスが拡張するために予約されています。
フェーズ 6: BeanFactory による BeanPostProcessor フェーズの登録
invokeBeanFactoryPostProcessors(beanFactory);
BeanFactoryPostProcessor を呼び出します。BeanFactoryPostProcessor は何をしますか?
最初にこの記事を読むことをお勧めします: Spring シリーズの記事 29: BeanFactory 拡張機能 (BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor)
この段階では主に、Spring コンテナから BeanFactoryPostProcessor インターフェースのすべての実装クラスを検索し、すべての Bean 登録関数を呼び出して完了します。Bean 登録とは、Bean 定義情報を BeanDefinition オブジェクトに変換し、それを Bean に登録することであることに注意してください。 Spring コンテナー この時点では Bean はまだインスタンス化されていないため、以下に進みます。
フェーズ 1 を振り返ってみましょう。フェーズ 1 では、非常に重要な Bean を Spring コンテナに登録します: ConfigurationClassPostProcessor。コードは次のとおりです。
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
ConfigurationClassPostProcessor は BeanFactoryPostProcessor インターフェースを実装しているため、ConfigurationClassPostProcessor はフェーズ 6 で呼び出されます。以下のアノテーションはすべてこのクラスで処理されるため、以下のアノテーションの原理を学びたい場合は、ConfigurationClassPostProcessor のソース コードを直接参照してください。重要なAクラス、Springのソースコードの学習、この種の必見
@Configuration
@Component
@PropertySource
@PropertySources
@ComponentScan
@ComponentScans
@Import
@ImportResource
@Bean
通常、ステージ 6 の実行後、すべてのカスタム Bean は Spring コンテナに登録され、BeanDefinition に変換されて BeanFactory にスローされますが、Bean はまだインスタンス化されていません。
フェーズ 7: BeanPostProcessor の登録
registerBeanPostProcessors(beanFactory);
BeanPostProcessor を登録するこの段階では、Spring コンテナの Bean 定義リストを走査し、BeanPostProcessor インターフェースを実装するすべての Bean を取り出し、それらを Spring コンテナの BeanPostProcessor リストに追加します。
BeanPostProcessor は Bean ポストプロセッサであり、Bean 作成のプロセスを拡張するための多くのメソッドを内部的に提供します。
フェーズ 8: 組み込み Bean: MessageSource を初期化します。
initMessageSource();
MessageSource は国際化を処理するために使用されます。この段階で、MessageSource が作成されます。各国化を拡張または実装する場合は、このメソッドのソース コードを確認してください。
国際化については、次の記事を参照してください: Spring シリーズの記事 26: 国際化の詳細な説明
フェーズ 9: 組み込み Bean の初期化: Spring イベント ブロードキャスター
initApplicationEventMulticaster();
ApplicationEventMulticaster は、イベントのブロードキャストに使用されるイベント ブロードキャスターです。この段階で、ApplicationEventMulticaster が作成されます。イベント ブロードキャスターをカスタマイズする場合は、このメソッドのソース コードを参照してください。スプリング イベントの使用方法については、「Spring イベントの使用方法」を参照してください。こちら:春シリーズ第27回記事:春イベントの仕組みを詳しく解説
フェーズ 10: Spring アプリケーション コンテキストの更新フェーズ (サブクラスによって実装される)
onRefresh();
サブクラスによって実装される他の特別な Bean を初期化するために使用されます。
フェーズ 11: Spring イベント リスナー登録フェーズ
registerListeners();
次のように、イベント リスナーをイベント ブロードキャスターに登録し、そのソース コードを確認します。
protected void registerListeners() {
// @1:先注册静态指定的侦听器,即将spring上下文中添加的时间监听器,添加到时间广播器(ApplicationEventMulticaster)中
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// @2:将spring容器中定义的事件监听器,添加到时间广播器(ApplicationEventMulticaster)中
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// @3:此时事件广播器准备好了,所以此时发布早期的事件(早期的事件由于事件广播器还未被创建,所以先被放在了earlyApplicationEvents中,而此时广播器创建好了,所以将早期的时间发布一下)
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
ここでは主に @1 について説明し、コンテキスト内のイベント リスナーをイベント ブロードキャスターに追加します。理解するには以下のソース コードを参照してください。
org.springframework.context.support.AbstractApplicationContext
Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
public Collection<ApplicationListener<?>> getApplicationListeners() {
return this.applicationListeners;
}
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
Assert.notNull(listener, "ApplicationListener must not be null");
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(listener);
}
this.applicationListeners.add(listener);
}
もう一度 @3 を見てみましょう、初期のイベントをブロードキャストします。初期の頃は、イベント ブロードキャスターがthis.applicationEventMulticaster
まだ空だったので、イベントはthis.earlyApplicationEvents
このコレクションに配置され、ブロードキャストされませんでした。初期のイベントをブロードキャストするには、この時間まで待ってください。イベント、全員が注意する必要があります。ステージ 11 より前に次のメソッドを呼び出してイベントを公開すると、現時点ではイベントの効果が表示されない可能性があります。
applicationContext.publishEvent(事件对象)
したがって、Bean が次のインターフェースを実装している場合、インターフェースを実装することはお勧めできませんorg.springframework.context.ApplicationListener
。そうしないと、説明が難しくなるでしょう。
org.springframework.beans.factory.config.BeanFactoryPostProcessor
org.springframework.beans.factory.config.BeanPostProcessor
フェーズ 12: 残りのすべての (遅延初期化ではない) シングルトンをインスタンス化します。
finishBeanFactoryInitialization(beanFactory);
このメソッドでは、すべてのシングルトン Bean がインスタンス化されます (遅延インスタンス化が必要な Bean は含まれません)。そのソース コードを見てみましょう。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 添加${}表达式解析器
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 冻结所有bean定义,表示已注册的bean定义不会被进一步修改或后处理。这允许工厂主动缓存bean定义元数据。
beanFactory.freezeConfiguration();
// @1:实例化所有单例bean(不包含需延迟实例化的bean),通常scope=singleton的bean都会在下面这个方法中完成初始化。
beanFactory.preInstantiateSingletons();
}
@1
コードに注目してください。ここでbeanFactory的preInstantiateSingletons()
メソッドを呼び出し、ソース コードを確認します。ソース コードはDefaultListableBeanFactory
次のようにこのクラスにあります。
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException {
// beanDefinitionNames表示当前BeanFactory中定义的bean名称列表,
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// @1:循环实例化bean
for (String beanName : beanNames) {
//这里根据beanName来来实例化bean,代码省略了。。。。
}
// @2:变量bean,若bean实现了SmartInitializingSingleton接口,将调用其afterSingletonsInstantiated()方法
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
smartSingleton.afterSingletonsInstantiated();
}
}
}
上記のメソッドは主に次の 2 つのことを行います。
1. すべてのシングルトン Bean のインスタンス化を完了します: 上記のコードに対応して@1
、beanNames リストをループしてすべてのシングルトン Bean のインスタンス化を完了します。このサイクルが完了すると、すべてのシングルトン Bean がインスタンス化され、Spring に配置されます。コンテナーはキャッシュされます。 。
2. コールバックSmartInitializingSingleton
インターフェイス: 上記のコードに対応して@2
、この時点ですべてのシングルトン Bean がインスタンス化され、この時点ですべてのシングルトン Bean がトラバースされます。Bean がインターフェイスを実装する場合、このインターフェイスには 1 つあり、このメソッドは次のようになりSmartInitializingSingleton
ますafterSingletonsInstantiated方法
。すべてのシングルトン Bean が作成された後に何かを実行したい場合は、このインターフェースを実装できます。
フェーズ 13: リフレッシュ完了フェーズ
finishRefresh();
入ってソースコードを見てください
protected void finishRefresh() {
// @1:清理一些资源缓存
clearResourceCaches();
// @2:为此上下文初始化生命周期处理器
initLifecycleProcessor();
// @3:首先将刷新传播到生命周期处理器
getLifecycleProcessor().onRefresh();
// @4:发布ContextRefreshedEvent事件
publishEvent(new ContextRefreshedEvent(this));
}
まず @2 のコードを見てください。
initLifecycleProcessor();
ソースコードは次のとおりです
protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//spring容器中是否有名称为"lifecycleProcessor"的bean
if (beanFactory.containsLocalBean("lifecycleProcessor")) {
//从spring容器中找到LifecycleProcessor,赋给this.lifecycleProcessor
this.lifecycleProcessor =
beanFactory.getBean("lifecycleProcessor", LifecycleProcessor.class);
}
else {
//如果spring容器中没有自定义lifecycleProcessor,那么创建一个默认的DefaultLifecycleProcessor
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
//设置当前spring应用上下文的生命周期处理器
this.lifecycleProcessor = defaultProcessor;
//将其注册到spring容器中
beanFactory.registerSingleton("lifecycleProcessor", this.lifecycleProcessor);
}
}
@3のコードをもう一度見てください
getLifecycleProcessor().onRefresh();
と呼ばれるLifecycleProcessor
、最初にこのインターフェイスであるライフ サイクル プロセッサonRefresh方法
について話しましょうorg.springframework.context.LifecycleProcessor
。インターフェイスには 2 つのメソッドが定義されており、onClose
後で説明するように、このメソッドはコンテキストが閉じられるときに呼び出されます。
public interface LifecycleProcessor extends Lifecycle {
/**
* 上下文刷新通知
*/
void onRefresh();
/**
* 上下文关闭通知
*/
void onClose();
}
まず onRefresh メソッドを見てみましょう。このインターフェイスにはデフォルトの実装があるorg.springframework.context.support.DefaultLifecycleProcessor
ため、デフォルトでDefaultLifecycleProcessor
はonRefresh
次のようにソース コードのみを確認します。
public void onRefresh() {
startBeans(true);
this.running = true;
}
次のように内部を見てくださいstartBeans(true)
。コードは少し複雑に見えるかもしれませんが、実際は非常に単純です。つまり、インターフェイスを実装するすべての Bean をコンテナから見つけて、そのメソッドを呼び出しorg.springframework.context.Lifecycle
ますstart
。
private void startBeans(boolean autoStartupOnly) {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
int phase = getPhase(bean);
LifecycleGroup group = phases.get(phase);
if (group == null) {
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
phases.put(phase, group);
}
group.add(beanName, bean);
}
});
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
Collections.sort(keys);
for (Integer key : keys) {
phases.get(key).start();
}
}
}
@4のコードをもう一度見てください
publishEvent(new ContextRefreshedEvent(this));
イベントを公開しますContextRefreshedEvent
。この段階で何かをしたい場合は、このイベントを聞くことができます。
まとめ
このステージでは主に次の 3 つのことを行います。
1. 現在のコンテキストでライフサイクル プロセッサ LifecycleProcessor を初期化します。
2. LifecycleProcessor.onRefresh() メソッドを呼び出します。カスタマイズがない場合はLifecycleProcessor
、Spring コンテナ内のインターフェイスを実装するすべてのBeanメソッドDefaultLifecycleProcessor
を呼び出します。Lifecycle
start
3. ContextRefreshedEvent イベントを発行します。
4. フェーズ 14: Spring アプリケーション コンテキストの終了フェーズ
applicationContext.close()
doClouse()
最後にメソッドに入ります。コードは次のとおりです
org.springframework.context.support.AbstractApplicationContext#doClose
protected void doClose() {
// 判断是不是需要关闭(active为tue的时候,才能关闭,并用cas确保并发情况下只能有一个执行成功)
if (this.active.get() && this.closed.compareAndSet(false, true)) {
//@1:发布关闭事件ContextClosedEvent
publishEvent(new ContextClosedEvent(this));
// @2:调用生命周期处理器的onClose方法
if (this.lifecycleProcessor != null) {
this.lifecycleProcessor.onClose();
}
// @3:销毁上下文的BeanFactory中所有缓存的单例
destroyBeans();
// @4:关闭BeanFactory本身
closeBeanFactory();
// @5:就给子类去扩展的
onClose();
// @6:恢复事件监听器列表至刷新之前的状态,即将早期的事件监听器还原
if (this.earlyApplicationListeners != null) {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// @7:标记活动状态为:false
this.active.set(false);
}
}
まず @1 のコードを見てください。
publishEvent(new ContextClosedEvent(this));
イベントを投稿しますContextClosedEvent
。
@2のコードをもう一度見てください
if (this.lifecycleProcessor != null) {
this.lifecycleProcessor.onClose();
}
ライフサイクルプロセッサを呼び出す方法onClose
。ここではDefaultLifecycleProcessor的onClose()
次のようにそのソースコードを直接見ていきます。
public void onClose() {
stopBeans();
//将running设置为false
this.running = false;
}
stopBeans()
org.springframework.context.Lifecycle
ソース コードは次のとおりです。大規模で理解しやすいコードです。コンテナからインターフェイスを実装するすべての Bean を検索し、そのclose()
メソッドを呼び出します。
private void stopBeans() {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
int shutdownPhase = getPhase(bean);
LifecycleGroup group = phases.get(shutdownPhase);
if (group == null) {
group = new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false);
phases.put(shutdownPhase, group);
}
group.add(beanName, bean);
});
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
keys.sort(Collections.reverseOrder());
for (Integer key : keys) {
phases.get(key).stop();
}
}
}
@3のコードをもう一度見てください
destroyBeans();
コンテキストの BeanFactory にキャッシュされたすべてのシングルトン Bean を破棄します。主に次の 2 つのことを行います。
1. Bean の破棄メソッドを呼び出す
たとえば、Bean がorg.springframework.beans.factory.DisposableBean
インターフェースを実装している場合、この時点でそのインターフェースが呼び出されます。Bean には@PreDestroy
アノテーションが付けられたメソッドもいくつかあり、これらもこの時点で呼び出されます。
2. BeanFactory から Bean 情報をクリーンアップします。
@4のコードをもう一度見てください
closeBeanFactory();
ソース コードは次のとおりです。主に、現在の Spring アプリケーション コンテキストで beanFactory プロパティを復元するためのものです。
org.springframework.context.support.AbstractRefreshableApplicationContext#closeBeanFactory
@Override
protected final void closeBeanFactory() {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory != null) {
this.beanFactory.setSerializationId(null);
this.beanFactory = null;
}
}
}
5. まとめ
この記事では、Spring アプリケーション コンテキストのライフ サイクルについて詳しく紹介します。非常に重要です。多くの内容と詳細が含まれています。ソース コードと組み合わせて何度か読むことをお勧めします。暇なときに、また、何度も読み返して理解を深めてください。ご質問がございましたら、メッセージ交換をお願いします。
6. ケースのソースコード
git地址:
https://gitee.com/javacode2018/spring-series
スターの皆さん、すべてのシリーズ コードがこれに含まれており、すべての元の記事へのリンクも含まれているので、簡単に参照できます。!!
出典: https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648939152&idx=2&sn=2177e513f51d8127c4c468be07515631&scene=21#wechat_redirect
接口,此时会被调用。还有bean中有些方法标注了
このとき、leBean @PreDestroy` アノテーションも呼び出されます。
2. BeanFactory から Bean 情報をクリーンアップします。
@4のコードをもう一度見てください
closeBeanFactory();
ソース コードは次のとおりです。主に、現在の Spring アプリケーション コンテキストで beanFactory プロパティを復元するためのものです。
org.springframework.context.support.AbstractRefreshableApplicationContext#closeBeanFactory
@Override
protected final void closeBeanFactory() {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory != null) {
this.beanFactory.setSerializationId(null);
this.beanFactory = null;
}
}
}
5. まとめ
この記事では、Spring アプリケーション コンテキストのライフ サイクルについて詳しく紹介します。非常に重要です。多くの内容と詳細が含まれています。ソース コードと組み合わせて何度か読むことをお勧めします。暇なときに、また、何度も読み返して理解を深めてください。ご質問がございましたら、メッセージ交換をお願いします。
6. ケースのソースコード
git地址:
https://gitee.com/javacode2018/spring-series
スターの皆さん、すべてのシリーズ コードがこれに含まれており、すべての元の記事へのリンクも含まれているので、簡単に参照できます。!!
出典: https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648939152&idx=2&sn=2177e513f51d8127c4c468be07515631&scene=21#wechat_redirect