【问题标题】:spring-boot property injection not working in custom @Configuration classspring-boot 属性注入在自定义@Configuration 类中不起作用
【发布时间】:2013-11-16 12:57:53
【问题描述】:

我想创建一个 DatabaseConfig 类来设置与我的数据库相关的东西(EntityManager、DataSource、TransactionManager)并获取我在String 字段上使用@Value("${property.name}") 的属性

喜欢

@Configuration
public class DataBaseConfig {
    @Value("${hibernate.connection.username}")
    private String hibernateConnectionUsername;
    @Value("${hibernate.connection.password}")
    private String hibernateConnectionPassword;
    @Value("${hibernate.connection.driver_class}")
    private String hibernateConnectionDriverClass;
    @Value("${hibernate.connection.url}")
    private String hibernateConnectionUrl;
    @Value("${hibernate.dialect}")
    private String hibernateDialect;
    @Value("${hibernate.showSql}")
    private String hibernateShowSql;
    @Value("${hibernate.generateDdl}")
    private String hibernateGenerateDdl;

// All my @Beans
}

问题是,所有这些字符串都是 NULL 而不是我的属性文件的值。

如果我将代码放入我的Application 类(具有main 并在SpringApplication.run(Application.class, args); 中引用的类),则值注入有效

简而言之,@Value 在我的 Application 类中有效,但在我的自定义 @Configuration 类中无效:(

可能出了什么问题?还是需要更多信息?

更新:更多代码

方式 1,我的 Application.java 中的 DB Config 和 @Value 可以在有和没有 PropertySourcesPlaceholderConfigurer 的情况下工作

import java.beans.PropertyVetoException;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import com.mchange.v2.c3p0.ComboPooledDataSource;

@Configuration
@ComponentScan
@EnableJpaRepositories
@EnableAutoConfiguration(exclude = HibernateJpaAutoConfiguration.class)
public class Application {
    public static void main(String[] args) throws Throwable {
        SpringApplication.run(Application.class, args);
    }

    // @Bean
    // public static PropertySourcesPlaceholderConfigurer properties() {
    // PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
    // pspc.setLocations(new Resource[] { new ClassPathResource("application.properties") });
    // return pspc;
    // }

    /*****************************/
    @Value("${hibernate.connection.username}")
    private String hibernateConnectionUsername;

    @Value("${hibernate.connection.password}")
    private String hibernateConnectionPassword;

    @Value("${hibernate.connection.driver_class}")
    private String hibernateConnectionDriverClass;

    @Value("${hibernate.connection.url}")
    private String hibernateConnectionUrl;

    @Value("${hibernate.dialect}")
    private String hibernateDialect;
    @Value("${hibernate.showSql}")
    private String hibernateShowSql;
    @Value("${hibernate.generateDdl}")
    private String hibernateGenerateDdl;

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setDatabasePlatform(hibernateDialect);
        boolean generateDdl = Boolean.parseBoolean(hibernateGenerateDdl);
        boolean showSql = Boolean.parseBoolean(hibernateShowSql);
        vendorAdapter.setGenerateDdl(generateDdl);
        vendorAdapter.setShowSql(showSql);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setDataSource(dataSource());
        factory.setPackagesToScan("xxx");

        return factory;
    }

    @Bean
    public DataSource dataSource() {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(hibernateConnectionUsername);
        dataSource.setPassword(hibernateConnectionPassword);
        try {
            dataSource.setDriverClass(hibernateConnectionDriverClass);
        } catch (PropertyVetoException e) {
            throw new IllegalArgumentException("Wrong driver class");
        }

        dataSource.setJdbcUrl(hibernateConnectionUrl);
        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

方式 2(我想要的),无论我在哪里拥有 PropertySourcesPlaceholderConfigurer(应用程序或数据库配置),它自己的文件(DatabaseConfing.java)中的 DB Stuff 都不起作用,因为它总是在 @Beans 之后被调用在 DatabaseConfig 内:(

import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;

import com.mchange.v2.c3p0.ComboPooledDataSource;


@Configuration
public class DatabaseConfig {
    @Value("${hibernate.connection.username}")
    private String hibernateConnectionUsername;
    @Value("${hibernate.connection.password}")
    private String hibernateConnectionPassword;
    @Value("${hibernate.connection.driver_class}")
    private String hibernateConnectionDriverClass;
    @Value("${hibernate.connection.url}")
    private String hibernateConnectionUrl;
    @Value("${hibernate.dialect")
    private String hibernateDialect;
    @Value("${hibernate.showSql}")
    private String hibernateShowSql;
    @Value("${hibernate.generateDdl}")
    private String hibernateGenerateDdl;

        // @Bean
        // public static PropertySourcesPlaceholderConfigurer properties() {
        // PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
        // pspc.setLocations(new Resource[] { new ClassPathResource("application.properties") });
        // return pspc;
        // }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setDatabasePlatform(hibernateDialect);
        boolean generateDdl = Boolean.parseBoolean(hibernateGenerateDdl);
        boolean showSql = Boolean.parseBoolean(hibernateShowSql);
        vendorAdapter.setGenerateDdl(generateDdl);
        vendorAdapter.setShowSql(showSql);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setDataSource(dataSource());
        factory.setPackagesToScan("xxx");

        return factory;
    }

    @Bean
    public DataSource dataSource() {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(hibernateConnectionUsername);
        dataSource.setPassword(hibernateConnectionPassword);
        try {
            dataSource.setDriverClass(hibernateConnectionDriverClass);
        } catch (PropertyVetoException e) {
            throw new IllegalArgumentException("Wrong driver class");
        }
        System.err.println(hibernateConnectionUrl);
        dataSource.setJdbcUrl(hibernateConnectionUrl);
        return dataSource;
    }
}

【问题讨论】:

  • 不完全是重复的,但我希望接受的解决方案适合您:stackoverflow.com/questions/17097521/…
  • 查看您的容器文件(应用程序的上下文),@Value 被处理为某种容器范围,您必须将 <context:property-placeholder location="classpath:the-path-to-your-property-file" /> 添加到您的上下文文件中
  • 我已经尝试使用 PropertySourcesPlaceholderConfigurer,但是占位符是在我的数据库内容的 bean 之后执行的,无论如何。无论代码的位置如何(数据库或应用程序类)
  • 请发布您的其余配置,包括PropertySourcesPlaceholderConfiguere
  • 我刚刚添加了更多代码。

标签: java spring spring-boot


【解决方案1】:

代替您的DatabaseConfig,将以下application.properties 添加到src/main/resources(从而删除您的DatabaseConfig 类)

#DataSource configuration
spring.datasource.driverClassName=<hibernateConnectionDriverClass>
spring.datasource.url=<hibernateConnectionUrl>
spring.datasource.username=<hibernateConnectionUsername>
spring.datasource.password=<hibernateConnectionPassword>

#JPA/HIbernate
spring.jpa.database-platform=<dialect-class>
spring.jpa.generate-ddl=<hibernateGenerateDdl>
spring.jpa.show-sql=<hibernateShowSql>

替换为实际值,spring-boot 会处理这个问题。

提示删除 C3P0 依赖项,因为 Spring 将为您(默认)提供 tomcat 连接池(更新且维护得更积极,尽管名称在没有/外部 Tomcat 的情况下完全可用)。

【讨论】:

  • 这是 hibernate jpa 自动配置器的属性吗?
  • spring.jpa 属性是,其他是基本的 spring jdbc 属性(这些也可以在普通 jdbc 环境中工作)。
  • 很好,它可以工作,但似乎spring配置了另一种命名策略。虽然我的旧表像我的实体一样驼峰化,但它们现在是小写的并且_分隔“HelloWorldEntity”->“hello_world_entity”有点我想我不太在乎,因为该项目是相当新的,我认为没有理由强迫另一个命名策略
  • 默认使用ImprovedNamingStrategy,但通过添加属性spring.jpa.hibernate.naming-strategyapplication.properties可以被覆盖。
  • 非常感谢,这些属性(以及用于 spring-boot 自动配置的其他属性)是否已记录在案?
【解决方案2】:
@Import({ CacheConfig.class, DatabaseConfig.class })
@ComponentScan(excludeFilters = @Filter(Configuration.class))

成功了。

【讨论】:

  • 你在哪里添加了这段代码?我创建的 CacheConfig 文件也有同样的问题。
  • 我在 Application 类中添加了这个
  • 我遇到了同样的问题,Excluding the Configuration from the ComponentScan似乎解决了某些配置文件中@value的非注入
猜你喜欢
  • 1970-01-01
  • 2023-02-14
  • 2021-12-25
  • 2018-10-11
  • 1970-01-01
  • 2016-04-03
  • 2019-12-27
  • 2020-10-26
  • 1970-01-01
相关资源
最近更新 更多