Spring Boot の起動原理が分からない方は必見です!

Spring Boot プロジェクトを開発するときは、次のスタートアップ クラスを使用します。

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

上記のコードからわかるように、アノテーション定義 ( @SpringBootApplication) とクラス定義 ( SpringApplication.run) が最も魅力的であるため、SpringBoot の謎を解明するには、この 2 つから始める必要があります。


1. SpringBootApplication の背後にある秘密

@SpringBootApplication アノテーションは Spring Boot のコア アノテーションであり、実際には結合されたアノテーションです。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}

定義では元の情報に注釈を付けるために複数の注釈を使用しますが、実際には重要な注釈は 3 つだけです。

  • @Configuration(@SpringBootConfigurationクリックして表示すると、まだ適用されていることがわかります@Configuration)

  • @EnableAutoConfiguration

  • @ComponentScan

つまり、@SpringBootApplication= (デフォルト属性) @Configuration+ @EnableAutoConfiguration+です@ComponentScan

したがって、次の SpringBoot スタートアップ クラスを使用すると、SpringBoot アプリケーション全体は以前のスタートアップ クラスと機能的に同等になります。

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

この3つを毎回書くのは面倒なので、@SpringBootApplication1つ書いておくと便利です。次に、3 つのアノテーションを個別に紹介します。

1、@設定

これは@Configuration私たちにとって馴染みのないものではありません. これは、 Spring Ioc コンテナの構成クラスによって JavaConfig の形式で使用されるものです@Configuration. SpringBoot コミュニティでは、JavaConfig に基づいた構成フォームを使用することを推奨しています. したがって、ここで起動クラスがマークされた後@Configuration、実際には IoC コンテナの構成クラスです。

簡単な例をいくつか挙げて、XML 構成メソッドと構成構成メソッドの違いを確認してください。

(1) 発現レベル

XML ベースの構成は次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
       default-lazy-init="true">
    <!--bean定义-->
</beans>

JavaConfigによる設定方法は以下のとおりです。

@Configuration
public class MockConfiguration{
    //bean定义
}

注釈付きの Java クラス定義はすべて@ConfigurationJavaConfig 構成クラスです。

(2) 登録Bean定義レベル

XML ベースの構成は次のようになります。

<bean id="mockService" class="..MockServiceImpl">
    ...
</bean>

JavaConfig に基づく設定フォームは次のとおりです。

@Configuration
public class MockConfiguration{
    @Bean
    public MockService mockService(){
        return new MockServiceImpl();
    }
}

マークされたメソッドの場合@Bean、その戻り値は Spring の IoC コンテナに Bean 定義として登録され、メソッド名はデフォルトで Bean 定義の ID になります。

(3) Express 依存性注入関係レベル

Bean と Bean の依存関係を表現するには、XML 形式で次のように表現するのが一般的です。

<bean id="mockService" class="..MockServiceImpl">
   <propery name ="dependencyService" ref="dependencyService" />
</bean>
<bean id="dependencyService" class="DependencyServiceImpl"></bean>

JavaConfig に基づく設定フォームは次のとおりです。

@Configuration
public class MockConfiguration{
    @Bean
    public MockService mockService(){
        return new MockServiceImpl(dependencyService());
    }

    @Bean
    public DependencyService dependencyService(){
        return new DependencyServiceImpl();
    }
}

Bean の定義が他の Bean に依存している場合は、対応する JavaConfig クラスで依存する Bean の作成メソッドを直接呼び出すことができます。

@Configuration: それを言うときは、@Configuration彼のパートナーについても触れなければなりません@Beanこれら 2 つのアノテーションを使用すると、対応する XML 構成ファイルを置き換えるために使用できる単純な Spring 構成クラスを作成できます。

<beans> 
    <bean id = "car" class="com.test.Car"> 
        <property name="wheel" ref = "wheel"></property> 
    </bean> 
    <bean id = "wheel" class="com.test.Wheel"></bean> 
</beans>

に相当:

@Configuration 
public class Conf { 
    @Bean 
    public Car car() { 
        Car car = new Car(); 
        car.setWheel(wheel()); 
        return car; 
    }

    @Bean 
    public Wheel wheel() { 
        return new Wheel(); 
    } 
}

@Configuration注釈付きのクラスは、このクラスが Bean 定義のソースとして Spring IoC コンテナを使用できることを示します。

@Beanこのアノテーションは、@Bean アノテーションが付けられたメソッドが Spring アプリケーション コンテキストに Bean として登録されるオブジェクトを返すことを Spring に伝えます。

2、@ComponentScan

@ComponentScanこのアノテーションは Spring では非常に重要です。XML 構成の要素に対応します。その機能は、修飾されたコンポーネント (およびなど) または Bean 定義を@ComponentScan自動的にスキャンしてロードし、最終的にこれらの Bean 定義を IoC コンテナーにロードします。@Component@Repository

BasePackages などの属性を使用して自動スキャンの範囲を細かくカスタマイズできます@ComponentScan。指定しない場合、デフォルトの Spring フレームワーク実装は、@ComponentScanクラスが宣言されているパッケージからスキャンします。

注: したがって、basePackages がデフォルトで指定されていないため、SpringBoot のスタートアップ クラスはルート パッケージの下に配置するのが最適です。

3、@EnableAutoConfiguration

個人的には@EnableAutoConfigurationこのAnnotationが一番重要だと思っているので最後に解説しますが、@EnableSpringフレームワークで提供されている様々な名前を持つAnnotationの定義を覚えていますか?例えば@EnableScheduling、@EnableCaching、@EnableMBeanExport@EnableAutoConfigurationコンセプトとやり方は実は同列で、簡単にまとめると、@Importサポートの力を借りて、特定のシナリオに関連するBean定義を収集して登録する、ということになります。

@EnableScheduling@Import を通じて Spring スケジューリング フレームワークに関連するすべての Bean 定義を IoC コンテナーにロードします。
@EnableMBeanExport@Import を通じて JMX 関連の Bean 定義を IoC コンテナにロードします。
ただし@EnableAutoConfiguration、@Import の助けを借りて、自動構成条件を満たすすべての Bean 定義が IoC コンテナーにロードされるだけです。

@EnableAutoConfigurationプロジェクトは、クラスパス内の jar の依存関係に従って自動的に構成されます。たとえば、依存関係が追加された場合spring-boot-starter-web、Tomcat と Spring MVC の依存関係が自動的に追加され、Spring Boot によって Tomcat と Spring MVC が自動的に構成されます。

複合アノテーションとして、@EnableAutoConfiguration はキー情報を次のように定義します。

@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ...
}

その中で最も重要なことは、SpringBoot アプリケーション@Import(EnableAutoConfigurationImportSelector.class)現在の SpringBoot 作成に適格な構成をすべてロードして使用できるようにする IoC コンテナーを使用することです。Springフレームワーク独自のツールクラスをサポートすることで、まるで「タコ」のようにインテリジェントな自動設定機能を実現!EnableAutoConfigurationImportSelector,@EnableAutoConfiguration@ConfigurationSpringFactoriesLoader@EnableAutoConfiguration

舞台裏のヒーローを自動的に構成する: SpringFactoriesLoader の詳細

SpringFactoriesLoader は Spring フレームワークのプライベート拡張スキームであり、その主な機能は、指定された構成ファイルから構成をロードすることですMETA-INF/spring.factories

public abstract class SpringFactoriesLoader {
    //...
    public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
        ...
    }


    public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        ....
    }
}

一緒に使用すると@EnableAutoConfiguration、構成検索のより機能的なサポートが提供されます。つまり、検索キーとして@EnableAutoConfigurationクラスの完全なクラス名に従って、対応するクラスのセットを取得できます。org.springframework.boot.autoconfigure.EnableAutoConfiguration@Configuration

画像

上の図はMETA-INF/spring.factoriesSpringBoot の autoconfigure 依存関係パッケージの構成ファイルからの抜粋であり、問​​題をよく示しています。

したがって、@EnableAutoConfiguration自動構成の魔法騎士は、META-INF/spring.factoriesクラスパスからすべての構成ファイルを検索し、リフレクション (Java Reflection) によってマークされた JavaConfig の形式で、org.springframework.boot.autoconfigure.EnableutoConfiguration対応する構成項目を対応する IoC コンテナー構成クラスにインスタンス化し、1 つに集約されます。@Configurationそして IoC コンテナにロードされます。


2. SpringApplication の実行プロセスの詳細な調査

SpringApplication の run メソッドの実装が今回の主なルートですが、このメソッドの主なプロセスは次のように概略的に要約できます。

1) SpringApplication の静的 run メソッドを使用している場合、このメソッドでは、まず SpringApplication オブジェクトのインスタンスを作成し、次に作成された SpringApplication のインスタンス メソッドを呼び出す必要があります。SpringApplication インスタンスが初期化されるとき、事前にいくつかの処理が実行されます。

  • クラスパスに特性クラスが存在するかどうかに応じて、org.springframework.web.context.ConfigurableWebApplicationContextWebアプリケーション用のApplicationContext型を作成するかどうかが決まります。

  • Use を使用すると、SpringFactoriesLoaderアプリケーションの classpath 内で使用可能なすべてのものが検索されてロードされますApplicationContextInitializer

  • Use を使用すると、SpringFactoriesLoaderアプリケーションの classpath 内で使用可能なすべてのものが検索されてロードされますApplicationListener

  • main メソッドの定義クラスを推測して設定します。

SpringFactoriesLoader2) SpringApplication インスタンスの初期化と設定が完了すると、run メソッドのロジックが実行されますが、メソッド実行の開始時には、まず、見つかってロードできるすべてのメソッドを走査して実行します。SpringApplicationRunListenerメソッドを呼び出して、「SpringBoot アプリケーションの実行が開始されます!」とstarted()伝えます。SpringApplicationRunListener

3) 現在の Spring Boot アプリケーションによって使用される環境を作成して構成します (使用する PropertySource とプロファイルの構成を含む)。

SpringApplicationRunListener4) すべてのメソッドをトラバースして呼び出しenvironmentPrepared()、「現在の SpringBoot アプリケーションで使用される環境の準備ができました!」と伝えます。

5) SpringApplication の showBanner プロパティが true に設定されている場合、バナーを印刷します。

6) ユーザーがapplicationContextClassタイプを明示的に設定したかどうかと初期化フェーズの推論結果に応じて、現在の SpringBoot アプリケーションに対してどのタイプを作成するかを決定してApplicationContext作成を完了し、条件に従って ShutdownHook を追加するかどうかを決定します。カスタム環境を使用するかBeanNameGeneratorどうか、カスタム環境を使用するかどうかを決定する もちろんResourceLoader、最も重要なことは、事前に準備した環境を作成した環境に設定することですApplicationContext

7) ApplicationContext が作成された後、SpringApplication はそれを再度使用して、Spring-FactoriesLoaderクラスパス内の使用可能なすべてのメソッドを検索してロードしApplicationContext-Initializer、これらのApplicationContextInitializer( applicationContext) メソッドを走査して呼び出して、initialize作成されたメソッドをApplicationContextさらに処理します。

8) すべてのSpringApplicationRunListenerメソッドをトラバースして呼び出しますcontextPrepared()

9) 中心となるステップは、@EnableAutoConfiguration以前に取得したすべての構成と他の形式の IoC コンテナー構成を、準備された構成にロードすることですApplicationContext

10) すべてのSpringApplicationRunListenerメソッドをトラバースして呼び出しますcontextLoaded()

11) IoC コンテナで利用可能な最後のプロセスを完了するApplicationContextために呼び出されるメソッド。refresh()

ApplicationContext12) 現在のシステムに登録があるかどうかを確認しCommandLineRunner、ある場合はそれらをスキャンして実行します。

13) 通常の状況では、実行SpringApplicationRunListenerメソッドをトラバースしますfinished()(プロセス全体で例外が発生した場合でも、すべてのメソッドが呼び出されますがSpringApplicationRunListenerfinished()この場合、例外情報は処理のために渡されます)。

イベント通知ポイントを削除した後のプロセス全体は次のようになります。


この記事では、実際の SpringBoot 起動プログラムのデバッグを例に挙げ、プロセス内のメイン クラス図を参照しながら、その起動ロジックと自動構成原理を分析します。

概要:

上の図は SpringBoot の起動構造図を示していますが、起動プロセスは主に 3 つの部分に分かれていることがわかりました。

  • 最初の部分は、SpringApplication のモジュールを初期化し、いくつかの基本的な環境変数、リソース、コンストラクター、およびリスナーを構成することです。

  • 2 番目の部分では、起動プロセスの監視モジュール、ローディング構成環境モジュール、コア作成コンテキスト モジュールなど、アプリケーションの特定の起動スキームを実装します。

  • 3 番目の部分は自動構成モジュールです。これは Springboot 自動構成の中核であり、次の分析で詳しく説明します。以下のスタートアップ ルーチンでは、構造内の主要な関数を配線します。

起動:

各 SpringBoot プログラムには、メイン メソッドであるメイン エントリがあり、SpringApplication.run()Spring-Boot プログラム全体を呼び出して開始します。メソッドが配置されているクラスは、@SpringBootApplicationアノテーションを使用する必要があります@ImportResource。また、アノテーション (必要な場合) ( @SpringBootApplication3 つのアノテーション、関数を含む) を使用する必要があります。以下の通り:

  • @EnableAutoConfiguration: SpringBoot は、アプリケーションによって宣言された依存関係に基づいて Spring フレームワークを自動的に構成します。

  • @SpringBootConfiguration(内部@Configuration): マークされたクラスは、applicationContext.xmlSpring XML 構成ファイルの ( ) に相当し、すべての Bean トランザクションをアセンブルし、Spring コンテキストを提供します。

  • @ComponentScan: Bean を自動的に検出してアセンブルできるコンポーネント スキャン デフォルトでは、SpringApplication の run メソッド内のパッケージ パスの下のファイルがスキャンされるため、Booter.classスタートアップ クラスをルート パッケージ パスの下に置くのが最善です。

画像

SpringBoot スタートアップ クラス

まず run メソッドを入力します

image.gif

runメソッドではSpringApplicationインスタンスが作成されており、この構築メソッドでは初期化されたinitializeメソッドを呼び出していることが分かります。

これは主に、SpringApplication オブジェクトにいくつかの初期値を割り当てるためです。コンストラクターが実行された後、run メソッドに戻ります。

このメソッドでは次の主要な手順が実装されます。

1. アプリケーション リスナーを作成しSpringApplicationRunListeners、リッスンを開始します

2. SpringBoot 構成環境をロードします ( ConfigurableEnvironment)、Web コンテナーを通じて公開されている場合はロードされStandardEnvironment、最終的には継承されますConfigurableEnvironment。クラス図は次のとおりです。

画像

*Environment が最終的に PropertyResolver インターフェイスを実装していることがわかります。通常、環境オブジェクトを通じて設定ファイル内の指定された Key に対応する value メソッドを取得するとき、propertyResolver インターフェイスの getProperty メソッドを呼び出します。

3. 構成環境 ( Environment) がリスナー オブジェクト ( SpringApplicationRunListeners)に追加されます。

4. run メソッドの戻りオブジェクトを作成します: ConfigurableApplicationContext(アプリケーション構成コンテキスト)。作成メソッドを確認できます。

このメソッドは、まず明示的に設定されたアプリケーション コンテキスト ( ) を取得しapplicationContextClass、それが存在しない場合は、次にデフォルトの環境設定をロードし ( かどうかを判断してweb environment)、AnnotationConfigApplicationContextデフォルトでアノテーション コンテキストを選択します (すべてのアノテーション クラスをスキャンして Bean をロードします)。最後に、BeanUtils を通じてコン​​テキスト オブジェクトをインスタンス化し、それを返します。

ConfigurableApplicationContext クラス図は次のとおりです。

これは主に、継承の 2 つの方向に依存します。

  • LifeCycle: ライフサイクル クラス。start start、stop end、isRunning を定義し、中程度のライフ サイクルの null 値メソッドを実行するかどうかを決定します。

  • ApplicationContext: 主に beanFactory (Bean ファクトリ クラス) を継承するアプリケーション コンテキスト クラス

5. run メソッドに戻り、prepareContext メソッドがlisteners、environment、applicationArguments、banner他の重要なコンポーネントをコンテキスト オブジェクトに関連付けます。

6. 次のrefreshContext(context)メソッド (初期化メソッドは次のとおり) は、ロードや Bean のインスタンス化などのコア作業をspring-boot-starter-*含む自動構成 (mybatis、redis など) を実現するための鍵となります。spring.factories

構成後、Springboot はいくつかの基本的な仕上げ作業を行い、アプリケーション環境コンテキストを返しました。全体のプロセスを振り返ると、Springboot の起動では主に構成環境 (environment)、イベント リスナー (listener)、アプリケーション コンテキスト (applicationContext) が作成され、上記の条件に基づいてコンテナ内で必要な Bean のインスタンス化が開始されます。ここまでで SpringBoot 起動によるプログラムの構築が完了しましたので、次に自動構成を実現する方法について説明します。


自動構成:

前の起動構造図では、アプリケーションの初期化と特定の実行プロセスの両方で SpringBoot 自動構成モジュールが呼び出されていることがわかりました。

SpringBoot自動構成モジュール

この構成モジュールの主な用途はSpringFactoriesLoader、Spring ファクトリ ローダーです。このオブジェクトはloadFactoryNamesメソッドを提供します。入力パラメータは、factoryClass と classLoader です。つまり、上の図のファクトリ クラスの名前と、対応するクラス ローダーを渡す必要があります。このメソッドは指定された classLoader に基づいて、クラス加算器の検索パスの下に指定されたファイル、つまりファイルをロードします。spring.factories受信ファクトリ クラスはインターフェイスであり、ファイル内の対応するクラスはその実装クラスです。この種の 1 対多のクラス名のコレクションでは、これらの実装クラスのクラス名を取得した後、メソッドはクラス名のコレクションとメソッド呼び出し元を返しますloadFactoryNames。これらのコレクションを取得し、リフレクションを通じてクラス オブジェクトとそのクラスの構築メソッドを取得し、最後にインスタンスを生成します。

ファクトリ インターフェースといくつかの実装クラスのインターフェース名

以下の図は、自動構成プロセスを視覚化するのに役立ちます。

SpringBoot 自動構成の主要コンポーネントの関係図

mybatis-spring-boot-starterspring-boot-starter-web他のコンポーネントの META-INF ファイルspring.factoriesにはファイルが含まれています。自動構成モジュールでは、SpringFactoriesLoaderファイル内のクラスの完全名が収集され、クラスの完全名の配列が返されます。返されたクラスの完全名は次のとおりです。リフレクションを通じてインスタンス化され、コンポーネントが特に必要とする Bean を生成するための特定のファクトリ インスタンスを形成します。

アノテーションについては前に説明しましたがEnableAutoConfiguration、そのクラス図は次のとおりです。

以下のメソッドを中心に、 ImportSelector(セレクター) と(Bean クラスローダーミドルウェア)を最終的に実装していることがわかりますBeanClassLoaderAwareAutoConfigurationImportSelectorselectImports

[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-Dm6tiUWw-1597051375071) (https://upload-images.jianshu.io/) Upload_images/18688925-97932faefd1184cf?imageMogr2 /auto-orient/strip%7CimageView2/2/w/1240)]

このメソッドは、Springboot の起動プロセス (Bean のインスタンス化) の前に実行され、インスタンス化されるクラス情報のリストを返します。クラス情報が取得されれば、Spring はクラス ローダーを通じてクラスを jvm に自然にロードできることがわかります。Spring-Boot スターターの依存関係を通じて必要なコンポーネントに依存したので、これらのコンポーネントのクラス情報はselect メソッドでも取得できますが、心配せずに分析を続けてみましょう。

このメソッドのメソッドgetCandidateConfigurationsは、メソッド アノテーションを通じて学習され、自動構成クラスのクラス名のリストを返します。メソッドはメソッドを呼び出しloadFactoryNames、メソッドを表示します。

image.gif

上記のコードでは、自動コンフィギュレーターが、内部のクラスをロードするために、渡されたプロジェクト システム パスの下のfactoryClass.getName()すべてのファイル内で対応するキーを検索することがわかります。この下のファイルをspring.factories選択しますmybatis-spring-boot-autoconfigurespring.factories

image.gif

と入力するとorg.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration、主にクラス ヘッダーを確認します。

Spring が@Configurationアノテーションが付けられた springBean のようなものであることを発見し、引き続き下を見て、

  • @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class}): これら 2 つのクラスが存在する場合SqlSessionFactory.class、構成クラスはSqlSessionFactoryBean.class解析されますMybatisAutoConfiguration。そうでない場合、この構成クラスは解析されません。当然のことですが、mybatis がセッション オブジェクトを返す必要があり、セッション ファクトリ関連のクラスが存在する必要があります。

  • @CondtionalOnBean(DataSource.class): Bean として宣言された dataSource のみを処理します。

  • @ConditionalOnMissingBean(MapperFactoryBean.class)このアノテーションは、名前で指定された Bean がコンテナー内に存在しない場合は Bean インジェクションが作成され、それ以外の場合は実行されないことを意味します (このクラスのソース コードは長く、スペース制限が完全に貼り付けられていません)。

上記の設定により、sqlSessionFactory、sqlSessionTemplate、dataSourcemybatis に必要なコンポーネントが自動的に設定され、@Configurationアノテーションによって Spring コンテキスト環境が提供されるため、上記のコンポーネントの設定方法は、Spring 起動時の mybatis.xml ファイルによる設定と同じ効果があります。 。

SqlSessionFactory.class分析を通じて、SpringBoot プロジェクトに基づくクラスパスが存在し、SqlSessionFactoryBean.classdataSourceBean がコンテナーに登録されている限り、自動構成をトリガーできることがわかります。つまり、mybatis に必要ないくつかの依存関係を追加するだけで済みます自動構成をトリガーすることはできますが、mybatis のネイティブ依存関係が導入されている場合、統合機能ごとに自動構成クラスを変更する必要があるため、すぐに使用できる効果は得られません。

したがって、Spring-boot は、関連クラスを直接設定できる統合スターターを提供しており、自動設定をトリガーするために必要な依存関係 (mybatis) は次のとおりです。

mybatis-spring-boot-starterインターセプトされたソース コード内の pom.xml ファイル内のすべての依存関係は次のとおりです。

Maven の依存関係には推移的な性質があるため、すぐに使える機能を実現するためにスターターに依存している限り、自動的に設定する必要があるすべてのクラスに依存できます。また、Springboot によって、Spring フレームワークによってもたらされる大量の XML 構成と複雑な依存関係管理が簡素化され、開発者がビジネス ロジックの開発により注意を払えるようになることも示されています。

やっと

公式アカウント「Programmer Chasing the Wind」に注目してください。Reply 003 最新の 2020 Java 面接質問マニュアル (200 ページを超える PDF ドキュメント) を入手します。

おすすめ

転載: blog.csdn.net/Design407/article/details/107917917