FactoryBean は、複雑なインスタンス化ロジックを必要とする可能性のあるオブジェクトをプログラムで作成するために使用できます。
ただし、FactoryBean
によって作成されたBeanが作成されたは、スプリング管理されないようです。この解釈は正しいですか?その場合、ニースの回避策はありますか?問題を説明するために、短いコードサンプルが含まれています。
ApplicationContext:
<bean id="searcher" class="some.package.SearcherFactory" />
<bean id="service" class="some.package.Service" />
工場での実装:
public class SearcherFactory implements FactoryBean<Searcher> {
@Override
public Searcher getObject() throws Exception {
return new Searcher(); // not so complex after all ;)
}
@Override
public Class<Searcher> getObjectType() {
return Searcher.class;
}
....
}
ファクトリーによって作成されたクラス:
public class Searcher() {
private Service service;
@Autowired
public void setService(Service service) {
// never invoked
this.service=service;
}
}
FactoryBean
areによって作成されたオブジェクトは、Springによって管理されますが、Springによってインスタンス化または構成されません。 FactoryBean
を使用することにより、あなたはその責任を自分で負います。すべてのインジェクションと設定は、FactoryBean
によって処理される必要があります
より適切に機能する代替手段があります。 XMLベースの構成の代わりに注釈ベースの構成 を使用します。つまり、Javaで複雑なインスタンス化ロジックを使用しながら、@Autowired
オブジェクト自体。
私は今、すべての非自明なSpringアプリに注釈スタイルの設定を使用する傾向があります。これにより、多くのことがより簡単になります。
自動配線を行う抽象FactoryBean
実装は次のとおりです。
_public abstract class AbstractAutowiringFactoryBean<T> extends
AbstractFactoryBean<T> implements ApplicationContextAware{
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(
final ApplicationContext applicationContext){
this.applicationContext = applicationContext;
}
@Override
protected final T createInstance() throws Exception{
final T instance = doCreateInstance();
if(instance != null){
applicationContext
.getAutowireCapableBeanFactory()
.autowireBean(instance);
}
return instance;
}
/**
* Create the bean instance.
*
* @see #createInstance()
*/
protected abstract T doCreateInstance();
}
_
それを拡張し、getObjectType()
メソッドとdoCreateInstance()
メソッドを実装すると、自動配線で起動して実行されます。
注: BeanPostProcessorsは適用されず、追加のコードが必要になります。
これはどうですか ?
<bean id="serviceFactory"
class="some.package.SearcherFactory" />
<bean id="service"
factory-bean="serviceFactory"
factory-method="getObject"/>
...そして、Bean 'サービス'を注入するだけで、コードのファクトリを気にしません
手動の方法は次のとおりです。
ファクトリBeanにApplicationContext
を挿入(またはApplicationContextAware
を実装して取得)して、ctx.getAutowireCapableBeanFactory().autowireBean(bean)
を実行することもできます。
しかし、私は両方とも奇妙に感じると認めます。
しかし、実際には、ロジックがそれほど単純(インスタンス化のみ)の場合は、prototype
スコープを使用します。
FactoryBeanは、開発者としてファクトリクラスを記述するときに実装するインターフェースであり、ファクトリクラスによって作成されたオブジェクトをSpringによってBeanとして管理する必要があります。一方、BeanFactoryはSpring IoCコンテナを表します。管理対象Beanが含まれ、それらを取得するためのアクセスを提供します。これは、制御コンテナの反転の基本機能を実装するフレームワークのコアの一部です。
ほとんどの場合、フレームワークのコア機能を拡張しない限り、BeanFactoryインターフェースを直接使用または実装することはありません。一方、ファクトリーによって作成され、Springで管理する必要があるオブジェクトがある場合は、FactoryBeanを実装します。
もっと簡潔に言うと、BeanFactoryはSpringコンテナを表し、FactoryBeanは作成されたオブジェクトがコンテナ内のBeanとして取得および登録されるファクトリクラスを表します。
File: 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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="sha" class="MessageDigestFactoryBean">
<property name="algorithm" value="SHA1"/>
</bean>
<bean id="md5" class="MessageDigestFactoryBean"/>
</beans>
File: Main.Java
import Java.security.MessageDigest;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class Main {
public static void main(String[] args) {
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("context.xml"));
String d1 = (String) factory.getBean("sha");
String d2 = (String) factory.getBean("md5");
System.out.println(d1);
System.out.println(d2);
}
}
class MessageDigestFactoryBean implements FactoryBean, InitializingBean {
private static final String DEFAULT_ALGORITHM = "MD5";
private String algorithm = DEFAULT_ALGORITHM;
public Object getObject() throws Exception {
return this.algorithm;
}
public Class getObjectType() {
return MessageDigest.class;
}
public boolean isSingleton() {
return true;
}
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
public void afterPropertiesSet() throws Exception {
this.algorithm += " after setting";
}
}