ioc injection framework example español dependency annotation java spring inversion-of-control spring-annotations

java - framework - spring injection dependencies



FactoryBeans y la configuración basada en anotaciones en Spring 3.0 (6)

Spring proporciona la interfaz FactoryBean para permitir la inicialización no trivial de los beans. El marco proporciona muchas implementaciones de beans de fábrica y, cuando se utiliza la configuración XML de Spring, los beans de fábrica son fáciles de usar.

Sin embargo, en Spring 3.0, no puedo encontrar una manera satisfactoria de usar beans de fábrica con la configuración basada en anotaciones (née JavaConfig).

Obviamente, podría crear una instancia manual del bean de fábrica y establecer las propiedades requeridas por mí mismo, de este modo:

@Configuration public class AppConfig { ... @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource()); factory.setAnotherProperty(anotherProperty()); return factory.getObject(); }

Sin embargo, esto fallaría si FactoryBean implementara alguna interfaz de devolución de llamada específica de Spring, como InitializingBean , ApplicationContextAware , BeanClassLoaderAware o @PostConstruct por ejemplo. También necesito inspeccionar FactoryBean, averiguar qué interfaces de devolución de llamada implementa, luego implementar esta funcionalidad yo mismo llamando a setApplicationContext , afterPropertiesSet() etc.

Esto me parece incómodo y al revés: los desarrolladores de aplicaciones no deberían tener que implementar las devoluciones de llamada del contenedor IOC.

¿Alguien sabe de una mejor solución para usar FactoryBeans de Spring Annotation configs?


¿Por qué no inyectas la fábrica en tu AppConfiguration?

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

Pero puede que no haya entendido tu pregunta correcta. Porque me parece que estás intentando algo extraño: retrocede un paso y replantea lo que realmente necesitas.


Así es como lo estoy haciendo:

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

El sessionFactoryBean se crea y le suceden las cosas adecuadas del ciclo de vida posterior a la creación (afterPropertiesSet, etc.).

Tenga en cuenta que no hago referencia directamente al sessionFactoryBean como un bean. Yo autowire la sessionFactory en mis otros frijoles.


Creo que esto se resuelve mejor cuando se confía en el cableado automático. Si está utilizando la configuración de Java para los beans, esto le gustaría:

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

Entonces Spring inyectará para nosotros la instancia MyBean devuelta por myFactory (). GetObject () como lo hace con la configuración XML.

Esto también debería funcionar si está utilizando @ Inject / @ Autowire en sus clases de @ Component / @ Service, etc.


Esto es lo que estoy haciendo, y funciona:

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

Cualquier bean que haya declarado se puede pasar como un argumento a cualquier otro método @Bean (invocar nuevamente el mismo método creará una nueva instancia que no se procesará en primavera). Si declara un FactoryBean, puede usar el tipo de bean que crea como argumento para otro método @Bean y recibirá la instancia correcta. También podrías usar

@Autowired private SqlSessionFactory sqlSessionFactory;

En cualquier lugar y funcionará también.


Por lo que entiendo, su problema es lo que quiere que un resultado de sqlSessionFactory() sea ​​un SqlSessionFactory (para su uso en otros métodos), pero debe devolver SqlSessionFactoryBean desde un método @Bean @Bean para desencadenar devoluciones de llamada de Spring.

Se puede resolver con la siguiente solución:

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

El punto es que las llamadas a @Bean Bean-métodos anotados son interceptadas por un aspecto que realiza la inicialización de los beans que se devuelven ( FactoryBean en su caso), por lo que la llamada a sqlSessionFactoryBean() en sqlSessionFactory() devuelve un FactoryBean completamente inicializado.


Spring JavaConfig tenía una clase ConfigurationSupport que tenía un método getObject () para usar con FactoryBean''s.

Lo usarías estar extendiendo

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

Hay algunos antecedentes en este tema de la jira.

Con Spring 3.0, JavaConfig se trasladó a Spring Core y se decidió eliminar la clase ConfigurationSupport . El enfoque sugerido es usar ahora un patrón de construcción en lugar de fábricas.

Un ejemplo tomado del nuevo SessionFactoryBuilder

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

Algunos antecedentes here