5

Spring構成ファイルでBeanを定義しましたが、

 <bean id="accountConfigFile" class="java.lang.String">
    <constructor-arg index="0" type="java.lang.String" value="/account.properties"/>
</bean>

次に、この Bean を AccountHelper クラスのフィールドに接続します。

@Autowired
@Qualifier("accountConfigFile")
private static String configFilename;

ただし、コンストラクターでアクセスしようとすると、null であるため、NullPointerException が発生しました。

public Class AccountHelper {

    private Properties properties;

    @Autowired
    @Qualifier("accountConfigFile")
    private static String configFilename;

    public AccountHelper() {
        properties = new Properties();
        InputStream is = null;

        try
        {
            is = getClass().getResourceAsStream(configFilename);
            properties.load(is);
            is.close();

        } catch (Exception e)
        {
                    ......
        }
    }
    ......

}

なぜこれが起こるのかを理解するのを手伝ってくれる人はいますか?

どうもありがとう!

4

7 に答える 7

1

まず第一に、@ rAyが言ったように、静的フィールドに注入しないでください。正直なところ、それはまったく意味がありません。

質問に戻ります(フィールドを非静的に変更したと仮定します)。問題全体は(まだ)自動配線に関連していません。すでにかなりの回答が指摘されているように、Springでは、最初にBeanのインスタンスが作成され、その後、フィールド/セッターの注入が行われます。したがって、コンストラクターは、使用するフィールドを挿入する前に実行されます。

この問題を解決する方法はたくさんあります。私は最も一般的なオプションのいくつかをリストしています(私はまだもっと多くの方法があるに違いありません)、それらを理解して、あなたのデザインに合ったものを選んでください。

コンストラクターインジェクション

フィールドに注入する代わりに、コンストラクターを介して注入することを選択できます。AccountHelperを次のようにします。

public Class AccountHelper {

    private String configFilename;

    public AccountHelper(String configFilename) {
        this.configFilename = configFilename;
        // do something base on configFilename
    }
}

コンストラクター引数に自動配線を使用するか、XMLで明示的に宣言することができます(あなたの質問から、あなたはそれを行う方法を知っているようです)

初期化方法

Springでは、すべてのプロパティが設定された後に初期化メソッドを使用する方法がたくさんあります。したがって、次のようなことができます。

public Class AccountHelper implements InitializingBean{

    private String configFilename;
    // corresponding setters etc

    public AccountHelper() {
        // don't do initialization in ctor
    }

    @Override
    public void afterPropertiesSet() {
        // called after property injections finished
        // do something base on configFilename
    }
}

または、任意の名前のメソッドを使用して、Springに初期化メソッドとして使用するように指示することもできます。これには、、またはXMLで、またはでなどの注釈@PostConstructinit-method付けinitMethodNameます@Bean

ファクトリービーン

AccountHelperの作成方法をあまり制御できず、作成プロセスを単純なSpring構成で実行するのが難しい場合は、ファクトリBeanを記述してBeanを作成できます。構築ロジックは、ファクトリービーン。


自動配線なしで動作させると、自動配線を追加するのは簡単です。

于 2012-12-19T02:33:55.690 に答える
1

Spring でサポートされていない静的フィールドに値を注入しているようです。本当にこれを行いたい場合は、Spring: How to inject a value to static field?の手順に従うことができます。. しかし、AccountHelper クラスで構成ファイル名を自動配線するのは良い考えではないと思います。プロパティは同じ Spring 構成ファイルで構築できるため、プロパティ オブジェクトを AccountHelper クラスに挿入することをお勧めします。ただし、AccountHelp クラスがプロパティ ファイル内のプロパティ ノードを使用するだけの場合は、setter を使用して、プロパティ ファイルから読み取った値をクラスに挿入するだけです。そしてSpring設定ファイルは次のようになります

<bean id="propertyConfigurer"  
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
    <property name="location" value="/account.properties"/>  
</bean>
<bean class="your.package.AccountHelper">
    <property name="foobar" value="node.name.in.the.properties"/>
</bean>

AccountHelper クラスは次のようになります

public AccountHelper {
    private String foobar;
    public void setFoobar(String foobar) {
        this.foobar = foobar;
    }
    ...other methods
}
于 2012-12-19T02:12:03.590 に答える
0

フィールドの自動配線はオブジェクトの構築後に行われるため、コンストラクター内からアクセスすることはできません。

コンストラクターでBeanを変更する必要がある場合は、フィールド依存性注入の自動配線の代わりにコンストラクターを使用できます。ただし、コンストラクターの依存性注入の制限は、タイプによってのみ検索されることだと思います。あなたのBeanタイプはjava.lang.Stringなので、それは不可能だと思います。

Springがコンストラクター自動配線修飾子を提供しない場合のそれほど洗練されていない解決策の1つは、Stringのサブクラスを作成して、型ごとにコンストラクターインジェクションを使用できるようにすることです。

または、他の方法では、一意のクラスを作成し、文字列プロパティをこのクラスのフィールドとして持つことができます。次に、このクラスをタイプ別に自動配線できます

Springマニュアルの第4章には、これに関する優れた情報が記載されています。http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.htmlをお読みになることをお勧めします。

于 2012-12-19T00:48:59.513 に答える
0

AccountHelperBeanを作成し、コンストラクターインジェクションに切り替えることをお勧めします。

AccountHelper

package com.cloudfoundry.tothought;

@Component(value="AccountHelper")
public class AccountHelper {

    private Properties properties;

    private String configFilename;

    @Autowired
    public AccountHelper(@Qualifier("accountConfigFile") String configFileName) {
        this.configFilename = configFileName;
                //Other logic...
    }

    public String getConfigFilename() {
        return configFilename;
    }

    public void setConfigFilename(String configFilename) {
        this.configFilename = configFilename;
    }
}

応用

public class App {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/META-INF/application-context.xml");
        AccountHelper helper = (AccountHelper) context.getBean("AccountHelper");
        System.out.println(helper.getConfigFilename());
    }
}

application-context.xml

<?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.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <bean id="accountConfigFile" class="java.lang.String">
        <constructor-arg index="0" type="java.lang.String"
            value="/account.properties" />
    </bean>

    <context:component-scan base-package="com.cloudfoundry.tothought"/>
</beans>
于 2012-12-19T01:16:55.993 に答える
0

@Autowiredオブジェクトが構築されるまで Spring はオートワイヤリングを実行できないため、Spring 管理コンポーネントのコンストラクターでプロパティを参照することはできません。

定義上、コンストラクターの実行が完了するまで、オブジェクトはまだ構築されていません。

コンストラクターの実行が完了すると、Spring は@Autowireプロパティを処理します。そのプロパティが利用可能になったらすぐに実行したいことがある場合は、@PostConstructアノテーションを使用して Init メソッドを構成できます。

詳細については、@PostConstruct

于 2012-12-19T03:41:49.237 に答える
0

私は Spring 1の専門家ではありませんが、Spring は最初に AccountHelper をインスタンス化し、次に (その後) 依存関係をプッシュすると思います。したがって、コンストラクターでは、依存関係はまだ準備ができていません。

ロジックをコンストラクターからビジネス メソッド (より適切と思われる) に移動し、最初の必要時にプロパティを遅延ロードすることをお勧めします。コンストラクターはオブジェクトのみを構築する必要があり、プロパティの読み込みはビジネス メソッドのように聞こえます。

1春 それは私のためではありません。いつの日か、人々は Spring を EJB のように見て、「オブジェクトを組み立てるのに Java ではなく xml を書くことを好むのはなぜだろう?」と言うでしょう。

于 2012-12-19T00:53:25.590 に答える
0

ここで文字列を自動配線する必要はないと思います。値を configFilename に渡したい場合は、プロパティでそれを行うことができます。

于 2012-12-19T00:56:26.480 に答える