私はSpring 3.0.5を使用しており、可能な限りクラスメンバーに@Autowireアノテーションを使用しています。自動配線する必要があるBeanの1つは、コンストラクターへの引数が必要です。私はSpringドキュメントを調べましたが、コンストラクター引数に注釈を付ける方法への参照を見つけることができないようです。
XMLでは、Bean定義の一部として使用できます。 @Autowireアノテーションに同様のメカニズムはありますか?
例:
@Component
public class MyConstructorClass{
String var;
public MyConstructorClass( String constrArg ){
this.var = var;
}
...
}
@Service
public class MyBeanService{
@Autowired
MyConstructorClass myConstructorClass;
....
}
この例では、@ Autowireアノテーションを使用してMyBeanServiceで「constrArg」の値を指定するにはどうすればよいですか?これを行う方法はありますか?
おかげで、
エリック
@Value
アノテーションが必要です。
一般的な使用例は、
"#{systemProperties.myProp}"
スタイルの式を使用してデフォルトのフィールド値を割り当てることです。
public class SimpleMovieLister {
private MovieFinder movieFinder;
private String defaultLocale;
@Autowired
public void configure(MovieFinder movieFinder,
@Value("#{ systemProperties['user.region'] }"} String defaultLocale) {
this.movieFinder = movieFinder;
this.defaultLocale = defaultLocale;
}
// ...
}
参照:式言語>注釈設定
より明確にするために、シナリオでは、次のような2つのクラス、MybeanService
とMyConstructorClass
を配線します。
@Component
public class MyBeanService implements BeanService{
@Autowired
public MybeanService(MyConstructorClass foo){
// do something with foo
}
}
@Component
public class MyConstructorClass{
public MyConstructorClass(@Value("#{some expression here}") String value){
// do something with value
}
}
更新:異なる値を持つMyConstructorClass
のいくつかの異なるインスタンスが必要な場合は、 修飾子アノテーションを使用
まあ、時々同じ質問に出くわします。私の知る限り、動的パラメーターをコンストラクターに追加したい場合、それはできません。ただし、ファクトリパターンが役立つ場合があります。
public interface MyBean {
// here be my fancy stuff
}
public interface MyBeanFactory {
public MyBean getMyBean(/* bean parameters */);
}
@Component
public class MyBeanFactoryImpl implements MyBeanFactory {
@Autowired
WhateverIWantToInject somethingInjected;
public MyBean getMyBean(/* params */) {
return new MyBeanImpl(/* params */);
}
private class MyBeanImpl implements MyBean {
public MyBeanImpl(/* params */) {
// let's do whatever one has to
}
}
}
@Component
public class MyConsumerClass {
@Autowired
private MyBeanFactory beanFactory;
public void myMethod() {
// here one has to prepare the parameters
MyBean bean = beanFactory.getMyBean(/* params */);
}
}
現在、MyBean
はそれ自体はSpring Beanではありませんが、十分に近いものです。依存性注入は機能しますが、Bean自体ではなくファクトリーを注入します。置き換えたい場合は、新しいMyBean
実装の上に新しいファクトリーを注入する必要があります。
さらに、MyBean
は他のBeanにアクセスできます-ファクトリの自動配線されたものにアクセスできる可能性があるためです。
そして、明らかにgetMyBean
関数にいくつかのロジックを追加したいと思うかもしれませんが、これは私が許す余分な努力ですが、残念ながら私にはこれ以上の解決策はありません。問題は通常、動的パラメーターがデータベースやユーザーインタラクションなどの外部ソースからのものであるため、その情報をすぐに利用できる場合にのみ、実行中にのみそのBeanをインスタンス化する必要があるため、Factory
が非常に適切である。
この例では、
MyBeanService
の「constrArg」の値を@Autowire
アノテーションで指定するにはどうすればよいですか?これを行う方法はありますか?
いいえ、あなたの言う意味ではありません。 MyConstructorClass
を表すBeanは、クライアントBeanを必要とせずに構成可能でなければならないため、MyBeanService
はMyConstructorClass
の構成方法については発言しません。
これは自動配線の問題ではありません。ここでの問題は、MyConstructorClass
が@Component
である場合に、SpringがMyConstructorClass
をインスタンス化する方法です。 MyConstructorClass
構成内で明示的に)。
@Seanが言ったように、ここでの答えの1つは、コンストラクターパラメーターで@Value
を使用することです。これにより、Springはシステムプロパティまたはプロパティファイルからコンストラクター値を取得します。別の方法は、MyBeanService
がMyConstructorClass
を直接インスタンス化することですが、それを行うと、MyConstructorClass
はSpring Beanではなくなります。
次のようにコンポーネントを構成することもできます。
package mypackage;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConstructorClassConfig {
@Bean
public MyConstructorClass myConstructorClass(){
return new myConstructorClass("foobar");
}
}
}
Bean
アノテーションを使用すると、返されたBeanをBeanFactory
に登録するようにSpringに指示します。
したがって、必要に応じて自動配線できます。
@Autowiredと@Valueを使用する必要があります。このトピックの詳細については、これを参照してください post .
もう1つの方法として、オブジェクトのインスタンスが既に作成されていて、それを@autowired依存関係として追加して、すべての内部@autowired変数を初期化する場合、次のようになります。
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
public void doStuff() {
YourObject obj = new YourObject("Value X", "etc");
autowireCapableBeanFactory.autowireBean(obj);
}
別の方法は、コンストラクターにパラメーターを渡す代わりに、それらをゲッターおよびセッターとして使用し、@ PostConstructで必要に応じて値を初期化することです。この場合、Springはデフォルトのコンストラクタを使用してBeanを作成します。以下に例を示します
@Component
public class MyConstructorClass{
String var;
public void setVar(String var){
this.var = var;
}
public void getVar(){
return var;
}
@PostConstruct
public void init(){
setVar("var");
}
...
}
@Service
public class MyBeanService{
//field autowiring
@Autowired
MyConstructorClass myConstructorClass;
....
}
ほとんどの答えはかなり古いため、当時は不可能だったかもしれませんが、実際には、考えられるすべてのユースケースを満たすソリューションがあります。
答えは次のとおりです。
@Value
を使用して、構成ファイルのどこかに値が必要です)これらの問題を解決する解決策は、ApplicationContext
を使用してオブジェクトを手動で作成することです。
@Component
public class MyConstructorClass
{
String var;
public MyConstructorClass() {}
public MyConstructorClass(String constrArg) {
this.var = var;
}
}
@Service
public class MyBeanService implements ApplicationContextAware
{
private static ApplicationContext applicationContext;
MyConstructorClass myConstructorClass;
public MyBeanService()
{
// Creating the object manually
MyConstructorClass myObject = new MyConstructorClass("hello world");
// Initializing the object as a Spring component
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(myObject);
factory.initializeBean(myObject, myObject.getClass().getSimpleName());
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
}
}
次の理由により、これはクールなソリューションです。
@Autowired
はもちろんですが、たとえば@Async
も)。念頭に置いておくべき唯一のことは、インスタンス化するクラス(または必要に応じて@Autowired
コンストラクター)に引数を取らない(そして空にすることができる)コンストラクターを持たなければならないということです。