如何在 XML 配置文件中使用 Spring Boot 自动配置的 bean?

Posted

技术标签:

【中文标题】如何在 XML 配置文件中使用 Spring Boot 自动配置的 bean?【英文标题】:How can I use Spring Boot auto-configured beans in XML configuration files? 【发布时间】:2014-10-19 04:15:16 【问题描述】:

我想利用 XML 配置文件中的一些 Spring Boot 自动配置的 bean,但是当我尝试这样做时,我总是遇到异常和错误。

例如,如果我的类路径上有与数据相关的库,Spring Boot 将自动配置一个 DataSource 对象,我可以将其自动装配到我自己的 bean 和类中,如下所示:

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

但是,如果我尝试在 XML 配置文件中做同样的事情,我会得到一个异常。我一直在通过将@ImportResource("classpath:xmlconfig.xml") 添加到我的主配置类来引导 XML 配置文件。这是我正在谈论的一个例子......内部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>

尽管dataSource 是一个有效的、自动配置的 Bean 名称,但在运行 Spring Boot 应用程序时,上述内容会出现异常。我还尝试使用自动配置的ConnectionFactory(在类路径上使用 ActiveMQ)和在类路径上使用 Hibernate 和 JPA 的EntityManagerFactory,但这些都不起作用。

基本上,我要问的是:什么相当于将 Spring Boot 自动配置的 bean 自动装配到 XML 配置文件中?

这是我的主要 Spring Boot 入口点,只是所有文档中列出的标准类:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application 

    public static void main(String[] args) throws Exception 
        SpringApplication.run(Application.class, args);
    

我主要在 Spring Integration 应用程序中使用它,其中 Java 配置尚未得到很好的支持,框架的核心是基于 XML 配置的,但我想使用 Spring Boot 自动配置 @987654331 @ 和ConnectionFactory bean 中的一些集成元素。

编辑:@AdilF 提供的答案适用于 dataSource bean,但类似的配置不适用于 connectionFactory bean。请参阅以下 GitHub 项目的演示代码来说明这一点:

https://github.com/ccampo133/autoconfig-test/tree/master

如果有人能弄清楚如何正确连接connectionFactory bean,我将不胜感激。

以下是说明这一点的大部分代码:

Application.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>

build.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"

【问题讨论】:

您在哪里创建数据源?您的 java 配置和 xml 配置都没有创建数据源。 Spring Boot 如果你启用了@EnableAutoConfiguration 功能,就会自动创建一个DataSource。然后,您可以将其自动连接到您的 JavaConfig bean。 对于初学者,您的Application 类需要在已经存在的内容旁边添加@Configuration 注释。基于 Java 的配置和 XML 配置之间的主要区别在于,Java 配置基于类型注入,而 XML 配置基于名称。我建议不要创建 Config 类,而是将那里的 @Configuration@ImportResource 移动到您的应用程序类(或者将 Application 类上的内容移动到您的 Config 类)。跨度> 应用程序类用@Configuration注解。我一定在帖子里把它漏掉了。无论哪种情况,如果我将所有内容都移至应用程序类,我仍然会遇到同样的问题。 @ComponentScan 注释的目的是让我不必在主类中包含所有 bean 定义,因此它不应该改变任何东西。 您需要做的就是从您的Application.java 文件中删除@Configuration @ComponentScan @EnableAutoConfiguration 并将其放在Config.java 上。这对我有用。 【参考方案1】:

以下示例代码对我有用。

主要应用

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 配置

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;


酒吧服务

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>

【讨论】:

我启动 Spring Boot 的主类已经设置了该注释......所以那里没有骰子。我应该在我的原始帖子中更清楚 - 我会继续更新它。 在这种情况下,将 --debug 选项添加到命令行参数并检查 spring boot 是否正在获取所有配置。如果你可以发布一个描述问题的 github 项目,我可以看看。 当使用--debug 运行时,Boot 甚至没有足够远来吐出自动配置报告。它似乎是先解析 XML 文件,然后再做其他任何事情。 你的类路径上有spring-boot-starter-data-jpa吗? 是的。你有一个简单的项目吗?我想看看。【参考方案2】:

我使用了您的 autoconfig-test 示例项目并且能够让它工作。我发现您的 xml 的唯一问题如下...

我假设您想使用嵌入式代理。当我运行你的项目时,这是自动配置的......

@Bean
public ConnectionFactory jmsConnectionFactory() 
    return this.properties.createConnectionFactory();

这将创建一个名为 jmsConnectionFactory 的 bean,但是您的 xml 正在尝试连接一个名为 connectionFactory 的 bean。将 bean 名称更改为 jmsConnectionFactory 修复了该问题...

<bean id="barService" class="app.service.BarService">
    <property name="dataSource" ref="dataSource"/>
    <property name="connectionFactory" ref="jmsConnectionFactory"/>
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

我不知道你为什么要使用 xml,但它确实有效。

编辑: 我还要补充一下,对于如何使用spring jpa集成可能存在一些误解。尽管 EntityManagerFactory 的自动装配确实有效,但它确实不应该直接使用。您应该按如下方式连接 EntityManager...

@PersistenceContext
private EntityManager entityManager

我知道它超出了这个问题的范围,但我只是想我应该补充一下

【讨论】:

以上是关于如何在 XML 配置文件中使用 Spring Boot 自动配置的 bean?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 xml 配置文件、JAVA、Spring 安全性对 LDAP 用户进行身份验证

如何在spring中配置定时任务

如何在spring中配置定时任务

如何把spring配置文件拆解成多个

如何让是spring启动时加载一个类。这里类实现了读取xml配置数据到内存中(不是属性文件)

如何在基于xml的spring配置中为hibernate.javax.cache.uri属性指定相对路径