1.フロンティア
Spring Bootの起動プロセスの記事では、Spring Bootの起動プロセスについて学習しました。このプロセスでは、更新コンテキスト中にすべての自動構成クラスが読み込まれます。
Spring Bootの自動構成ロードは、次の2つのステップに分かれています。
1)まず、Spring Bootの初期化フェーズでは、すべてのMATA-INF / spring.factoriesファイルのすべての構成コンテンツが、SpringFactoriesLoaderを介してクラス名の1対多のコレクションとしてキャッシュに格納されます。
spring-boot-autoconfigureモジュールのMATA-INF / spring.factoriesファイルのEnableAutoConfigurationに対応するクラスセットは次のとおりです。
キャッシュにロードされるクラスのコレクションは次のとおりです。
2)次に、コンテキストを更新する過程で、SpringFactoriesLoaderのloadFactoryNamesメソッドを介して自動構成クラスのコレクションを取得し、最後にリフレクションを介してこれらのクラスのクラスオブジェクトと構築メソッドを取得してクラスインスタンスを生成します
自動構成クラスを作成するプロセスは次のとおりです。
2つの自動構成フローチャート
自動化構成をよりよく理解するために、次の図に示すように、図を使用して説明します。
mybatis-spring-boot-starterなどのコンポーネントのMETA-INFディレクトリにはspring.factoriesファイルが含まれており、SpringFactoriesLoaderはspring.factoriesファイル内のクラスのすべてのフルネームをスキャンし、クラスのフルネームの配列を返します。 、返されたクラスのフルネームリフレクションによってインスタンス化されることにより、具体的なファクトリインスタンスが形成され、ファクトリインスタンスを使用して、コンポーネントが特に必要とするBeanが生成されます。
3つの自動構成ソースコード
SpringBoot自動構成機能をオンにするのは@EnableAutoConfigurationアノテーションです。@ EnableAutoConfigurationアノテーションから始めましょう。
3.1EnableAutoConfiguration
@EnableAutoConfiguration関数は、SpringBoot自動構成を有効にするためのもので、ソースコードは次のとおりです。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 自动配置包下的bean注册
@AutoConfigurationPackage
// AutoConfigurationImportSelector 自动配置导入组件,这个类是 Spring Boot 实现自动配置的核心
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
// 自动配置排除特定的类
Class<?>[] exclude() default {};
// 自动配置排除特定的类名
String[] excludeName() default {};
}
@EnableAutoConfigurationアノテーションのソースコードから、AutoConfigurationImportSelectorクラスが自動構成のコアであることがわかります。
3.2 AutoConfigurationImportSelector
AutoConfigurationImportSelectorクラス構造は次のとおりです。
AutoConfigurationImportSelectorのコアメソッドgetAutoConfigurationEntryのソースコードは次のとおりです。
// 1、AutoConfigurationImportSelector 的 getAutoConfigurationEntry 方法
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
// 没有开始自动配置,则返回空
return EMPTY_ENTRY;
}
// 获取元数据属性,只有 exclude 和 excludeName
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 根据元数据获取所有配置类集合
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
// 获取需要排除的配置类集合
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
// 移除需要排除的配置类集合
configurations.removeAll(exclusions);
// 根据配置的 AutoConfigurationImportFilter 过滤器进一步过滤掉不需要的配置类集合
configurations = filter(configurations, autoConfigurationMetadata);
// 发布自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
// 构建 AutoConfigurationEntry 对象返回
return new AutoConfigurationEntry(configurations, exclusions);
}
// 2、AutoConfigurationImportSelector 的 getCandidateConfigurations 方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
// 获取 spring.factories 文件中 EnableAutoConfiguration 对应的配置类集合
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
AutoConfigurationImportSelectorによって実装されたコアメソッドを読んだ後、AutoConfigurationImportSelectorのメソッドをどこで呼び出すかを理解することですか?
コンテキストが更新されると、確実に答えが呼び出されます。特定のプロセスは、自動構成クラス作成プロセスによって異なります。
3.3自動構成クラス作成プロセス
自動構成クラスの作成は、次の2つのプロセスを経ます。
1)まず、AbstractApplicationContextのinvokeBeanFactoryPostProcessorsメソッドを使用して、構成済みの自動構成クラスをBeanDefinitionに変換し、BeanFactoryに登録します。自動構成クラスでプロキシクラスを生成する必要がある場合は、CGLIB動的プロキシを使用して直接生成します。対応するプロキシクラス
2)次に、AbstractApplicationContextのfinishBeanFactoryInitializationメソッドを使用して、対応するBeanにBeanDefinitionをインスタンス化します。
3.3.1BeanDefinitionに変換する
特定のエントリは、AbstractApplicationContextのinvokeBeanFactoryPostProcessorsメソッドにあります。デバッグプロセスを次の図に示します。
特定のスタック情報をデバッグします。
getAutoConfigurationEntry:127, AutoConfigurationImportSelector (org.springframework.boot.autoconfigure)
process:420, AutoConfigurationImportSelector$AutoConfigurationGroup (org.springframework.boot.autoconfigure)
getImports:878, ConfigurationClassParser$DeferredImportSelectorGrouping (org.springframework.context.annotation)
processGroupImports:804, ConfigurationClassParser$DeferredImportSelectorGroupingHandler (org.springframework.context.annotation)
process:774, ConfigurationClassParser$DeferredImportSelectorHandler (org.springframework.context.annotation)
parse:185, ConfigurationClassParser (org.springframework.context.annotation)
processConfigBeanDefinitions:315, ConfigurationClassPostProcessor (org.springframework.context.annotation)
postProcessBeanDefinitionRegistry:232, ConfigurationClassPostProcessor (org.springframework.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:275, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:95, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:691, AbstractApplicationContext (org.springframework.context.support)
refresh:528, AbstractApplicationContext (org.springframework.context.support)
refresh:142, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:775, SpringApplication (org.springframework.boot)
refreshContext:397, SpringApplication (org.springframework.boot)
run:316, SpringApplication (org.springframework.boot)
main:29, MainApplication (com.springboot.demo)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
run:49, RestartLauncher (org.springframework.boot.devtools.restart)
次の図に示すように、AbstractApplicationContextのinvokeBeanFactoryPostProcessorsメソッドの後、すべてのspring.factoriesファイルの自動構成クラスがBeanDefinitionに解析されます。
3.3.2BeanDefinitionはBeanインスタンスを生成します
BeanDefinitionが生成された後、BeanDefinitionは対応するBeanインスタンスを生成します。Beanの作成については、SpringソースコードのBeanロードをすでに 分析しているため、ここでは繰り返しません。
4つの自動構成例分析
ソースコードを通してその原理を理解するための例としてRedisAutoConfigurationを取り上げましょう
RedisAutoConfigurationのソースコードは次のとおりです。
// 表明是一个配置类,其所有被 @bean 注解的方法都会被 Spring 容器创建成 Bean 实例,
// proxyBeanMethods 属性表示是否是代理,默认为 true,如果需要生成代理类,则会调用 CGLIB 生成代理类实例
@Configuration(proxyBeanMethods = false)
// 依赖于 RedisOperations 类,必须先实例该类
@ConditionalOnClass(RedisOperations.class)
// 启动该类的 ConfigurationProperties 功能;将配置文件中对应的值和 RedisProperties 绑定起来;并把 RedisProperties 加入到 Spring 的 Environment 中去
// 例如配置文件中的 spring.redis.url、spring.redis.host 等属性值会绑定到 RedisProperties 对应的属性上去
@EnableConfigurationProperties(RedisProperties.class)
// 引入需要的配置类
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
// 缺少 RedisTemplate Bean 时会创建 RedisTemplate 实例,否则什么也不做
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
// 会生成 StringRedisTemplate 实例
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
構成ファイルで構成できるすべてのプロパティは、xxxPropertiesクラスで定義されます。構成ファイルで構成できるプロパティは、特定の関数に対応するプロパティクラス(@EnableConfigurationProperties(RedisProperties.class)など)を参照できます。 RedisAutoConfigurationソースコード。RedisPropertiesファイルで定義されているプロパティは、構成ファイルで構成できるプロパティです。
RedisPropertiesのソースコードは次のとおりです。
// 所有属性的前缀
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
/**
* Database index used by the connection factory.
*/
// 数据库,默认是 0
private int database = 0;
/**
* Connection URL. Overrides host, port, and password. User is ignored. Example:
* redis://user:[email protected]:6379
*/
// url
private String url;
/**
* Redis server host.
*/
// host 地址,默认是 localhost
private String host = "localhost";
/**
* Login password of the redis server.
*/
// 密码
private String password;
/**
* Redis server port.
*/
// 端口,默认是 6379
private int port = 6379;
/**
* Whether to enable SSL support.
*/
// 是否支持 ssl
private boolean ssl;
/**
* Connection timeout.
*/
// 超时时间
private Duration timeout;
}
RedisPropertiesソースコードから、spring.redis.url、spring.redis.host、spring.redis.password、およびその他のプロパティを構成ファイルで構成できます。
次の図に示すように、構成ファイルでredisプロパティを構成します。
右側の赤いボックス内のすべてのプロパティは、RedisPropertiesプロパティ定義からのものです
五数要約
1. Spring Bootが開始されると、多数の構成クラスがロードされます。これらの構成クラスは、spring-boot-autoconfigureモジュールのMETA-INF /spring.factoriesで定義されています。
2. spring-boot-autoconfigureで定義されていない自動構成を使用する必要がある場合は、mybatis-spring-boot-starterを導入してmybatisに依存するなど、pom内の依存モジュールを個別に参照する必要があります。
3. xxxxAutoConfigurartion自動構成クラスの役割は、コンテナーにコンポーネントを追加することです。
4. xxxxPropertiesの役割は、関連するプロパティを構成ファイルにカプセル化することです。つまり、構成ファイルで構成できるプロパティです。
5.コンテナの自動構成クラスにコンポーネントを追加すると、特定のプロパティがプロパティクラスから取得されます。これらのプロパティの値は、構成ファイルで指定できます。