【SpringUtil】 2. 深い理解

1.ナンセンス

SpringUtil の基本的な内容を理解した後でも、SpringUtil について疑問がたくさんあるので、ここで質問形式で 1 ​​つずつ答えていきます。
PS:主に私の個人的な理解ですので、問題があれば修正してください。

2、SpringUtil

コードを見やすくするために、同じ SpringUtil コードをここに配置します。

@Component
public class SpringUtil implements ApplicationContextAware {
    
    
    /** 静态成员*/
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        context = applicationContext;
    }

    public static <T> T getBean(Class<T> beanClass) {
    
    
        return context.getBean(beanClass);
    }
}

3、問題

ここではRedisSessionDAOへのShiroUtilクラスの導入を例に、主に静的静的メンバーを例に説明します。

1. SpringUtil を使用する必要があるのはどのような場合ですか?

Springコンテナで管理されていないBeanでSpringコンテナ内のBeanを使用する必要がある場合、SpringUtilクラスを利用してSpringで管理しているBeanオブジェクトを取得することができる。
[Spring コンテナー内のいくつかのオブジェクト (RedisSessionDAO など) を使用する必要がある非 Spring 管理ツール クラス (ShiroUtil などの Bean) があるとします。
ここに画像の説明を挿入
Springの管理範囲外なので、@Autowiredアノテーションを使ってオブジェクトを注入することができないので、
まずShiroConfigの@Configurationと@Beanを使ってRedisSessionDAOをSpringコンテナに登録する必要があります。

@Configuration
public class ShiroConfig {
    
    

	@Bean
    public SecurityManager securityManager() {
    
    
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 自定义Ssession管理
        securityManager.setSessionManager(sessionManager());
        // 自定义Cache实现
        securityManager.setCacheManager(cacheManager());
        // 自定义Realm验证
        securityManager.setRealm(shiroRealm());
        return securityManager;
    }
	@Bean
    public RedisSessionDAO redisSessionDAO() {
    
    
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        return redisSessionDAO;
    }
	@Bean
    public SessionManager sessionManager() {
    
    
        ShiroSessionManager shiroSessionManager = new ShiroSessionManager();
        shiroSessionManager.setSessionDAO(redisSessionDAO());
        return shiroSessionManager;
    }
	···
}

リフレクションを通じてオブジェクトを取得し、内部のプロパティとメソッドを呼び出します
[インポートされた jar パッケージはまず Spring コンテナに登録する必要があり、その後 SpringUtil を直接使用してオブジェクトを取得できます]

public class ShiroUtils {
    
    
	/** 采用SpringUtil静态成员方法**/
	private static RedisSessionDAO redisSessionDAO = SpringUtil.getBean(RedisSessionDAO.class);

	private static ...{
    
    }
	···
}

補足: ここで static を使っているのは、ここでのShiroUtilのメソッドはすべてstaticメソッドであり、ShiroUtilを使用する際にクラス
【SpringUtil】 1. 基本内容

補足2:
同じ点: どちらも結果は Spring コンテナに Bean を登録することですが、
違い:
@Component は通常、クラスパススキャンによって自動的に検出され、自動的に Spring コンテナに組み込まれます。
@Bean アノテーションは通常、このアノテーションでマークされたメソッドでこの Bean を生成するために定義するロジックです。
@Component と @Bean の違い 1 記事
@Component と @Bean の違い 2

2. SpringUtil によって書き換えられた getBean メソッドを使用することに加えて、@Autowired を使用してオブジェクトを取得できますか?


① 静的メンバー static [主に使用]

@Component
public class ShiroUtils {
    
    
	/** set方法依赖注入**/
    private static RedisSessionDAO redisSessionDAO;
    @Autowired
    public void setRedisSessionDAO(RedisSessionDAO redisSessionDao){
    
    
        redisSessionDAO = redisSessionDao;
    }

	···
}
  1. RedisSeeionDAO は Spring コンテナ管理の一部ではないため、@Component を使用して、ShiroUtil を Spring コンテナ管理に導入する必要があります。
  2. ここでは静的メンバー変数(private static RedisSessionDAO redisSessionDAO)を使用しているため、プロパティに直接@Autowiredを追加することはできず、setメソッドに@Autowiredを追加して依存性注入を行う必要があります。

②非静的部材 [非推奨]
テストされていないため、使用中に積載穴が存在する可能性が高くなります。

@Component
public class ShiroUtils {
    
    
	/** @Autowired依赖注入**/
    @Autowired
    private RedisSessionDAO redisSessionDAO;
	···
}

注:
1. 非静的メンバーを使用した後は、次のいずれのメソッドも静的メソッドを使用できなくなります。
静的メソッドでは非静的変数およびメソッドにアクセスできない; 非静的メソッドでは静的および非静的変数およびメソッドにアクセスできる
2. 他のクラスがこの非静的メンバー RedieSessionDAO の ShiroUtil を呼び出す場合、クラス。メソッドを作成し、使用するオブジェクトを作成する必要があります。
【SpringUtil】 1. 基本内容

3. @Autowired を静的な静的メンバー変数に追加できないのはなぜですか? また、依存関係注入のために @Autowired を set メソッドに追加する必要がありますか?

①なぜ追加できないのでしょうか?

1. 初期化順序の問題: 静的メンバー変数はクラス レベルに属し、クラスのロード時に初期化されて割り当てられますが、Spring コンテナーは実行時にのみ動作を開始します。静的メンバー変数が @Autowired アノテーションによって自動的にアセンブルされる場合、使用時に初期化されておらず、静的メンバー変数は何を割り当てるべきかわからないため、NullPointerException が発生します。
2. Springコンテナの管理範囲:静的メンバー変数はクラスレベルです、とSpringコンテナはオブジェクトレベルを管理しますつまり、Spring コンテナが管理できるオブジェクトはすべて、クラス自体ではなく、インスタンス化されたクラス オブジェクトです。したがって、@Autowired が静的メンバー変数に使用される場合、実際にはコンテナーによって管理されず、Spring フレームワークの本来の目的と矛盾します。
3. 要約すると、静的メンバー変数の初期化順序は Spring コンテナーよりも前であり、Spring コンテナーはインスタンス化されたオブジェクトのみを管理できるため、@Autowired は静的メンバー変数に作用できません。したがって、インスタンス変数には @Autowired アノテーションを使用することをお勧めします。

②なぜsetメソッドに追加するのか?

1. 静的メンバー変数はオブジェクトのインスタンス化に依存しないため、オブジェクトを渡すことで依存性注入を実行できません。
2. 静的メンバー変数はクラスの定義とロードに依存するため、静的メンバー変数の依存性注入を実現するには、 set メソッドを設定し、 @Autowired を追加してリフレクションを通じてそれを実現する必要があります。
[Spring コンテナがShiroUtil をインスタンス化すると、自動的に RedieSessionDAO インスタンスが挿入され、set メソッドを通じて静的メンバー変数 redisSessionDAO に割り当てられます] 3. Spring コンテナが初期化されると、
@Autowired アノテーションをスキャンし、次に Spirngフレームワークは、リフレクション メカニズムを通じてアノテーション付きクラス Object を探し、このタイプのオブジェクトのインスタンスを取得し、それを注入する必要がある変数に割り当てます。

補足:リフレクションは主にクラスのオブジェクトを取得することです。プログラムの実行時にクラスを介してインスタンスを取得する順序は new よりも前になります (クラスのロードはオブジェクトのインスタンス化に先立ちます)。

4. SpringUtil が静的な static ApplicationContext を設定する必要があるのはなぜですか?

あくまで個人的な理解ですので、ご質問がございましたら修正してください。
SpringUtilはgetBeanメソッドを設定する必要があるため、リフレクションのようにクラスを介してオブジェクトのインスタンスを取得することが目的であり、それが便利であるため、staticを使用するにはクラスのロード時に完了する必要があります。

5. 質問 2 で述べたメソッドに加えて、静的メンバー変数をクラスに直接インスタンス化したり、SpringUtil の非静的メンバー メソッドを使用してオブジェクトを取得したりすることはできますか?

クラスを直接インスタンス化することはできません

public class ShiroUtils {
    
    
	/** 直接实例化   不行,没有进行配置 会为null**/
    private static RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
	···
}

Spring に静的メンバー変数を挿入させるのではなく、静的メンバー変数を直接インスタンス化すると、他の依存関係の設定が失敗する可能性があります。
設定する必要のないクラスの場合は、直接インスタンス化できます。

②SpringUtilの非静的メンバーメソッドを採用する
ここでSpringUtilは非静的メソッドを使用する必要があります。

@Component
public class SpringUtil implements ApplicationContextAware {
    
    
    /** 非静态成员*/
    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        context = applicationContext;
    }

    public <T> T getBean(Class<T> beanClass) {
    
    
        return context.getBean(beanClass);
    }
}

ここで使用される SpringUtil は非静的であるため、メソッドを直接クラス化することができないため、ここで getBean を使用して SpringUtil をインスタンス化する必要があります。

public class ShiroUtils {
    
    
	/** 采用SpringUtil非静态成员方法     不行 会为null**/
  private static RedisSessionDAO redisSessionDAO = new SpringUtil().getBean(RedisSessionDAO.class);
	···
}
  1. 静的メンバはクラスのロード時に初期化されるため、ここでは静的メンバ変数を新たに代入します。このコード全文はクラスのロード時に完了する必要があります。ただし、ShiroConfigの@Configurationおよび@BeanによってRedisSessionDAOが登録されていません; さらに、クラスがロードされるとき、SpringUtil はまだインスタンス化できないため、静的メンバーはクラスを直接インスタンス化できません。
  2. 静的メンバー変数はクラス レベルですが、Spring コンテナ管理はオブジェクト レベルです。静的メンバー変数は Spring コンテナのインスタンス化前に初期化されます。つまり、ApplicationContext がロードされていないためインスタンス化できません。

6. ApplicationContext をロードする前にインスタンス化できないのはなぜですか?


Spring プロジェクトは、クラスが
ロードされた後に開始されます。これらの構成ファイルは、Spring コンテナーに含める必要があるコンポーネント、依存関係注入の実行方法などを定義します。
2. ApplicationContext の作成と初期化: Spring 構成ファイルがロードされると、Spring はその定義に従って ApplicationContext インスタンスを作成し、初期化します。このプロセスは、プレースホルダーの解析、属性の解析など、いくつかの前処理操作を実行します。
3. Bean の作成と初期化: ApplicationContext が作成され初期化された後、Spring は構成ファイルの定義に従って各 Bean (インスタンス化された Bean とも呼ばれる) を作成し、コンテナーに注入します。このプロセスでは、Spring は依存関係に従ってこれらの Bean を並べ替え、依存関係が正しく挿入されていることを確認します。[ログ情報で確認できます]
4. ApplicationContext を外部環境に公開する: ApplicationContext の初期化が完了すると、Spring はそれを外部環境に公開し、他のコンポーネントが使用できるようにします。
[ここが先ほど見た setApplicationContext メソッドです]

主な理由:
Bean がコンテナーによって管理されず、関連する依存関係が注入されないため、Bean は不完全なインスタンスとなり正常に動作できず、null ポインター例外が発生します。

詳細な理由は次のとおりです。
1. インスタンス化時に ApplicationContext がロードされていない (Spring コンテキストが初期化されていない) ため、Spring がパッケージをスキャンしないか、構築と依存関係の注入が完了していません。[クラスのロード時に静的メンバー変数が初期化されるため、Bean が作成/インスタンス化されていないため、上記の理由が発生します] 2.
Spring に静的メンバー変数をインジェクションさせるのではなく、直接静的メンバー変数をインスタンス化します。これにより、他の依存関係が発生する可能性があります。設定に失敗すること。

7. Bean とは一体何ですか?

公式説明:
Spring では、アプリケーションのバックボーンを形成し、Spring IoC コンテナによって管理されるオブジェクトは Bean と呼ばれます。Bean は、Spring IoC コンテナによってインスタンス化、組み立て、管理されるオブジェクトです。
春の豆の説明

概要: Bean は Spring の用語で、 Spring IOC コンテナによって管理されるインスタンス化されたオブジェクト
を指します。これには、POJO (純粋な Java オブジェクト)、ビジネス クラス、データ アクセス オブジェクト、サービス オブジェクトなどが含まれます。Bean はオブジェクトです

補充:

  1. Bean のインスタンス化: Spring コンテナによって作成された Bean は Spring コンテナ内のオブジェクトです。つまり、クラス new オブジェクトによれば、Spring コンテナ内に存在し、必要に応じて直接呼び出すことができますが、実際には呼び出すことはできません。新しいオブジェクト内に存在する必要があります。
  2. 静的メンバー変数を直接インスタンス化します: 直接 (private static a = 新しいクラス)。

8. SpringUtil クラスに @Component を追加します。その中の setApplicationContext (ApplicationContext applicationContext) は、applicationContext の依存関係の注入をどのように実現しますか?

SpringUtil クラスに @Component アノテーションが付けられると、このクラスは Spring コンテナによってスキャンされてコンテナに追加され、同時に Spring はそのインスタンス オブジェクトも作成し、そのオブジェクトをコンテナの管理に組み込みます。
Spring コンテナが初期化されると、@Override の setApplicationContext メソッドが自動的に呼び出され、現在のコンテナに ApplicationContext インスタンス オブジェクトが設定されます。

説明: 現在のコンテナ内の ApplicationContext インスタンス オブジェクト
インスタンス化されるクラスが Aware 型および ApplicationContextAware 型の場合、setApplicationContext(this.applicationContext) メソッドが呼び出されてスプリング コンテキストを設定します。つまり、ApplicationContextAware インターフェイスが実装されます。
ps: 私はこの部分を詳しく読んでいませんが、この最終的な目的だけは知っています。
ApplicationContextAwareインタフェースのsetApplicationContextメソッド呼び出し処理

ここに画像の説明を挿入

9. SpringUtil が @Component と @Override を set メソッドに追加して ApplicationContext を自動的に挿入できるのはなぜですか?

SpringUtil の setApplicationContext メソッドは、@Autowired を使用せずにインジェクションに依存することもできます。
Spring コンテナが起動すると、すべての @Component アノテーションがスキャンされ、それらがインスタンス化され、管理のためにコンテナの BeanFactory に追加されるためです。同時に、Spring はコンテナ自体の ApplicationContext インスタンスを ApplicationContextAware インターフェイス (つまり SpringUtil) を実装する Bean に注入します。したがって、Spring は初期化中に setApplicationContext メソッドを自動的に呼び出し、現在のコンテナの ApplicationContext インスタンスに渡すことができます。

一般に、SpringUtil は、 ApplicationContextAware インターフェイスを介してSpringUtil オブジェクトの setApplicationContext メソッドApplicationContext オブジェクトを挿入し、依存関係の注入を完了します。

10. 一部のクラスは @Autowired で直接注入できますが、一部のクラスは注入用の set メソッドに @Autowired を追加する必要があるのはなぜですか?

主に、非静的と静的の違いです。

  1. 非静的メンバー変数:
    @Autowired を使用して直接注入できます。
    Spring コンテナがインスタンス化されると、ロードされたクラスの Bean (Spring のオブジェクト) がインスタンス化され、 @Autowired アノテーションを通じて
    Bean オブジェクトが Spring コンテナから取得され、変数に注入されます。
  2. 静的メンバー変数:
    初期化はクラスのロード時に Spring コンテナのインスタンス化の前に行われるため、静的メンバー変数の初期化時に @Autowired はコンテナから Bean を取得できません。
    まず静的メンバー変数を定義し、次に Spring コンテナーによって管理されないオブジェクトを Spring コンテナーに追加し、次に setter メソッドを記述して @Autowired をメソッドに追加する必要があります。
    ここに画像の説明を挿入

11. Spring が、ApplicationContextAware インターフェースを実装する Bean にコンテナ自体の ApplicationContext インスタンスを挿入するのはなぜですか?

質問 9 と似ていますが、この質問ではさらに詳しく説明されています。

Spring コンテナは、ApplicationContextAware インタフェースを実装する Bean にコンテナ自体の ApplicationContext インスタンスを注入します。これは、ApplicationContextAware は Spring によって提供されるインタフェースであり、Bean がインスタンス化された後、Bean オブジェクトに ApplicationContext インスタンスへの参照を提供するために使用されます。これにより、Bean は Spring コンテナ自体の機能にアクセスできるようになります。このようにして、Bean は独自のコードで Spring コンテナ内の他の Bean にアクセスできるだけでなく、設定ファイルやリソース ファイルなどの Spring によって提供される他のサービスにもアクセスできます。

実際、ApplicationContextAware は Marker インターフェイスであり、メソッドは定義されていません。このインターフェースを実装することにより、Bean は Spring コンテナにコールバック関数やイベント リスナーを登録せず、この Bean が Spring コンテナに一定の依存関係を持っており、ApplicationContext インスタンスを注入するために Spring コンテナが必要であることを Spring コンテナに示すだけです。Spring コンテナが Bean を初期化するときに、Bean が ApplicationContextAware インターフェースを実装していることが判明すると、Bean の setApplicationContext メソッドを呼び出して、Bean の依存関係要件を満たすために ApplicationContext インスタンスを Bean に注入します。

おすすめ

転載: blog.csdn.net/weixin_42516475/article/details/130188299