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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25495629/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 00:02:22  来源:igfitidea点击:

How can I use Spring Boot auto-configured beans in XML configuration files?

springspring-integrationspring-boot

提问by ccampo

I'd like to take advantage of some of the Spring Boot auto-configured beans in XML configuration files, but I keep running into exceptions and errors when I try to do so.

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

For example, if I have data-related libraries on my class path, Spring Boot will auto-configure a DataSourceobject which I can autowire into my own beans and classes, like so:

例如,如果我的类路径中有与数据相关的库,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;
    }
}

However, if I try to do the same in an XML configuration file, I will get an exception. I have been bootstrapping the XML config file by added an @ImportResource("classpath:xmlconfig.xml")to my main configuration class. Here's an example of what I'm talking about... Inside xmlconfig.xml:

但是,如果我尝试在 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>

The above will give an exception when running the Spring Boot app, despite dataSourcebeing a valid, auto-configured Bean name. I've also tried this with the auto-configured ConnectionFactory(with ActiveMQ on the class path) and EntityManagerFactorywith Hibernate & JPA on the class path, and none of this works.

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

Basically, what I'm asking is: what is the equivalent to autowiring Spring Boot auto-configured beans into an XML configuration file?

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

Here's my main Spring Boot entry point is just the standard class listed in all the docs:

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

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

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

I'm mainly using this in a Spring Integration application, where Java Configuration isn't well supported yet and the core of the framework is XML config based, but I'd like to use the Spring Boot auto-configured DataSourceand ConnectionFactorybeans in some of the integration elements.

我主要在 Spring Integration 应用程序中使用它,其中 Java 配置还没有得到很好的支持,并且框架的核心是基于 XML 配置的,但是我想在某些应用程序中使用 Spring Boot 自动配置DataSourceConnectionFactorybean集成元素。

EDIT: The answer provided by @AdilF works for the dataSourcebean, but a similar configuration does not work for the connectionFactorybean. Please see the following GitHub project for demo code that illustrates this:

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

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

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

If anybody could figure out how to properly wire the connectionFactorybean, I would greatly appreciate it.

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

Here's most of the code illustrating this:

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

Application.java

应用程序.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

构建.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}"
}

回答by Adil F

The following sample code worked for me.

以下示例代码对我有用。

Main Application

主要应用

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

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;

}

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>

回答by hyness

I used your autoconfig-test sample project and was able to get it to work. The only problem I found with your xml is as follows...

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

I'm assuming you want to use the embedded broker. When I ran your project, that was what was auto configured...

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

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

This creates a bean named jmsConnectionFactory, however your xml is trying to wire a bean named connectionFactory. Changing the bean name to jmsConnectionFactoryfixes that...

这将创建一个名为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>

I don't know why you would want to use xml, but it does work.

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

Edit:I will also add there may be some misunderstanding of how to use spring jpa integration. Despite the fact the autowiring of the EntityManagerFactorydoes work, it really shouldn't be used directly. You should be wiring an EntityManageras follows...

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

@PersistenceContext
private EntityManager entityManager

I know its beyond the scope of this question, but just thought I should add that

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