1

私はSpringのFactoryBeanを把握しようとしていますが、問題がありました。以下の私の情報源を見て、答えてください。それは私のアプリのコンテキストです:

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <context:annotation-config/>

    <bean id="SHADigest" class="com.dtoryanik.spring.factorybean.MessageDigestFactoryBean">
        <property name="algorithmName">
            <value>SHA1</value>
        </property>
    </bean>

    <bean id="defaultDigest" class="com.dtoryanik.spring.factorybean.MessageDigestFactoryBean"/>

    <bean id="digester" class="com.dtoryanik.spring.factorybean.MessageDigester">
        <property name="messageDigest1">
            <ref local="SHADigest"/>
        </property>
        <property name="messageDigest2">
            <ref local="defaultDigest"/>
        </property>
    </bean>
</beans>

実際にはファクトリ Bean です。

public class MessageDigestFactoryBean implements FactoryBean<MessageDigest>{

    private String algorithmName = "MD5";
    private MessageDigest messageDigest = null;

    @Override
    public MessageDigest getObject() throws Exception {
        System.out.println("<> MessageDigestFactoryBean.getObject()");
        return messageDigest;
    }

    @Override
    public Class<?> getObjectType() {
        System.out.println("<> MessageDigestFactoryBean.getObjectType()");
        return MessageDigest.class;
    }

    @Override
    public boolean isSingleton() {
        System.out.println("<> MessageDigestFactoryBean.isSingleton()");
        return true;
    }

    @PostConstruct
    public void postConstructHandler() throws NoSuchAlgorithmException {
        System.out.println("<> MessageDigestFactoryBean.postConstructHandler()");
        messageDigest = MessageDigest.getInstance(algorithmName);
    }

    public void setAlgorithmName(String algorithmName) {
        this.algorithmName = algorithmName;
    }
}

MessageDigester という別のクラスがありますが、トピックに役立つことは何もありません。そして、私はメインメソッドクラスを持っています:

public class MessageDigestDemo {

public static void main(String[] args) {
    GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
    ctx.load("classpath:app-ctx.xml");
    ctx.refresh();

    MessageDigester messageDigester = (MessageDigester) ctx.getBean("digester");
    messageDigester.digest("Hello World!");
}

}

問題は私の出力にあります。私は二重のインスタンス化をしているようです。メソッド isSingleton()、getObject() は、Bean ごとに 2 回呼び出されます (ただし、ファクトリーからは 2 つのインスタンスしか取得しません)。なぜ発生するのですか?多分私は何か間違ったことをしますか?

<> MessageDigestFactoryBean.postConstructHandler()
<> MessageDigestFactoryBean.postConstructHandler()
<> MessageDigestFactoryBean.isSingleton()
<> MessageDigestFactoryBean.getObject()
<> MessageDigestFactoryBean.isSingleton()
<> MessageDigestFactoryBean.getObject()
<> MessageDigestFactoryBean.isSingleton()
<> MessageDigestFactoryBean.getObjectType()
<> MessageDigestFactoryBean.isSingleton()
<> MessageDigestFactoryBean.getObjectType()
4

1 に答える 1

2

MessageDigestFactoryBeanクラスも出力するように変更しましたalgorithmName。これは、ケースをクリアするのに役立ちます。その変更後、出力は次のようになります。

<> MessageDigestFactoryBean.postConstructHandler() SHA1
<> MessageDigestFactoryBean.postConstructHandler() MD5
<> MessageDigestFactoryBean.isSingleton() SHA1
<> MessageDigestFactoryBean.getObject() SHA1
<> MessageDigestFactoryBean.isSingleton() MD5
<> MessageDigestFactoryBean.getObject() MD5
<> MessageDigestFactoryBean.isSingleton() SHA1
<> MessageDigestFactoryBean.getObjectType() SHA1
<> MessageDigestFactoryBean.isSingleton() MD5
<> MessageDigestFactoryBean.getObjectType() MD5

この出力を分析してみましょう。

  1. 2 つのインスタンスを宣言しMessageDigestFactoryBeanたので、Spring がそれらをコンテキストで検出すると、それらを初期化し、その過程で@PostConstruct-で注釈が付けられたメソッドを呼び出しますMessageDigestFactoryBean.postConstructHandler()
  2. 次に、Spring がdigesterBean を発見すると、その依存関係を取得しようとします。Spring は依存関係がFactoryBeanであることを認識し、最終的にFactoryBeanRegistrySupport.getObjectFromFactoryBeanを呼び出します。このメソッドは、最初に Bean がシングルトンかどうかを確認し、 を呼び出しMessageDigestFactoryBean.isSingleton()ます。Bean がシングルトンの場合、最初にファクトリ Bean オブジェクト キャッシュから参照を取得しようとします。この Bean が参照されるのはこれが初めてであるため、まだキャッシュされていないため、 を介して参照が取得MessageDigestFactoryBean.getObject()され、キャッシュされてから返されます。で 2 つのファクトリ Bean を参照しているためdigester、明らかに、このプロセスはそれぞれに対して繰り返されます。
  3. 初期化が完了すると、Spring はContextRefreshedEventをライフサイクル プロセッサに発行しようとするため、 Lifecycleインターフェースを実装するインスタンスのすべての Bean 定義を検索します。基本的に、Spring はコンテキストで定義されたすべての Bean をループし、一致するタイプのシングルトン Bean をチェックします (実際にはさらに多くのチェックがありますが、これらにのみ関心があります)。この過程で、MessageDigestFactoryBean.isSingleton()オブジェクトがシングルトンかどうかを判断するために for factory Bean が呼び出され、MessageDigestFactoryBean.getObjectType()オブジェクトの型がインターフェイスから割り当て可能かどうかを確認するために呼び出されLifecycleます。のインスタンスが 2 つあるためMessageDigestFactoryBean、これらのメソッドはそれぞれ 2 回呼び出されます。

を呼び出すと、このようになりますctx.refresh()。これは単なる見栄えであり、明らかに、フードの下でSpringによってさらに多くのことが行われていますが、あなたの出力に関連して私が見ることができるのはそれだけです. これが最初の質問の答えになることを願っています。

2 番目の質問ですが、いいえ、何も間違ったことはしていません。表示される出力は、Spring が内部でどのように機能するかを反映しているだけです。

于 2013-09-16T09:01:11.087 に答える