私はSpringにあまり詳しくなく、次のような状況にあります。
リポジトリクラス:
@Repository
public class MyRepository {
// ...
}
リポジトリクラスを使用するクラス:
public class MyClass extends AbstractClass {
@Autowired
private MyRepository myRepository;
//...
}
MyClass
に@Component
で注釈を付け、@Autowired
で使用すると、@Autowired
MyRepository
が問題なく解決されることを知っています。問題は、MyClass
の新しいインスタンスをリフレクションで作成する必要がある状況にあることです。したがって、MyRepository
は決して解決されず、常にnullです。
この状況で@Autowired
を使用する方法はありますか?
私の状況をより良く説明する:AbstractClass
の実装がいくつかあります。アプリケーションのセットアップフェーズで、これらの実装のHashMap
を作成します。基本的に:
{"MyClass", MyClass.class}
//...
次に、URLにマップされる汎用Controller
を持っています/{class}?options=...
{class}
@PathVariable
を使用して、上記のHashMap
とリフレクションのインスタンスを作成できます指定されたoptions
に基づくクラス(この部分は重要です)。あなたはこれを行うより良い方法があると思いますか?
前もって感謝します
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オブジェクトなどで特に役立ちます。
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インターフェイスを使用することもできます。
ここで Factory Design Pattern を使用できます。
これは最初は少し複雑に見えるかもしれませんが、実装した後はきっと気に入っていただけると思います。
手順:
ファクトリクラスを次のように作成します。
@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の新しい実装を追加すると、非常に簡単になります。
これを試して
@Component
public class SomeClass extends AbstractClass {
private static ApplicationContext applicationContext;
public MyClass getMyClass(){
// Now @Autowired MyRepository will work
return applicationContext.getBean(MyClass.class);
}
}
1つの方法は、MyClass
の上に@Component
を宣言することです。
次に、セットアップフェーズで、HashMapでMyClass.class
自体の代わりにMyClass
のinstanceを渡すことができます。リフレクションを介してインスタンスを作成する必要はありません。
注:セットアップフェーズでMyClass
からApplicationContext
のインスタンスをフェッチできます。
はい、すべてのAbstractClass実装Beanに@Componentアノテーションを付け、次の宣言を使用できます
@Autowired
private List<AbstractClass> beans;
その後、@ PostConstructメソッドでそれをMapに変換できます。
リストを自動配線しても、Springは重複した定義について文句を言いません。