Spring 学習ソース コードの基本的な中心原則と中心的な概念


基本原則

AnnotationConfigApplicationContext

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.test();
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();

上記の方法で Spring を使用することはほとんどなく、Spring MVC または Spring Boot を使用しますが、これらは基本的にこのメソッドに基づいており、内部で ApplicationContext を作成する必要があります。

  • SpringBoot は AnnotationConfigApplicationContext を作成します
  • SpringMVC は、ClassPathXmlApplicationContext と同様の XML に基づいた XmlWebApplicationContext を作成します。

AnnotationConfigApplicationContextは調査と研究のためのメインクラスです

IoCコンテナのロードプロセス

IoC コンテナのロード プロセスは 2 つのステップに分けることができます

  • コンテナ初期化プロセスで使用するための基礎となるインフラストラクチャ ツール クラスを準備して登録し、構成クラスを登録して、コンテナを更新します。
  • 構成されたさまざまな Bean をスキャンして解析して BeanDefinition に変換し、BeanDefinitionMap に保存します。
  • BeanDefinitionMap を走査し、シングルトンを生成し、シングルトン プールにキャッシュします。

Springでオブジェクトを作成する方法

新しい AnnotationConfigApplicationContext(Config.class) の処理は、IoC コンテナのロード処理、スキャンによる BeanDefinition の生成、トラバースによるシングルトン Bean の生成、最後に手動で getBean(beanName) を呼び出してキャッシュから対応する Bean を取得する処理です。

Bean作成プロセス(ライフサイクル)

クラス -> リフレクション newInstance -> 元のオブジェクト -> 依存性注入 (プロパティの割り当て) -> Aware の束 -> 初期化前 (@PostConstruct) -> 初期化 (InitailizedBean) -> 初期化後 (AOP) -> プロキシ オブジェクト (Proxy)オブジェクト .target=元のオブジェクト) -> Bean

  • インスタンス化、リフレクションを通じてクラスの特定のコンストラクターを呼び出すことによってオブジェクトを作成します。複数のコンストラクターがある場合は、推論コンストラクターと呼ばれる選択が行われます。
  • 依存関係の注入 (プロパティの割り当て)、オブジェクト内のフィールドの走査、@Autowired による自動割り当て
  • 認識ウィービング。オブジェクトが BeanNameAware、ApplicationContextAware、およびその他の認識であるかどうか (つまり、クラスが実装されているかどうか) を判断します。認識している場合は、構造体で定義された set メソッドの呼び出しを強制します。
  • @PostConstruct処理では、このアノテーションを持つメソッドが存在するかどうかを判断し、存在する場合はメソッドを実行します。
  • InitializingBean 処理では、オブジェクトがインターフェイスのインスタンスであるかどうかを判断し、そうであれば、インターフェイスによって定義された afterPropertiesSet メソッドを実行します。
  • カスタム init-method メソッド
  • AOP が必要かどうかを判断します。必要ない場合は、現在のオブジェクトを返します。必要に応じて、プロキシ オブジェクトを生成して返します。
  • シングルトン Bean の場合は、シングルトン プールに格納されます。

シングルトンプロトタイプ

Beanのスコープはシングルトンとプロトタイプの2種類に分かれます。

  • シングルトン: getBean が同じオブジェクトを取得するたびに、そのオブジェクトは初めて作成された後にシングルトン プールにキャッシュされます。
  • プロトタイプ: getBean が作成されるたびに、それはシングルトン プールに配置されません。

遅延ロードされた Bean は、IoC コンテナのロード時に作成およびキャッシュされませんが、使用時に作成およびキャッシュされます。

推論されたコンストラクター

インスタンス化するとき、デフォルトでパラメータなしのコンストラクタが使用されます (パラメータが記述されている場合、明示的に定義されていない限り、デフォルトではパラメータなしのコンストラクタはありません)。

パラメータなしのコンストラクタがある場合は、パラメータなしのコンストラクタを使用します。パラメータなしのコンストラクタがない場合は、パラメータ化されたコンストラクタがいくつあるかを確認します。パラメータ化されたコンストラクタが 1 つしかない場合は、このパラメータ化されたコンストラクタを使用します。パラメータなしのコンストラクタが複数ある場合は、確認できませんどちらを使用すればよいので、エラー: デフォルトのパラメーターのないコンストラクターが見つかりません。

複数のパラメーター化コンストラクターがある場合は、 @Autowired を追加して、どのパラメーター化コンストラクターを使用するかを指定することもできます。

パラメーター化されたコンストラクターのパラメーター オブジェクトはどこから来たのでしょうか?

  • まず、タイプに従ってコンテナを検索します。1 つしかない場合は、それを直接使用します。複数ある場合は、名前に基づいてフィルタリングします。名前が一致する場合は、直接使用します。一致しない場合は、エラーになります。報告。

依存性注入

まず、タイプでコンテナをフィルタリングします。一致が 1 つだけの場合は、それを直接使用します。一致が複数ある場合は、名前で一致します。一致がある場合は、それを直接使用します。一致がない場合は、エラーが報告されます。

AOP動的プロキシ

Bean 作成の最後のステップで、AOP が必要かどうかが判断され、必要な場合は動的プロキシが使用されます。

AOP が必要かどうかを判断するための一般的なプロセス

  • すべてのアスペクト Bean を検索する
  • 各メソッドを走査し、@Before や @After などのアノテーションが記述されているかどうかを判断します。
  • 書き込まれた場合、対応する PointCut が現在作成されている Bean と一致するかどうかを判断します。
  • 一致する場合は、現在の Bean が AOP を実行する必要があることを意味します。

CGLib で AOP を実行する一般的なプロセス

  • 元のクラスを継承するプロキシ クラスを生成します。プロキシ クラスは、元のクラス オブジェクトのターゲットを保持します。元のクラス オブジェクトは、依存関係の注入、初期化などの Bean 作成プロセスを経ることに注意してください。
  • プロキシ クラスは元のクラスのメソッドをオーバーライドし、最終的にはターゲットの対応するメソッドを呼び出しますが、大まかに次のように前後にアスペクト ロジックを追加します。
  • 最後に作成された Bean は、元のオブジェクトを保持するプロキシ オブジェクトを返します。
public class UserService {
    
    
	@Autowired
	private OrderService orderService;
	public void test() {
    
    
		sout;
	}
}
class UserServiceProxy extend UserService {
    
    
	UserService target;
	public void test() {
    
    
		// @Before 的逻辑
		target.test();
		// @After 的逻辑
	}
}

プロキシクラスは元のクラスを継承しているため、元のクラスのフィールドもプロキシクラスに存在しますが、Springではプロキシクラスへの依存性注入は必要ないため行いません。

JoinPoint.getTarget()プロキシ オブジェクトは、元のオブジェクトの特定のメソッドを拡張するためにのみ使用されます。アスペクト ロジックで元のオブジェクトの依存関係注入フィールドを使用する必要がある場合は、元のオブジェクトを操作することもでき、元のオブジェクトの各フィールドも取得できます。オブジェクトはすでに依存関係が注入されています。

事務

@Transactional アノテーションをメソッドに追加すると、AOP 段階でこのクラスのプロキシ クラスとプロキシ オブジェクトが生成されます。

トランザクションプロキシオブジェクト実行メソッドの処理

  • 現在のメソッドに @Transactional アノテーションがあるかどうかを確認する
  • 存在する場合、トランザクション マネージャーはデータベース接続を作成します (この接続は接続プールからのものではないでしょうか?)
  • 接続の autoCommit を false に設定します (トランザクション アノテーションがない場合、接続は接続プールから取得され、SQL が実行されるたびに自動的に送信されます)
  • 実行方法、SQL in 実行方法
  • 接続の commit または rollback メソッドを呼び出す

トランザクション アノテーションの有効期限がスケジュールされている理由

トランザクションが失敗するかどうかは、どのオブジェクトが @Transactional アノテーション メソッドを実行するかによって決まります。

  • プロキシ オブジェクト: 有効期限はありません
  • 元のオブジェクト: 実行されるのは通常のメソッドであり、プロキシ オブジェクトによる拡張がないため、無効です。

最も一般的な例は、クラス内に 2 つのトランザクション メソッド a と b があり、a で b が呼び出されます。a と b のトランザクションを別々に実行することは無効ではありませんが、a で b が実行されると、上の設定が無効になります。 b のトランザクション アノテーションは無効になります

aを実行する処理はこんな感じなので、クラスのプロキシオブジェクトを取得し、そのaを実行し、まずアスペクトロジックを通って接続を作成し、自動送信しないように設定してから、aであるtarget.aを実行します。元のオブジェクトのメソッド、このときの本体 プロキシオブジェクトではなく元のオブジェクトです bメソッドを実行すると本質はこれです b、主語は元のオブジェクトのままでアスペクトはありませんそのため、a の b メソッドのトランザクション アノテーション設定は無効になります。

もちろん、詳細な分析が必要な理由は他にもたくさんあります。

他の多くの AOP 障害も同じ理由で、すべて自己呼び出しが原因です。

解決策は自己参照です。クラスはselfに自分自身を注入することに依存しています。このとき、selfがプロキシオブジェクトです。aでbを呼び出すときはself.bを使用します。このように、本体はプロキシ オブジェクトです。ロジックと b の関係を強化する側面があります。設定が有効になります。

@Configuration トランザクションを以下に追加すると有効になるのはなぜですか?

@Configuration
public class Config {
    
    
	@Bean
	public TransactionManager transationManager() {
    
    
		return new DataSourceTransactionManager(dataSource());
	}
	@Bean
	public JdbcTemplate jdbcTemplate() {
    
    
		return new JdbcTemplate(dataSource())
	}
	@Bean
	public DataSource dataSource() {
    
    
		return new DataSource();
	}
}
  • 時間を追加せずに dataSource() を 2 回呼び出すと 2 つの異なるデータ ソースが生成され、最終的にトランザクション マネージャーとテンプレートは異なるデータ ソースを使用します。
  • また、dataSource()をBeanとみなし、両方に同じオブジェクトを渡すという特殊な処理が行われます。

JdbcTemplate で接続を取得すると、それがトランザクション環境であるかどうかがチェックされ、トランザクション環境TransactionSynchronizationManager.getResource(dataSource);このようにして、トランザクション マネージャーのコミットおよびロールバック操作が JdbcTemplate に反映されます。

核となるアイデア

Spring のソース コードには多くの抽象化とツールがあり、ソース コードを読みやすくするために事前に理解しておく必要があります。

Bean定義

BeanDefinition は、Bean の構成に関するさまざまな情報を記録するために使用されます。

  • Beanのタイプを示すクラス
  • スコープ、Bean スコープ、シングルトンまたはプロトタイプなどを示します。
  • LazyInit: Bean が遅延ロードされるかどうかを示します
  • initMethodName: Beanの初期化時に実行されるメソッドを示します。
  • destroyMethodName: Beanが破棄されるときに実行されるメソッドを示します
  • 他にもたくさんあります…

Bean を定義するには、宣言型とプログラム型の 2 つの方法があり、さまざまな方法で定義された Bean は、最終的に BeanDefinition に解析されてキャッシュされます。

  • 宣言:
    • <豆/>
    • @豆
    • @コンポーネント(@サービス,@コントローラー)
  • プログラマティック
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    
    // 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中
    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
    beanDefinition.setBeanClass(User.class);
    context.registerBeanDefinition("user", beanDefinition);
    
    System.out.println(context.getBean("user"));
    

Bean定義リーダー

特定のルールに従ってリソースを BeanDefinition に解析するために使用されます

AnnotatedBeanDefinitionReader

クラスは、クラスのアノテーション (@Conditional、@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description) を含めて BeanDefinition に解析できます。

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context);

// 将User.class解析为BeanDefinition
reader.register(User.class);

System.out.println(context.getBean("user"));

XmlBeanDefinitionReader

<bean/> タグで構成された Bean を解析できます

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
int i = reader.loadBeanDefinitions("spring.xml");

System.out.println(context.getBean("user"));

ClassPathBeanDefinitionScanner

スキャナーですが、その機能は BeanDefinitionReader に似ており、スキャン、特定のパッケージ パスのスキャン、およびスキャンされたクラスの解析が可能です。

@Component アノテーションがスキャンされたクラスに存在する場合、クラスは BeanDefinition に解析されます。

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.coder");

System.out.println(context.getBean("userService"));

ビーンファクトリー

Spring コンテナのルート インターフェイスである Bean ファクトリは、Bean の作成と取得を担当し、さまざまな getBean() メソッドの定義を提供します。

DefaultListableBeanFactory

BeanFactory にはコア実装クラスDefaultListableBeanFactoryがあり、BeanFactory として直接使用したり、ApplicationContext の代わりに使用したりできますが、機能は少なくなります。

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);

beanFactory.registerBeanDefinition("user", beanDefinition);

System.out.println(beanFactory.getBean("user"));

DefaultListableBeanFactory

DefaultListableBeanFactory のアーキテクチャは上記の通りで、多くのインターフェイス (機能) とクラスがあります。

  • AliasRegistry : エイリアス機能をサポートし、エイリアスの登録・取得・判定・削除機能を定義し、複数名のBeanDefinition/Beanの機能をサポートします。
  • SimpleAliasRegistry、維持されますMap<String, String> aliasMap。ここでは、エイリアスと beanName の間の多対 1 の関係を示します。これにより、エイリアスから元の名前を簡単に見つけることができます (エイリアスにエイリアスを付けることもできます)。もちろん、元の名前からすべてのエイリアスを見つけることもできます。名前
  • BeanDefinitionRegistry : BeanDefinitionの登録/取得/存在/削除関数を定義します。
  • SingletonBeanRegistry : シングルトンBeanの登録/存在/取得/数量取得/名前取得などの関数を定義
  • BeanFactory : Beanの取得/存在/エイリアスの取得/スコープの決定などの機能を定義します。
  • ListableBeanFactory : BeanFactory を拡張し、コンテナ内の Bean インスタンスを列挙および取得するためのメソッドを提供します。すべての Bean の名前を簡単に取得したり、タイプごとに Bean を取得したり、条件ごとに Bean を取得したりできます。
  • HierarchicalBeanFactory : BeanFactory を拡張し、階層コンテナ構造と継承メカニズムを提供し、各サブコンテナは独自の Bean 定義とインスタンスを独立して管理できます。子コンテナは親コンテナで定義された Bean を継承でき、親コンテナの Bean 定義を子コンテナでオーバーライドまたは拡張できます。より優れたモジュール化と組織化を実現し、Bean 定義とスコープを柔軟に管理およびカスタマイズできます。
  • AutowireCapableBeanFactory : BeanFactory を拡張し、Bean を自動的にアセンブルする機能を提供し、依存関係の注入、自動アセンブリ、デカップリングなどの機能を実現できます。
  • ConfigurableBeanFactoryは、BeanFactory Bean に加えて、BeanFactory を構成するためのツールも提供します。親 BeanFactory の設定、クラス ローダー (クラスをロードするためにクラス ローダーを指定できることを示します)、および Spring EL 式パーサーの設定 (BeanFactory が実行できることを示します) の設定が追加されました。 EL 式の解析)、型変換サービスの設定 (BeanFactory が型変換を実行できることを示す)、BeanPostProcessor の追加 (BeanFactory が Bean ポストプロセッサーをサポートすることを示す)、BeanDefinition のマージ、Bean の破棄など。
  • ConfigurableListableBeanFactory : ConfigurableBeanFactory に加えて、Bean 定義の分析と変更、およびシングルトンの事前インスタンス化のためのツールも提供します。
  • DefaultSingletonBeanRegistry : 主にシングルトン Bean の登録と取得を管理および維持するために使用されます。singletonObjects はここにあります。
  • FactoryBeanRegistrySupport : 主に FactoryBean の登録と取得をサポートするために使用されます。factoryBeanObjectCache はここにあります
  • AbstractBeanFactory : この関数はすでに非常に包括的ですが、BeanName を自動的にアセンブルして取得することはできません。
  • AbstractAutowireCapableBeanFactory : 自動アセンブリの機能があります
  • DefaultListableBeanFactory : Spring コンテナの主要コンポーネントであり、BeanDefinition の登録、マージ、検索、および Bean の作成、アセンブリ、破棄の管理を担当します。これは、豊富な機能と柔軟な構成オプションを提供し、Spring アプリケーションで一般的に使用される BeanFactory 実装の 1 つです。

アプリケーションコンテキスト

BeanFactory にはコア サブインターフェイスApplicationContextがあり、次のように定義されます。

public interface ApplicationContext 
extends EnvironmentCapable, 
ListableBeanFactory, 
HierarchicalBeanFactory, 
MessageSource, 
ApplicationEventPublisher, 
ResourcePatternResolver

ここに画像の説明を挿入します

  • HierarchicalBeanFactory: 親BeanFactoryを取得する機能を持つ
  • ListableBeanFactory: beanNameを取得する機能を持つ
  • ResourcePatternResolver: 複数のリソース(ファイルリソースなど)を一度に取得できるリソースローダー
  • EnvironmentCapable: 実行環境を取得できます(実行環境を設定する機能はありません)
  • ApplicationEventPublisher: イベントをブロードキャストする機能を持ちます(イベントリスナーを追加する機能はありません)
  • MessageSource: 国際化機能があります

ApplicationContextはSpringのアプリケーションコンテキストとして位置付けられており、アプリケーションの各部の管理や整理を担っていますが、コードレベルで見るとBeanFactoryであり、アーキテクチャレベルで見るとBeanFactoryよりも上位の存在であり、BeanFactoryを司っています。 EnvironmentCapable、MessageSource、およびその他のコンポーネントは対応する機能を完成させますが、BeanFactory はその一部にすぎません。

この考え方によれば、GenericApplicationContext は DefaultListableBeanFactory を継承せず、属性として利用し、BeanFactory から継承した関数はすべて、BeanFactory が保持する DefaultListableBeanFactory に委ねて実行するという非常に合理的な考え方となります。

ApplicationContext インタフェースは ListableBeanFactory および HierarchicalBeanFactory を継承していますが、上位 BeanFactory としての位置付けであり、BeanFactory のある程度の基本機能のみに焦点を当てており、中間層や下位層のより強力で詳細な機能をすべて必要とするわけではありません。

ApplicationContext には 2 つの重要な実装クラスがあります

  • AnnotationConfigApplicationContext
  • ClassPathXmlApplicationContext
AnnotationConfigApplicationContext

ここに画像の説明を挿入します

  • ライフサイクル: ライフサイクルの開始/停止制御メソッドを定義する共通インターフェイス
  • ConfigurableApplicationContext : 追加、イベントリスナーの追加、BeanFactoryPostProcessor の追加、Environment の設定、ConfigurableListableBeanFactory の取得およびその他の機能
  • AbstractApplicationContext : ユニバーサル コンテキスト関数を実装します。有名な更新メソッドはここにあります
  • GenericApplicationContext : 一般的なアプリケーション コンテキストの具象実装クラス
  • AnnotationConfigRegistry : アプリケーション コンテキストに注釈を付けて構成するために使用されます。クラスを BeanDefinition として個別に登録できます (このクラスで @Configuration @Bean アノテーションを処理できます)
  • AnnotationConfigApplicationContext : 便利で強力なアプリケーション コンテキストの実装であり、アノテーション駆動型の開発に適しています。アノテーションをスキャンして処理することでBeanの登録とアセンブリの自動化を実現し、面倒なXML設定を軽減します。
ClassPathXmlApplicationContext

ここに画像の説明を挿入します
AbstractApplicationContextも継承していますが、BeanDefinitionの登録ができないなど、AnnotationConfigApplicationContextに比べて機能が強力ではありません。

国際的なメッセージソース

ここに画像の説明を挿入します

# messages.properties
test = 你好啊
# messages_en_US.properties
test = Hello
# messages_zh_CN.properties
test = 你好
@Configuration
public class MessageSourceConfig {
    
    

	@Bean
	public MessageSource messageSource() {
    
    
		ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
		resourceBundleMessageSource.setDefaultEncoding("UTF-8");
		resourceBundleMessageSource.setBasename("i18n.messages");
		return resourceBundleMessageSource;
	}

}
	public static void main(String[] args) {
    
    
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
		System.out.println(Locale.getDefault()); // zh_CN
		System.out.println(context.getMessage("test", null, Locale.getDefault())); // 你好
		System.out.println(context.getMessage("test", null, new Locale("zh_CN"))); // 你好
		System.out.println(context.getMessage("test", null, new Locale("en_US"))); // Hello
		System.out.println(context.getMessage("test", null, new Locale("de_DE"))); // 你好, 不存在, 走默认
	}
リソースの読み込み getResource/getResources
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);

Resource resource1 = context.getResource("file:/C:/coder/develop/workspace/idea/mrathena/spring/spring-analyze-test/src/main/java/com/coder/UserService.java");
System.out.println(resource1.contentLength());
System.out.println(resource1.getFilename());

Resource resource2 = context.getResource("https://www.baidu.com");
System.out.println(resource2.contentLength());
System.out.println(resource2.getURL());

// Resource resource3 = context.getResource("classpath:spring.xml");
// System.out.println(resource3.contentLength());
// System.out.println(resource3.getURL());

Resource[] resources = context.getResources("classpath:com/coder/**/*.class");
for (Resource resource : resources) {
    
    
	System.out.println(resource.contentLength());
	System.out.println(resource.getFilename());
}
実行環境を取得する
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);

Map<String, Object> systemEnvironment = context.getEnvironment().getSystemEnvironment();
for (Map.Entry<String, Object> entry : systemEnvironment.entrySet()) {
    
    
	System.out.println(entry.getKey() + "\t\t" + entry.getValue());
}

System.out.println("=======");

Map<String, Object> systemProperties = context.getEnvironment().getSystemProperties();
for (Map.Entry<String, Object> entry : systemProperties.entrySet()) {
    
    
	System.out.println(entry.getKey() + "\t\t" + entry.getValue());
}

System.out.println("=======");

// 会包含所有的属性源, 包括上面的 SystemEnvironment 和 SystemProperties
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
for (PropertySource<?> propertySource : propertySources) {
    
    
	System.out.println(propertySource);
}

System.out.println("=======");

System.out.println(context.getEnvironment().getProperty("NO_PROXY"));
System.out.println(context.getEnvironment().getProperty("sun.jnu.encoding"));
System.out.println(context.getEnvironment().getProperty("Path"));

注:@PropertySource("classpath:spring.properties")メソッドを使用して、プロパティ ファイル内のパラメータをランタイム環境に追加できます。

イベントリリース
@ComponentScan
@Configuration
public class ApplicationListenerTest {
    
    

	@Bean
	public ApplicationListener<ApplicationEvent> applicationListener() {
    
    
		return event -> {
    
    
			System.out.println();
            System.out.println("接收到了一个事件\t\t" + event.getClass());
            System.out.println(event);
			if (event instanceof PayloadApplicationEvent) {
    
    
				System.out.println(((PayloadApplicationEvent) event).getPayload());
			}
        };
	}

	public static void main(String[] args) {
    
    
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationListenerTest.class);
		context.publishEvent("测试事件");
	}

}

型変換

Spring のソース コードでは、String を他の型に変換する必要がある場合があるため、Spring のソース コードでは、オブジェクトの型変換をより便利にするためのいくつかのテクノロジが提供されています。型変換のアプリケーション シナリオについては、ソースを読むときに遭遇します。コードは後で。たくさんあります。

プロパティエディター

おすすめ

転載: blog.csdn.net/mrathena/article/details/132474313