FactoryBeans and the annotation-based configuration in Spring 3.0

后端 未结 6 1656
-上瘾入骨i
-上瘾入骨i 2020-12-24 14:13

Spring provides the FactoryBean interface to allow non-trivial initialisation of beans. The framework provides many implementations of factory beans and -- when

相关标签:
6条回答
  • 2020-12-24 14:35

    This is what I'm doing, and it works:

    @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);
    }
    

    Any bean you have declared can be passed as an argument to any other @Bean method (invoking the same method again will create a new instance which is not processed by spring). If you declare a FactoryBean, you can use the bean type it creates as an argument for another @Bean method, and it will receive the right instance. You could also use

    @Autowired
    private SqlSessionFactory sqlSessionFactory;
    

    Anywhere and it will work too.

    0 讨论(0)
  • 2020-12-24 14:39

    I think that this is best solved when you rely on auto-wiring. If you are using Java configuration for the beans, this would like:

    @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);
    }
    

    So Spring will inject for us the MyBean instance returned by the myFactory().getObject() as it does with XML configuration.

    This should also work if you are using @Inject/@Autowire in your @Component/@Service etc classes.

    0 讨论(0)
  • 2020-12-24 14:46

    Spring JavaConfig had a ConfigurationSupport class that had a getObject() method for use with FactoryBean's.

    You would use it be extending

    @Configuration
    public class MyConfig extends ConfigurationSupport {
    
        @Bean
        public MyBean getMyBean() {
           MyFactoryBean factory = new MyFactoryBean();
           return (MyBean) getObject(factory);
        }
    }
    

    There is some background in this jira issue

    With Spring 3.0 JavaConfig was moved into Spring core and it was decided to get rid of the ConfigurationSupport class. Suggested approach is to now use builder pattern instead of factories.

    An example taken from the new SessionFactoryBuilder

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

    Some background here

    0 讨论(0)
  • 2020-12-24 14:46

    Why do you not inject the Factory in your AppConfiguration?

    @Configuration
    public class AppConfig {
    
        @Resource
        private SqlSessionFactoryBean factory;
    
        @Bean 
        public SqlSessionFactory sqlSessionFactory() throws Exception {
           return factory.getObjectfactory();    
        }    
    }
    

    But may I did not understand your question correct. Because it looks to me that you are trying something strange - go a step back and rethink what are you really need.

    0 讨论(0)
  • 2020-12-24 14:48

    As far as I understand your problem is what you want a result of sqlSessionFactory() to be a SqlSessionFactory (for use in other methods), but you have to return SqlSessionFactoryBean from a @Bean-annotated method in order to trigger Spring callbacks.

    It can be solved with the following workaround:

    @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());
        }
    }
    

    The point is that calls to @Bean-annotated methods are intercepted by an aspect which performs initialization of the beans being returned (FactoryBean in your case), so that call to sqlSessionFactoryBean() in sqlSessionFactory() returns a fully initialized FactoryBean.

    0 讨论(0)
  • 2020-12-24 14:50

    Here is how I am doing it:

    @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
    }
    

    The sessionFactoryBean gets created and the proper post-create lifecycle stuff happens to it (afterPropertiesSet, etc).

    Note that I do not reference the sessionFactoryBean as a bean directly. I autowire the sessionFactory into my other beans.

    0 讨论(0)
提交回复
热议问题