24

Spring は、FactoryBeanBean の重要な初期化を可能にするインターフェースを提供します。このフレームワークはファクトリー Bean の多くの実装を提供します。また、Spring の XML 構成を使用する場合、ファクトリー Bean は簡単に使用できます。

しかし、Spring 3.0 では、ファクトリー Bean をアノテーション・ベースの構成 (旧称 JavaConfig) で使用する満足のいく方法を見つけることができません。

明らかに、次のように、ファクトリ Bean を手動でインスタンス化し、必要なプロパティを自分で設定できます。

@Configuration
public class AppConfig {

...

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource());
        factory.setAnotherProperty(anotherProperty());

        return factory.getObject();
    }

ただし、、、、またはFactoryBeanなどの Spring 固有のコールバック インターフェイスが実装されている場合、これは失敗します。また、FactoryBean を検査し、それが実装するコールバック インターフェイスを見つけてから、などを呼び出してこの機能を自分で実装する必要があります。InitializingBeanApplicationContextAwareBeanClassLoaderAware@PostConstructsetApplicationContextafterPropertiesSet()

これは私にはぎこちなく、前から後ろに見えます。アプリケーション開発者は、IOC コンテナーのコールバックを実装する必要はありません。

Spring Annotation 構成から FactoryBeans を使用するためのより良い解決策を知っている人はいますか?

4

6 に答える 6

22

これは、自動配線に頼る場合に最もよく解決されると思います。Bean に Java 構成を使用している場合、次のようになります。

@Bean
MyFactoryBean myFactory()
{ 
    // this is a spring FactoryBean for MyBean
    // i.e. something that implements FactoryBean<MyBean>
    return new MyFactoryBean();
}

@Bean
MyOtherBean myOther(final MyBean myBean)
{
    return new MyOtherBean(myBean);
}

したがって、Spring は、XML 構成の場合と同様に、myFactory().getObject() によって返される MyBean インスタンスを挿入します。

これは、@Component/@Service などのクラスで @Inject/@Autowire を使用している場合にも機能するはずです。

于 2012-01-26T09:42:00.210 に答える
21

私が理解している限り、あなたの問題は結果を(他のメソッドで使用するために)したいものですが、sqlSessionFactory()Springコールバックをトリガーするには、注釈付きメソッドからSqlSessionFactory戻る必要があります。SqlSessionFactoryBean@Bean

これは、次の回避策で解決できます。

@Configuration 
public class AppConfig { 
    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactoryBean sqlSessionFactoryBean() { ... }

    // FactoryBean is hidden behind this method
    public SqlSessionFactory sqlSessionFactory() {
        try {
            return sqlSessionFactoryBean().getObject();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    @Bean
    public AnotherBean anotherBean() {
        return new AnotherBean(sqlSessionFactory());
    }
}

ポイントは、@Bean-annotated メソッドへの呼び出しが、返される Bean の初期化を実行するアスペクトによってインターセプトされることです (あなたのFactoryBean場合) 。sqlSessionFactoryBean()sqlSessionFactory()FactoryBean

于 2011-04-04T16:55:46.710 に答える
5

Spring JavaConfig には、FactoryBean で使用する getObject() メソッドを持つConfigurationSupportクラスがありました。

あなたはそれを拡張して使用します

@Configuration
public class MyConfig extends ConfigurationSupport {

    @Bean
    public MyBean getMyBean() {
       MyFactoryBean factory = new MyFactoryBean();
       return (MyBean) getObject(factory);
    }
}

このジラの問題にはいくつかの背景があります

Spring 3.0 では、JavaConfig が Spring コアに移動され、 ConfigurationSupportクラスを取り除くことが決定されました。推奨されるアプローチは、ファクトリの代わりにビルダー パターンを使用することです。

新しいSessionFactoryBuilderからの例

@Configuration
public class DataConfig {
    @Bean
    public SessionFactory sessionFactory() {
        return new SessionFactoryBean()
           .setDataSource(dataSource())
           .setMappingLocations("classpath:com/myco/*.hbm.xml"})
           .buildSessionFactory();
    }
}

ここにいくつかの背景があります

于 2012-02-20T23:19:32.557 に答える
2

これは私がやっていることであり、うまくいきます:

@Bean
@ConfigurationProperties("dataSource")
public DataSource dataSource() { // Automatically configured from a properties file
    return new BasicDataSource();
}

@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource); // Invoking dataSource() would get a new instance which won't be initialized
    factory.setAnotherProperty(anotherProperty());
    return factory;
}


@Bean
public AnotherBean anotherBean(SqlSessionFactory sqlSessionFactory) { // This method receives the SqlSessionFactory created by the factory above
    return new AnotherBean(sqlSessionFactory);
}

宣言した Bean は、引数として他の @Bean メソッドに渡すことができます (同じメソッドを再度呼び出すと、Spring によって処理されない新しいインスタンスが作成されます)。FactoryBean を宣言すると、それが作成する Bean タイプを別の @Bean メソッドの引数として使用でき、適切なインスタンスを受け取ります。使用することもできます

@Autowired
private SqlSessionFactory sqlSessionFactory;

どこでも、それも機能します。

于 2015-11-26T15:11:30.983 に答える
0

これが私がやっている方法です:

@Bean
def sessionFactoryBean: AnnotationSessionFactoryBean = {
  val sfb = new AnnotationSessionFactoryBean

  sfb.setDataSource(dataSource)
  sfb.setPackagesToScan(Array("com.foo.domain"))

  // Other configuration of session factory bean
  // ...

  return sfb
}

@Bean
def sessionFactory: SessionFactory = {
   return sessionFactoryBean.getObject
}

sessionFactoryBean が作成され、適切な作成後のライフサイクルが発生します (afterPropertiesSet など)。

sessionFactoryBean を Bean として直接参照していないことに注意してください。sessionFactory を他の Bean に自動配線します。

于 2011-04-04T22:17:38.543 に答える
0

AppConfiguration に Factory を挿入しないのはなぜですか?

@Configuration
public class AppConfig {

    @Resource
    private SqlSessionFactoryBean factory;

    @Bean 
    public SqlSessionFactory sqlSessionFactory() throws Exception {
       return factory.getObjectfactory();    
    }    
}

しかし、あなたの質問が正しく理解できなかったかもしれません。あなたが何か変なことをしようとしているように見えるので、一歩下がって、本当に必要なものは何かを考え直してください。

于 2011-04-04T16:40:21.497 に答える