Java FactoryBeans和Spring3.0中基于注释的配置
Spring提供了Java FactoryBeans和Spring3.0中基于注释的配置,java,spring,inversion-of-control,spring-annotations,Java,Spring,Inversion Of Control,Spring Annotations,Spring提供了FactoryBean接口,允许对Bean进行非平凡的初始化。该框架提供了许多工厂bean的实现,当使用Spring的XML配置时,工厂bean很容易使用 然而,在Spring3.0中,我找不到一种令人满意的方法将FactoryBean与基于注释的配置(néeJavaConfig)结合使用 显然,我可以手动实例化工厂bean,并自己设置任何必需的属性,如下所示: @Configuration public class AppConfig { ... @Bean
FactoryBean
接口,允许对Bean进行非平凡的初始化。该框架提供了许多工厂bean的实现,当使用Spring的XML配置时,工厂bean很容易使用
然而,在Spring3.0中,我找不到一种令人满意的方法将FactoryBean与基于注释的配置(néeJavaConfig)结合使用
显然,我可以手动实例化工厂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的回调接口,例如初始化Bean
、ApplicationContextAware
、BeanClassLoaderware
、或@PostConstruct
,那么这将失败。我还需要检查FactoryBean,找出它实现了什么回调接口,然后通过调用setApplicationContext
,afterPropertiesSet()
等自己实现这个功能
这让我觉得很尴尬:应用程序开发人员不应该实现IOC容器的回调
有人知道使用Spring Annotation configs中的FactoryBeans的更好的解决方案吗?为什么不在AppConfiguration中注入Factory
@Configuration
public class AppConfig {
@Resource
private SqlSessionFactoryBean factory;
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
return factory.getObjectfactory();
}
}
但我不明白你的问题是对的。因为在我看来,你正在尝试一些奇怪的事情-退一步,重新思考你真正需要的是什么。据我所知,你的问题是你希望通过
sqlSessionFactory()
成为sqlSessionFactory
(用于其他方法),但是您必须从@Bean
注释的方法返回SqlSessionFactoryBean
,才能触发Spring回调
可以通过以下解决方法解决此问题:
@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
-带注释的方法的调用被一个方面截获,该方面对返回的Bean执行初始化(FactoryBean
,在您的例子中),因此在sqlSessionFactory()中对sqlSessionFactoryBean()
的调用
返回一个完全初始化的FactoryBean
以下是我的操作方法:
@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被创建,适当的创建后生命周期的东西发生在它身上(AfterPropertieSet,等等)
注意,我没有直接将sessionFactoryBean作为bean引用。我将sessionFactory自动连接到我的其他bean中。我认为,当您依靠自动连接时,这是最好的解决方法。如果您正在为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);
}
@Bean
MyFactoryBean myFactory()
{
//这是MyBean的spring FactoryBean
//即实现FactoryBean的东西
返回新的MyFactoryBean();
}
@豆子
MyOtherBean myOther(最终MyBean MyBean)
{
返回新的MyOtherBean(myBean);
}
因此Spring将为我们注入myFactory().getObject()返回的MyBean实例,就像它对XML配置所做的那样
如果您在@Component/@Service等类中使用@Inject/@Autowire,这也应该起作用。Spring JavaConfig有一个类,该类有一个getObject()方法用于FactoryBean
你可以用它来扩展
@Configuration
public class MyConfig extends ConfigurationSupport {
@Bean
public MyBean getMyBean() {
MyFactoryBean factory = new MyFactoryBean();
return (MyBean) getObject(factory);
}
}
这是有一定背景的
在Spring3.0中,JavaConfig被移动到SpringCore中,并决定去掉这个类。建议的方法是现在使用构建器模式,而不是工厂模式
一个新的例子
一些背景知识这就是我正在做的,它是有效的:
@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;
拉尔夫,谢谢你的回复,但是它不起作用,就像FactoryBean一样(在这个例子中,SqlSessionFactoryBean,但是它可以是任何实现
org.springframework.beans.factory.FactoryBean
——例如org.springframework.orm.hibernate3.LocalSessionFactoryBean
)不在我的控制之下(或在我的源代码中),并且未使用@Value/@Resource/@Autowired/@Inject注释进行注释。因此,在我调用Spring上的.getObject()
之前,Spring不会正确地注入它的依赖项。@Andrew Newdigate——工厂本身是XML配置的候选对象,或者如果您不喜欢XML,则在另一个@Bean注释的方法中创建它。(然后你可以使用@Value)我们每次在某处注入“MyBean”实例时,或者每个注入工厂都会创建新实例时,“MyBean”实例会是相同的吗?@KonstantinZyubin这取决于你如何实现该方法。但我不明白使用FactoryBean的好处在哪里。因为在这种情况下,我们可以使用静态工厂简单地创建常规bean,它将返回一个bean,结果将是相同的。是否希望在每次启动sqlSessionFactory时都创建一个新的SQl会话实例?
@Autowired
private SqlSessionFactory sqlSessionFactory;