1. SpringBoot自動アセンブリとは何ですか?
2. SpringBoot は自動アセンブリをどのように実装しますか? オンデマンド読み込みを実現するにはどうすればよいですか?
3. スターターを実装するにはどうすればよいですか?
序文
Spring を使用したことのある友人は、XML 構成に支配されるのではないかという恐怖を抱いているはずです。Spring では後でアノテーションベースの構成が導入されますが、特定の Spring 機能を有効にしたり、サードパーティの依存関係を導入したりする場合は、明示的な構成に XML または Java を使用する必要があります。
例えば。Spring Boot を使用せずに RestFul Web サービスを作成する場合は、まず次のように構成する必要があります。
@Configuration
public class RESTConfiguration
{
@Bean
public View jsonTemplate() {
MappingJackson2JsonView view = new MappingJackson2JsonView();
view.setPrettyPrint(true);
return view;
}
@Bean
public ViewResolver viewResolver() {
return new BeanNameViewResolver();
}
}
spring-servlet.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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context/ http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc/ http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.howtodoinjava.demo" />
<mvc:annotation-driven />
<!-- JSON Support -->
<bean name="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</beans>
ただし、Spring Boot プロジェクトの場合は、構成を行わずに、以下の main メソッドを開始するだけで、関連する依存関係を追加するだけで済みます。
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
application.properties
さらに、ポート番号の変更、JPA プロパティの構成など、Spring Boot のグローバル構成ファイルを通じてapplication.yml
プロジェクトを設定できます。Spring Boot はなぜとても使いやすいのでしょうか? これは自動配線のおかげです。Spring Bootの核とも言える自動アセンブリですが、自動アセンブリとは何でしょうか?
1. SpringBoot自動アセンブリとは何ですか?
自動アセンブリというと、一般的に Spring Boot を連想します。しかし、実はこの機能はSpring Frameworkですでに実現されています。Spring Boot はそれをベースにしているだけで、途中でSPI
さらに最適化されています。
SpringBoot は、次のことを規定する一連のインターフェイス仕様を定義します。 SpringBoot は、起動時に外部参照された jar パッケージ内の META-INF/spring.factories ファイルをスキャンし、ファイル内に設定された型情報を Spring コンテナーにロードします (ここには JVM が含まれます)。クラスローディングメカニズムと Spring のコンテナの知識)、クラスで定義されたさまざまな操作を実行します。外部 jar の場合、SpringBoot によって定義された標準に従って独自の関数を SpringBoot にインストールするだけで済みます。
Spring Boot がないと、サードパーティの依存関係を導入する必要がある場合、手動で設定する必要があり、非常に面倒です。ただし、Spring Boot では、 を直接導入できますstarter
。たとえば、プロジェクトで Redis を使用する場合は、対応するスターターをプロジェクトに直接インポートできます。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
スターターを導入した後は、いくつかのアノテーションといくつかの簡単な構成を通じて、サードパーティのコンポーネントによって提供される機能を使用できるようになります。
自動アセンブリは、アノテーションまたはいくつかの単純な構成を通じて、Spring Boot の助けを借りて特定の機能を実現できると簡単に理解できます。
2. SpringBoot は自動アセンブリをどのように実装しますか?
まず SpringBoot のコアとなるアノテーションを見てみましょうSpringBootApplication
。
b
おそらく注釈の集合体@SpringBootApplication
とみなしてよいでしょう。@Configuration、@EnableAutoConfiguration、@ComponentScan
SpringBoot 公式 Web サイトによると、これら 3 つのアノテーションの機能は次のとおりです。
@EnableAutoConfiguration
: SpringBoot の自動構成メカニズムを有効にします。@Configuration
: コンテキスト内で追加の Bean を登録したり、他の構成クラスをインポートしたりできます。@ComponentScan
: @Component (@Service、@Controller) によってアノテーションが付けられた Bean をスキャンします。アノテーションは、デフォルトでスタートアップ クラスが配置されているパッケージ内のすべてのクラスをスキャンします。一部の Bean をスキャンしないようにカスタマイズできます。以下の図に示すように、 と はTypeExcludeFilter
コンテナから除外されますAutoConfigurationExcludeFilter
。
@EnableAutoConfiguration
自動アセンブリを実現するためには重要なアノテーションですので、まずはこのアノテーションから始めます。
3. @EnableAutoConfiguration: 自動アセンブリのコア アノテーション
EnableAutoConfiguration
簡単なメモですが、自動アセンブリのコア機能は実際にはAutoConfigurationImportSelector
クラスを通じて実現されます。
@Target({
ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //作用:将main包下的所有组件注册到容器中
@Import({
AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {
};
String[] excludeName() default {
};
}
次に、AutoConfigurationImportSelector
クラスが何を行うかを分析することに集中しますか?
AutoConfigurationImportSelector
:自動配線クラスをロードします
AutoConfigurationImportSelector
クラスの継承システムは次のとおりです。
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
}
public interface DeferredImportSelector extends ImportSelector {
}
public interface ImportSelector {
String[] selectImports(AnnotationMetadata var1);
}
ImportSelector
AutoConfigurationImportSelector クラスがインターフェイスを実装し、selectImports
このインターフェイスのメソッドも実装していることがわかります。このメソッドは主に、IoC コンテナにロードする必要があるすべての対象クラスの完全修飾クラス名を取得するために使用されます。
private static final String[] NO_IMPORTS = new String[0];
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// <1>.判断自动装配开关是否打开
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
//<2>.获取所有需要装配的bean
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
getAutoConfigurationEntry()
ここでは、主に自動構成クラスのロードを担当するメソッドに焦点を当てる必要があります。
メソッド呼び出しチェーンは次のとおりです。
次に、結合されたソース コードと組み合わせgetAutoConfigurationEntry()
て詳細に分析してみましょう。
private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();
AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
//<1>.
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
//<2>.
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//<3>.
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
//<4>.
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
ステップ1:
自動組立スイッチがオンになっているかどうかを確認します。デフォルトspring.boot.enableautoconfiguration=true
、application.properties
またはでapplication.yml
設定できます
ステップ2:
EnableAutoConfiguration アノテーションを取得するexclude
ために使用されますexcludeName
。
ステップ3
自動接続する必要があるすべての構成クラスを取得し、読み取りますMETA-INF/spring.factories
spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
以下の図から、このファイルの設定内容が読み取られていることがわかります。XXXAutoConfiguration の役割は、コンポーネントをオンデマンドでロードすることです。
この依存関係がMETA-INF/spring.factories
読み取られるだけでなく、Spring Boot Starter の下にあるすべての META-INF/spring.factories も読み取られます。
druid
したがって、データベース接続プールの Spring Boot Starter が META-INF/spring.factories ファイルを作成していることが明確にわかります。
Spring Boot Starter を自分で作成したい場合、このステップは不可欠です。
ステップ 4:
この時点で、面接官は「spring.factories
システム内に非常に多くの構成があるので、起動するたびにそれらをすべてロードする必要がありますか?」と尋ねるかもしれません。
明らかに、これは非現実的です。デバッグ後、構成の値が小さくなっていることがわかります。
なぜなら、このステップは一連の審査を経て、@ConditionalOnXXX
その中のすべての条件が満たされ、クラスが発効するからです。
@Configuration
// 检查相关的类:RabbitTemplate 和 Channel是否存在
// 存在才会加载
@ConditionalOnClass({
RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
}
興味のある方は、Spring Boot が提供する条件付きアノテーションについて詳しく学ぶことができます。
- @ConditionalOnBean: コンテナ内に指定のBeanがある場合
- @ConditionalOnMissingBean: コンテナにBeanが指定されていない場合
- @ConditionalOnSingleCandidate: 指定された Bean がコンテナ内に 1 つだけある場合、または複数あるが優先 Bean を指定する場合
- @ConditionalOnClass: クラスパスに指定したクラスが存在する場合
- @ConditionalOnMissingClass: クラスパスに指定したクラスが存在しない場合
- @ConditionalOnProperty: 指定されたプロパティが指定された値を持つかどうか
- @ConditionalOnResource: クラスパスに指定された値があるかどうか
- @ConditionalOnExpression:SpEL式を判定条件とする
- @ConditionalOnJava: Javaのバージョンを判定条件とする
- @ConditionalOnJndi: JNDI が存在するという条件で、指定された場所に違いがあります
- @ConditionalOnNotWebApplication: 現在のプロジェクトが Web プロジェクトではないという条件下
- @ConditionalOnWebApplication: 現在のプロジェクトが Web プロジェクトであるという条件下
4. スターターの実装方法
偽のトリックを練習するのではなく、ただ話すだけです。カスタム スレッド プールを実現するために、今すぐスターターを開始しましょう。
最初のステップはthreadpool-spring-boot-starter
プロジェクトを作成することです
2 番目のステップは、Spring Boot 関連の依存関係を導入することです。
3 番目のステップは、ThreadPoolAutoConfiguration を作成することです。
4 番目のステップは、threadpool-spring-boot-starter プロジェクトのリソース パッケージの下に META-INF/spring.factories ファイルを作成することです。
最後の新しいプロジェクトのインポートthreadpool-spring-boot-starter
テストに合格しました!!!
要約する
Spring Boot は、最終ロードの自動構成クラスによる自動アセンブリを有効にする@EnableAutoConfiguration
ことで自動アセンブリを実現しますSpringFactoriesLoader
META-INF/spring.factories
自動構成クラスは、実際には@Conditional
オンデマンドで読み込まれる構成クラスです。これを有効にするには、spring-boot-starter-xxx
パッケージをインポートして開始依存関係を実装する必要があります。