简体   繁体   中英

Spring - using factory beans in configuration?

What is the correct way to use factory beans in @Configuration classes?

Suppose I have the following for SessionFactory :

@Bean
public AnnotationSessionFactoryBean sessionFactory() {
    AnnotationSessionFactoryBean factory = new AnnotationSessionFactoryBean();
    // set up properties etc.
    return factory;
}

Right now this method returns a bean factory which does not implement SessionFactory . If I use it in another bean with @Autowired as SessionFactory , it works just fine and obtains it from bean factory:

@Controller
public class MyController {
    @Autowired SessionFactory sessionFactory;
    // ...
}

I guess that's OK.

However, it becomes an issue if I want to use the SessionFactory in the same configuration class:

@Bean
public HibernateTransactionManager transactionManager() {
    HibernateTransactionManager man = new HibernateTransactionManager();
    // Ideal - doesn't work because sessionFactory() return type doesn't match:
    // SessionFactory sessionFactory = sessionFactory();
    // Is this one correct?
    // SessionFactory sessionFactory = (SessionFactory) sessionFactory().getObject();
    man.setSessionFactory(sessionFactory);
    return man;
}

What is The Right Way to implement this kind of dependency?

@Configuration approach is still relatively fresh and it has some rough edges. Factory beans are one of them. So the is no Right Way , at least I am not aware of any. Maybe future Spring releases will handles this case somehow. For now, this is my preferred way:

@Bean
public AnnotationSessionFactoryBean sessionFactoryBean() {
    AnnotationSessionFactoryBean factory = new AnnotationSessionFactoryBean();
    // set up properties etc.
    return factory;
}

@Bean
public SessionFactory sessionFactory() {
   return (SessionFactory) sessionFactoryBean().getObject();
}

And use sessionFactory() method whenever needed. If you want to call the sessionFactoryBean().getObject() several times for some reason (eg when FactoryBean does not return singletons), remember to use @Scope annotation. Otherwise Spring will make sure sessionFactory() is called only once and cache the result.

Spring is intelligent enough to perform all required initialization after calling @Bean method and before returning the bean itself. So InitializingBean , DisposableBean , @PostConstruct , etc. are all recognized and treated properly. In fact, I was always finding calling afterPropertiesSet a bit of a hack, because it is the container responsibility.


Also there is a second method advised in Spring Datastore Document - Reference Documentation , which at first sight looks a bit inconsistent, but works great:

@Resource
private Mongo mongo;

@Bean
MongoFactoryBean mongo() {
     return new MongoFactoryBean();
}

So factory is created using @Bean method but the bean created by the factory can be obtained using autowired field. Clever.

You can use it the following way:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class LoginServiceTest {

  @Configuration
  public static class Config {

    @Bean
    public HttpInvokerProxyFactoryBean loginServiceProxy() {
      HttpInvokerProxyFactoryBean proxy = new HttpInvokerProxyFactoryBean();
      proxy.setServiceInterface(LoginService.class);
      proxy.setServiceUrl("http://localhost:8080/loginService");
      return proxy;
    }

  }

  @Inject
  private LoginService loginService;

  @Test
  public void testlogin() {
    loginService.login(...);
  }
}

I found an example of this on the Spring forums .

@Bean
public SessionFactory sessionFactory() {
    AnnotationSessionFactoryBean sessionFactoryBean = 
              new AnnotationSessionFactoryBean();
    // ...configuration code here...
    sessionFactoryBean.afterPropertiesSet();
    return sessionFactoryBean.getObject();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM