このブログは機能が限られているため、不完全なものもありますが、お役に立てば幸いです。
プロセッサの継承図を見てみましょう
このツールクラスには、2つの非常に重要なプロパティがありますorg.springframework.context.annotation.ConfigurationClassUtils
private static final String CONFIGURATION_CLASS_FULL = "full";
private static final String CONFIGURATION_CLASS_LITE = "lite";
これらの2つの属性を説明する方法
いっぱい、私たちはそれをすべてとして理解することができ、春の対応するライトも一部として理解することができます
では、主人公の@Configurationアノテーションとこれら2つの属性の関係は何ですか?構成クラスに追加する場合と追加しない場合に、Spring環境が有効になるのはなぜですか?
最初に環境内のコードを見てみましょう
@Configuration
//@Import(TestImportSelector.class)
//@TestImportSelectorAnno
//@TestBeanFactoryPostProcessorAnno
@ComponentScan("org.springframework.test.main.*")
public class ScanConfig {
}
//测试
public class MainDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(ScanConfig.class);
ScanConfig scanConfig = (ScanConfig) ac.getBean("scanConfig");
}
}
このクラスのこのコードのブレークポイントを入力してデバッグしましょう
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
//断点调式
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
//给配置类产生cglib代理。加了@Configuration注解的
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
通常の状況では、このコードは、春の設計の厳密さのために、登録リスト(BeanDefinition)内のすべてのbdを解析し、検出されたクラスと@Configurationアノテーションを別のbdコレクションに配置する場合にのみelseに入ります。次へ進む分析。検出では、注釈付きのクラスの属性であるisFull(省略形)が設定され、そうでないものはlite(これも断続的)属性です。次のブレークポイント分析に進みます。
このタイプのソースコードの2番目の分析
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
このコードはこのように理解できます。@ Configurationを含むクラスをマップに配置します。空の場合は直接返され、空でない場合は次のコードを入力します。
次のコードは投稿されません。後で結果がわかり、ブレークポイントはテストクラスに戻ります。イースターエッグを見てみましょう
はい、cglibプロキシです。追加しない場合はそうではありません。結果を見てください。
なぜですか?これは、春の厳密さ(シングルトン原理)の長所の1つです。まず、次のコードを見てみましょう。
初期化された環境コードを見てください
@Configuration
@ComponentScan("org.springframework.test.main.*")
public class ScanConfig {
@Bean
public Test getTestBean(){
return new Test();
}
@Bean
public User getUserBean(){
return new User();
}
}
public class Test {
public Test(){}
}
public class User {
public User(){
System.out.println("init-user");
};
}
public class MainDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(ScanConfig.class);
}
}
このコメントが追加されているかどうかに関係なく、変更すると、印刷結果はすべてinit-userになります。
@Configuration
@ComponentScan("org.springframework.test.main.*")
public class ScanConfig {
@Bean
public Test getTestBean(){
getUserBean();
return new Test();
}
@Bean
public User getUserBean(){
return new User();
}
}
//cglib此结果会打印一次.加入static关键字会失效
@ComponentScan("org.springframework.test.main.*")
public class ScanConfig {
@Bean
public Test getTestBean(){
getUserBean();
return new Test();
}
@Bean
public User getUserBean(){
return new User();
}
}
//此结果会打印两次
しかし、問題があります。出力される2つのハッシュコードは同じであり、同じものがシングルトンのオブジェクトです。
レベルが限られているため、本当の理由は不明です
2つのハッシュコードは同じである可能性があります。これは、オブジェクトを作成するときに、Springが最初にキャッシュされたシングルトンプール(デフォルトはシングルトン、またはシングルトンプールとして理解できる)から取得するためです(キャッシュされたシングルトンプールからは取得しません)。それが解決策であるかどうかを知る循環依存の問題)初めて、実際のシングルトンプールからそれを取得します(Beanのライフサイクルコールチェーンはそのようなステップです)
能力の問題は後でしか修正できないので、お役に立てば幸いです。春のソースコードが醜いです。証拠がないため、オンラインの説明が正しいかどうかわかりません(オンラインの投稿が乱雑です。正しいものを見つけたい。見つけるのが難しい)。