context - ¿Cómo puedo usar los beans configurados automáticamente Spring Boot en los archivos de configuración XML?
spring xml config annotation (2)
Me gustaría aprovechar algunos de los beans de configuración automática de Spring Boot en los archivos de configuración XML, pero me mantengo con excepciones y errores cuando intento hacerlo.
Por ejemplo, si tengo bibliotecas relacionadas con datos en la ruta de mi clase, Spring Boot configurará automáticamente un objeto DataSource
que puedo crear automáticamente en mis propios beans y clases, como por ejemplo:
@Configuration
@ImportResource("classpath:xmlconfig.xml")
public class Config {
// This works!!
@Autowired
private DataSource dataSource;
@Bean
public ClassThatRequiresADataSource() {
ClassThatRequiresADataSource foo = new ClassThatRequiresADataSource();
foo.setDataSource(dataSource);
return foo;
}
}
Sin embargo, si trato de hacer lo mismo en un archivo de configuración XML, obtendré una excepción. He estado iniciando el archivo de configuración XML al agregar un @ImportResource("classpath:xmlconfig.xml")
a mi clase de configuración principal. Aquí hay un ejemplo de lo que estoy hablando ... Dentro de xmlconfig.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- THIS DOES NOT WORK! -->
<bean id="anotherClassThatRequiresADataSource" class="my.package.AnotherClassThatRequiresADataSource">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
Lo anterior dará una excepción cuando se ejecute la aplicación Spring Boot, a pesar de que dataSource
es un nombre Bean configurado automáticamente y válido. También he intentado esto con ConnectionFactory
configurada automáticamente (con ActiveMQ en la ruta de clase) y EntityManagerFactory
con Hibernate y JPA en la ruta de clase, y nada de esto funciona.
Básicamente, lo que pregunto es: ¿cuál es el equivalente a la transferencia automática de beans de configuración de Spring Boot a un archivo de configuración XML?
Aquí está mi principal punto de entrada de Spring Boot es solo la clase estándar que figura en todos los documentos:
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Principalmente utilizo esto en una aplicación Spring Integration, donde la configuración de Java aún no está bien soportada y el núcleo del marco se basa en la configuración XML, pero me gustaría usar los beans DataSource
y ConnectionFactory
configurados automáticamente con Spring Boot en Algunos de los elementos de integración.
EDITAR: La respuesta proporcionada por @AdilF funciona para el bean dataSource
, pero una configuración similar no funciona para el bean connectionFactory
. Consulte el siguiente proyecto de GitHub para el código de demostración que ilustra esto:
https://github.com/ccampo133/autoconfig-test/tree/master
Si alguien pudiera descubrir cómo cablear correctamente el bean connectionFactory
, se lo agradecería enormemente.
Aquí está la mayoría del código que ilustra esto:
Aplicacion.java
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Config.java
@Configuration
@ImportResource("classpath:/resources/config.xml")
public class Config { }
FooService.java
@Service
public class FooService {
final private Logger logger = LoggerFactory.getLogger(FooService.class);
@Autowired
private DataSource dataSource;
@Autowired
private ConnectionFactory connectionFactory;
@Autowired
private EntityManagerFactory entityManagerFactory;
@PostConstruct
public void init() {
Assert.notNull(dataSource, "dataSource is null!");
logger.info("dataSource not null");
Assert.notNull(connectionFactory, "connectionFactory is null!");
logger.info("connectionFactory not null");
Assert.notNull(entityManagerFactory, "entityManagerFactory is null!");
logger.info("entityManagerFactory is not null");
}
}
BarService.java
public class BarService {
final private Logger logger = LoggerFactory.getLogger(BarService.class);
private DataSource dataSource;
private ConnectionFactory connectionFactory;
private EntityManagerFactory entityManagerFactory;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public void setEntityManagerFactory(final EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
@PostConstruct
public void init() {
Assert.notNull(dataSource, "dataSource is null!");
logger.info("dataSource not null");
Assert.notNull(connectionFactory, "connectionFactory is null!");
logger.info("connectionFactory not null");
Assert.notNull(entityManagerFactory, "entityManagerFactory is null!");
logger.info("entityManagerFactory is not null");
}
}
config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="barService" class="app.service.BarService">
<!-- THIS WORKS! -->
<property name="dataSource" ref="dataSource"/>
<!-- THIS DOESN''T WORK! -->
<property name="connectionFactory" ref="connectionFactory"/>
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
</beans>
construir.gradle
buildscript {
ext {
junitVersion = "4.11"
springBootVersion = "1.1.5.RELEASE"
springIntegrationVersion = "4.0.3.RELEASE"
activeMqVersion = "5.7.0"
}
repositories {
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
}
}
apply plugin: "java"
apply plugin: "eclipse"
apply plugin: "idea"
apply plugin: "spring-boot"
configurations {
providedRuntime
}
jar {
baseName = "autoconfig-test"
version = "0.0.1-SNAPSHOT"
}
repositories {
mavenCentral()
maven { url "http://repo.spring.io/libs-milestone/" }
}
dependencies {
// Spring Boot starters
compile "org.springframework.boot:spring-boot-starter-data-jpa:${springBootVersion}"
compile "org.springframework.boot:spring-boot-starter-integration:${springBootVersion}"
compile "org.springframework.integration:spring-integration-jms:${springIntegrationVersion}"
// ActiveMQ
compile "org.apache.activemq:activemq-core:${activeMqVersion}"
// Persistence
runtime "com.h2database:h2"
// Test
testCompile "junit:junit:${junitVersion}"
}
El siguiente código de ejemplo funcionó para mí.
Aplicación principal
package app;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.Assert;
import javax.sql.DataSource;
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Config.class);
DataSource dataSource = context.getBean("dataSource", DataSource.class);
Assert.notNull(dataSource);
}
}
Spring Java Config
package app;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.*;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import javax.sql.DataSource;
@Configuration
@EnableAutoConfiguration
@EnableJpaRepositories
@ComponentScan
@ImportResource("classpath:config.xml")
public class Config {
@Autowired
private DataSource dataSource;
}
BarService
package app.service;
import org.springframework.util.Assert;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
public class BarService {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@PostConstruct
public void init() {
Assert.notNull(dataSource);
}
}
FooService
package app.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
@Service
public class FooService {
@Autowired
DataSource dataSource;
@PostConstruct
public void init() {
Assert.notNull(dataSource);
}
}
config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="barService" class="app.service.BarService">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
Utilicé su proyecto de muestra de autoconfig-test y pude hacerlo funcionar. El único problema que encontré con tu xml es el siguiente ...
Supongo que desea utilizar el intermediario incorporado. Cuando ejecuté tu proyecto, eso fue lo que se configuró automáticamente ...
@Bean
public ConnectionFactory jmsConnectionFactory() {
return this.properties.createConnectionFactory();
}
Esto crea un bean llamado jmsConnectionFactory , sin embargo, su xml está intentando conectar un bean llamado connectionFactory . Cambiando el nombre del bean a jmsConnectionFactory arreglos que ...
<bean id="barService" class="app.service.BarService">
<property name="dataSource" ref="dataSource"/>
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
No sé por qué querría usar xml, pero funciona.
Edición: También agregaré que puede haber algún malentendido sobre cómo usar la integración de spring jpa. A pesar de que el cableado automático de EntityManagerFactory funciona, realmente no debería usarse directamente. Debe estar cableando un EntityManager de la siguiente manera ...
@PersistenceContext
private EntityManager entityManager
Sé que está fuera del alcance de esta pregunta, pero solo pensé que debería agregar eso