web-dev-qa-db-ja.com

クラスの新しいインスタンスのSpring @Autowired

私はSpringにあまり詳しくなく、次のような状況にあります。

リポジトリクラス:

@Repository
public class MyRepository {
    // ...
}

リポジトリクラスを使用するクラス:

public class MyClass extends AbstractClass {

    @Autowired
    private MyRepository myRepository;

    //...
}

MyClass@Componentで注釈を付け、@Autowiredで使用すると、@AutowiredMyRepositoryが問題なく解決されることを知っています。問題は、MyClassの新しいインスタンスをリフレクションで作成する必要がある状況にあることです。したがって、MyRepositoryは決して解決されず、常にnullです。

この状況で@Autowiredを使用する方法はありますか?

私の状況をより良く説明する:AbstractClassの実装がいくつかあります。アプリケーションのセットアップフェーズで、これらの実装のHashMapを作成します。基本的に:

{"MyClass", MyClass.class}
//...

次に、URLにマップされる汎用Controllerを持っています/{class}?options=...{class}@PathVariableを使用して、上記のHashMapとリフレクションのインスタンスを作成できます指定されたoptionsに基づくクラス(この部分は重要です)。あなたはこれを行うより良い方法があると思いますか?

前もって感謝します

10
João Menighin

Spring自体は、newまたはnewInstance()などによって作成したオブジェクトで自動配線を行うための機能を提供します。

それを使用するには、 AutowireCapableBeanFactory が必要です。これは、_@Autowired_を使用したSpringの通常の依存性注入によって取得できます。

_@Autowired
private  AutowireCapableBeanFactory autowireCapableBeanFactory;
_

次に、 autowireBean(Object) メソッドを使用して、_@Autowired_プロパティをBeanに注入します。

_Object myBean = map.get(className).newInstance();
autowireCapableBeanFactory.autowireBean(myBean);
_

デザインノート:

上記のアプローチが本当に必要な場合はよく考えてください。 AutowireCapableBeanFactory のjavadocは、ほとんどのユースケースでこのインターフェースを使用しないことを推奨しています。

BeanFactoryのこのサブインターフェースは、通常のアプリケーションコードで使用するためのものではありません。典型的なユースケースでは、BeanFactoryまたはListableBeanFactoryに固執します。

他のフレームワークの統合コードは、このインターフェースを活用して、Springがライフサイクルを制御しない既存のBeanインスタンスをワイヤリングおよび移植できます。これは、たとえばWebWork ActionsやTapestry Pageオブジェクトなどで特に役立ちます。

12
Thomas Fritsch

1つの回避策は、MyClassをHashmapにバインドしてFactoryクラスをバインドする代わりにです。 MyClassFactory。この方法で、正しいクラスをインスタンス化し、正しいリポジトリを初期化するジョブを実行する具体的なファクトリに構築を委任します。

以下に例を示します。

{"MyClass", MyClassFactory.class}

ファクトリーをコンポーネントにすることもできます。その場合、ハッシュマップをファクトリークラスではなくファクトリーインスタンスにバインドする必要があります。しかし、それがコンポーネントではないと言ってみましょう。

//@Component   this is optional
    public MyClassFactory {
        //@Autowired optional
        ApplicationContext ctx;


       public MyClass createInstance() {
            MyRepository repo = ctx.getBean("")
            MyClass myclass = new MyClass(repo)
            return myclass;
       }
    }

コンポーネントとしてマークすると、ApplicationContextを自動配線する場合にApplicationContextAwareインターフェイスを使用することもできます。

3

ここで Factory Design Pattern を使用できます。

これは最初は少し複雑に見えるかもしれませんが、実装した後はきっと気に入っていただけると思います。

手順:

  1. AbstractClassのすべての実装に@Componentを追加します。
  2. ファクトリクラスを次のように作成します。

    @Component
    public class MyFactory {
    
        private final Map<String, AbstractClass> impletationMap = new HashMap<>();
    
        @Autowired
        ApplicationContext context;
    
        @PostConstruct
        public void initialize() {
            populateDataMapperMap(context.getBeansOfType(AbstractClass.class).values().iterator());
        }
    
        private void populateDataMapperMap(final Iterator<AbstractClass> classIterator) {
            while (classIterator.hasNext()) {
                AbstractClass abstractClassImpl = (AbstractClass) classIterator.next();
                impletationMap.put(abstractClassImpl.getClass().getName(), abstractClassImpl);
    
            }
        }
    }
    

このMyFactoryクラスのBeanが初期化されると、AbstractClass型のすべてのBeanが検索され、HashMap(implementationMap)に配置されます。

これで、このファクトリからHashMapを取得し、必要に応じて実装を取得できます。 Factoryが処理するので、AbstractClassの新しい実装を追加すると、非常に簡単になります。

3
Rishabh Agarwal

これを試して

@Component    
public class SomeClass extends AbstractClass {

  private static ApplicationContext applicationContext;

  public MyClass getMyClass(){
      // Now @Autowired MyRepository will work
      return applicationContext.getBean(MyClass.class);
  }

}
1
Maruthi Adithya

1つの方法は、MyClassの上に@Componentを宣言することです。

次に、セットアップフェーズで、HashMapでMyClass.class自体の代わりにMyClassinstanceを渡すことができます。リフレクションを介してインスタンスを作成する必要はありません。

注:セットアップフェーズでMyClassからApplicationContextのインスタンスをフェッチできます。

1
Pankaj Singhal

はい、すべてのAbstractClass実装Beanに@Componentアノテーションを付け、次の宣言を使用できます

@Autowired
private List<AbstractClass> beans;

その後、@ PostConstructメソッドでそれをMapに変換できます。

リストを自動配線しても、Springは重複した定義について文句を言いません。

0
user10367961