138

私はSpring3.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」の値を指定するにはどうすればよいですか?これを行う方法はありますか?

ありがとう、

エリック

4

9 に答える 9

74

@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つのクラスを配線MybeanServiceMyConstructorClass、次のようになります。

@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値が異なる複数の異なるインスタンスが必要な場合は、修飾子アノテーションを使用する必要があります

于 2011-07-18T21:20:51.240 に答える
19

まあ、時々私は同じ質問に出くわします。私の知る限り、コンストラクターに動的パラメーターを追加したい場合は、それを行うことはできません。ただし、ファクトリパターンが役立つ場合があります。

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それ自体は春の豆ではありませんが、それは十分に近いです。MyBean依存性注入は機能しますが、Bean自体ではなくファクトリを注入します。置き換えたい場合は、自分の新しい実装の上に新しいファクトリを注入する必要があります。

さらに、MyBean他のBeanにアクセスできます。これは、工場の自動配線されたものにアクセスできる可能性があるためです。

そして、どうやら関数にロジックを追加したいと思うかもしれませんgetMyBean。これは私が許可する余分な労力ですが、残念ながら私にはこれ以上の解決策はありません。通常、問題は動的パラメーターがデータベースなどの外部ソースから取得されること、またはユーザーの操作であるため、その情報がすぐに利用できる場合にのみ、実行の途中でのみそのBeanをインスタンス化する必要Factoryがあります。

于 2015-12-03T19:48:11.703 に答える
9

MyBeanServiceこの例では、@Autowireアノテーションを使用して「constrArg」の値を指定するにはどうすればよいですか?これを行う方法はありますか?

いいえ、あなたが言っている方法ではありません。Bean表現MyConstructorClassは、クライアントBeanを必要とせずに構成可能である必要があるためMyBeanService、構成方法についてはわかりませんMyConstructorClass

これは自動配線の問題ではありません。ここでの問題は、Springがどのようにインスタンス化するかMyConstructorClassですMyConstructorClass@Componentコンポーネントスキャンを使用しているため、構成でMyConstructorClass明示的に指定していません)。

@Seanが言ったように、ここでの1つの答えは@Value、コンストラクターパラメーターで使用することです。これにより、Springはシステムプロパティまたはプロパティファイルからコンストラクター値をフェッチします。別の方法は、MyBeanService直接インスタンス化MyConstructorClassすることですが、そうすると、SpringBeanでMyConstructorClassはなくなります。

于 2011-07-19T06:51:15.540 に答える
7

次のようにコンポーネントを構成することもできます。

package mypackage;
import org.springframework.context.annotation.Configuration;
   @Configuration
   public class MyConstructorClassConfig {


   @Bean
   public MyConstructorClass myConstructorClass(){
      return new myConstructorClass("foobar");
   }
  }
}

アノテーションを使用してBean、返されたBeanをに登録するようにSpringに指示しますBeanFactory

したがって、必要に応じて自動配線できます。

于 2017-01-22T16:40:29.517 に答える
0

別の方法は、パラメーターをコンストラクターに渡す代わりに、それらをgetterおよびsetterとして使用し、@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;

  ....
}
于 2016-03-06T14:22:58.970 に答える
0

ほとんどの回答はかなり古いため、当時は不可能だったかもしれませんが、実際には、考えられるすべてのユースケースを満たすソリューションがあります。

ですから、答えは次のとおりです。

  • 実際のSpringコンポーネントを提供していません(工場設計)
  • またはすべての状況に適合するわけではありません(@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;
    }
}

これはクールなソリューションです。理由は次のとおりです。

  • これにより、オブジェクトのすべてのSpring機能にアクセスできます(@Autowiredもちろん@Async、たとえば)、
  • コンストラクター引数には任意のソースを使用できます(構成ファイル、計算値、ハードコードされた値など)、
  • 何も変更せずに、数行のコードを追加するだけで済みます。
  • また、Spring管理クラスの不明な数のインスタンスを動的に作成するために使用することもできます(たとえば、複数の非同期エグゼキューターをオンザフライで作成するために使用しています)

覚えておくべき唯一のことは、インスタンス化するクラス(または@Autowired必要に応じてコンストラクター)に引数をとらない(そして空にすることができる)コンストラクターが必要であることです。

于 2016-10-31T09:55:20.587 に答える
0

別の方法として、オブジェクトのインスタンスがすでに作成されていて、それを@autowired依存関係として追加して、すべての内部@autowired変数を初期化する場合は、次のようになります。

@Autowired 
private AutowireCapableBeanFactory autowireCapableBeanFactory;

public void doStuff() {
   YourObject obj = new YourObject("Value X", "etc");
   autowireCapableBeanFactory.autowireBean(obj);
}
于 2018-06-25T22:28:20.343 に答える
0

Zakariaの答えは好きですが、チームがそのアプローチを使用したくないプロジェクトにいて、プロパティファイルからString、integer、float、またはprimative型を使用して何かを構築しようとして立ち往生している場合コンストラクターの場合、コンストラクターのパラメーターにSpringの@Valueアノテーションを使用できます。

たとえば、。で注釈が付けられたクラスのコンストラクターに文字列プロパティをプルしようとしたときに問題が発生しました@Service。私のアプローチはに対して機能しますが、Springがクラスのインスタンスを構築するものになることを示すアノテーション(、など)がある場合@Service、このアプローチは任意のSpringJavaクラスで機能するはずです。@Service@Component

いくつかのyamlファイル(または使用している構成)で、次のようなものがあるとします。

some:
    custom:
        envProperty: "property-for-dev-environment"

コンストラクターがあります:

@Service // I think this should work for @Component, or any annotation saying Spring is the one calling the constructor.
class MyClass {
...
    MyClass(String property){
    ...
    }
...
}

Springは文字列を見つけることができないため、これは実行されませんenvProperty。したがって、これはその値を取得する1つの方法です。

class MyDynamoTable
import org.springframework.beans.factory.annotation.Value;
...
    MyDynamoTable(@Value("${some.custom.envProperty}) String property){
    ...
    }
...

上記のコンストラクターでは、Springはクラスを呼び出し"property-for-dev-environment"、yaml構成から取得したStringを呼び出すときに使用することを認識しています。

注:これは、@ Valueアノテーションが文字列、インターガー用であり、プリミティブ型であると信じています。カスタムクラス(Bean)を渡そうとしている場合は、上記で定義された回答のアプローチが機能します。

于 2020-12-11T16:57:22.677 に答える
-1

@Autowiredと@Valueを使用する必要があります。このトピックの詳細については、この投稿を参照してください。

于 2014-11-22T06:31:23.830 に答える