【问题标题】:Spring Boot application.properties value not populatingSpring Boot application.properties 值未填充
【发布时间】:2014-11-04 01:05:49
【问题描述】:

我有一个非常简单的 Spring Boot 应用程序,我正在尝试使用一些外部配置。我尝试关注spring boot documentation 上的信息,但遇到了障碍。

当我在 application.properties 文件中的外部配置下运行应用程序时,不会将其填充到 bean 内的变量中。我确定我在做一些愚蠢的事情,感谢您的任何建议。

MyBean.java(位于 /src/main/java/foo/bar/)

package foo.bar;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    @Value("${some.prop}")
    private String prop;

    public MyBean() {
        System.out.println("================== " + prop + "================== ");
    }
}

Application.java(位于/src/main/java/foo/)

package foo;

import foo.bar.MyBean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

    @Autowired
    private MyBean myBean;

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

application.properties(位于 /src/main/resources/)

some.prop=aabbcc

执行 Spring Boot 应用时的日志输出

grb-macbook-pro:properties-test-app grahamrb$ java -jar ./build/libs/properties-test-app-0.1.0.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.5.RELEASE)

2014-09-10 21:28:42.149  INFO 16554 --- [           main] foo.Application                          : Starting Application on grb-macbook-pro.local with PID 16554 (/Users/grahamrb/Dropbox/dev-projects/spring-apps/properties-test-app/build/libs/properties-test-app-0.1.0.jar started by grahamrb in /Users/grahamrb/Dropbox/dev-projects/spring-apps/properties-test-app)
2014-09-10 21:28:42.196  INFO 16554 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@67e38ec8: startup date [Wed Sep 10 21:28:42 EST 2014]; root of context hierarchy
2014-09-10 21:28:42.828  INFO 16554 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2014-09-10 21:28:43.592  INFO 16554 --- [           main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080
2014-09-10 21:28:43.784  INFO 16554 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2014-09-10 21:28:43.785  INFO 16554 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.54
2014-09-10 21:28:43.889  INFO 16554 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-09-10 21:28:43.889  INFO 16554 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1695 ms
2014-09-10 21:28:44.391  INFO 16554 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-09-10 21:28:44.393  INFO 16554 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
================== null==================
2014-09-10 21:28:44.606  INFO 16554 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-09-10 21:28:44.679  INFO 16554 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2014-09-10 21:28:44.679  INFO 16554 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2014-09-10 21:28:44.716  INFO 16554 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-09-10 21:28:44.716  INFO 16554 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-09-10 21:28:44.902  INFO 16554 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-09-10 21:28:44.963  INFO 16554 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-09-10 21:28:44.965  INFO 16554 --- [           main] foo.Application                          : Started Application in 3.316 seconds (JVM running for 3.822)
^C2014-09-10 21:28:54.223  INFO 16554 --- [       Thread-2] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@67e38ec8: startup date [Wed Sep 10 21:28:42 EST 2014]; root of context hierarchy
2014-09-10 21:28:54.225  INFO 16554 --- [       Thread-2] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

【问题讨论】:

  • 在构造bean之前应该如何替换@Value?如果设置了值,您“检测”的方式是错误的。那时它总是为空,因为@Value 将在对象构造之后处理。

标签: java spring spring-boot


【解决方案1】:

您执行属性注入的方式将不起作用,因为注入是在调用构造函数之后完成的。

您需要执行以下操作之一:

更好的解决方案

@Component
public class MyBean {

    private final String prop;

    @Autowired
    public MyBean(@Value("${some.prop}") String prop) {
        this.prop = prop;
        System.out.println("================== " + prop + "================== ");
    }
}

可行但可测试性和可读性稍差的解决方案

@Component
public class MyBean {

    @Value("${some.prop}")
    private String prop;

    public MyBean() {

    }

    @PostConstruct
    public void init() {
        System.out.println("================== " + prop + "================== ");
    }
}

另请注意,这不是 Spring Boot 特定的,但适用于任何 Spring 应用程序

【讨论】:

  • 我必须在构造函数中添加一个@Autowired 注解才能使其工作
  • 感谢您的提示。这应该在 Spring 文档中讨论 @Value 注释 - 但这些人似乎对他们文档的反馈不感兴趣:(
  • 为我节省了一些烦恼。谢谢!
  • @geoand 如果您有超过 10 个值,您是否必须按照您的方式输入所有 10 个值?或者有没有更清洁的方法
  • @Jackie 确实有更清洁的方法!查看@ConfigurationProperties@EnableConfigurationProperties 注释
【解决方案2】:

用户“geoand”在这里指出原因并给出解决方案是正确的。但更好的方法是将您的配置封装到一个单独的类中,例如 SystemContiguration java 类,然后将该类注入您想要使用这些字段的任何服务中。

您当前将配置值直接读取到服务中的方式 (@grahamrb) 容易出错,并且如果更改配置设置名称会导致重构问题。

【讨论】:

  • 如果您为该属性设置了一个单独的类,怎么会少一些麻烦呢?重构时仍然需要记住一个字符串
  • 只有一个地方你需要“记住”,而不是N个。 SystemContiguration 上存在的标量值为您提供强类型。此外,如果有业务逻辑具有“分叉”~~~基于来自配置的值~~~.....最好将一些东西注入需要这些值的类/businessLogic。 Aka,模拟 SystemContiguration 然后尝试让@Value 在整个地方工作要容易得多。
【解决方案3】:

此答案可能适用于您的情况,也可能不适用于您的情况......一旦我有类似的症状并且我多次仔细检查我的代码并且一切看起来都很好,但@Value 设置仍然没有生效。然后用我的IntelliJ(我的IDE)做File &gt; Invalidate Cache / Restart之后,问题就消失了......

这很容易尝试,所以可能值得一试

【讨论】:

    【解决方案4】:

    实际上,对我来说,下面的工作正常。

    @Component
    public class MyBean {
    
       public static String prop;
    
       @Value("${some.prop}")
       public void setProp(String prop) {
          this.prop= prop;
       }
    
       public MyBean() {
    
       }
    
       @PostConstruct
       public void init() {
          System.out.println("================== " + prop + "================== ");
       }
    

    }

    现在只要我想调用就可以了

    MyBean.prop

    它会返回值。

    【讨论】:

      【解决方案5】:

      使用环境类我们可以得到应用程序。属性值

      @Autowired,

      private Environment env;
      

      并使用

      访问
      String password =env.getProperty(your property key);
      

      【讨论】:

        【解决方案6】:

        按照以下步骤操作。 1:- 创建你的配置类,如下所示

        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.beans.factory.annotation.Value;
        
        @Configuration
        public class YourConfiguration{
        
            // passing the key which you set in application.properties
            @Value("${some.pro}")
            private String somePro;
        
           // getting the value from that key which you set in application.properties
            @Bean
            public String getsomePro() {
                return somePro;
            }
        }
        

        2:- 当你有一个配置类时,然后从你需要的配置中注入变量。

        @Component
        public class YourService {
        
            @Autowired
            private String getsomePro;
        
            // now you have a value in getsomePro variable automatically.
        }
        

        【讨论】:

          【解决方案7】:

          如果您正在处理具有多个不同application.properties 文件的大型多模块项目,请尝试将您的值添加到 项目的属性文件中。

          如果您不确定哪个是您的父项目,请检查您的项目的 pom.xml 文件中的 &lt;parent&gt; 标记。

          这为我解决了这个问题。

          【讨论】:

            【解决方案8】:

            你可以使用Environment类来获取数据:

            @Autowired
            private Environment env;
            String prop= env.getProperty('some.prop');
            

            【讨论】:

              【解决方案9】:

              为我解决此问题的最简单解决方案:

              在需要填充@Value字段的Component/Service中添加@PropertySource注解:

              @Service
              @PropertySource("classpath:myproperties.properties")
              public class MyService {
              
                @Value("${some.prop}")
                private String someProperty;
              
                // some logic...
              }
              

              确保将属性文件添加到与您的服务/组件相同的模块的资源文件夹中。

              【讨论】:

                【解决方案10】:

                您收到此错误是因为您正在使用 new 关键字初始化类。为了解决这个问题, 首先你需要创建配置类,在这个类下你需要创建这个类的bean。 当您使用 bean 调用它时,它将起作用..

                package ca.testing;
                import org.springframework.beans.factory.annotation.Autowired;
                import org.springframework.beans.factory.annotation.Value;
                import org.springframework.context.annotation.AnnotationConfigApplicationContext;
                import org.springframework.context.annotation.Bean;
                import org.springframework.context.annotation.PropertySource;
                import org.springframework.stereotype.Component;
                
                import javax.annotation.PostConstruct;
                import java.sql.Connection;
                import java.sql.DriverManager;
                
                @Component
                @PropertySource("db.properties")
                public class ConnectionFactory {
                    @Value("${jdbc.user}")
                    private String user;
                    @Value("${jdbc.password}")
                    private String password;
                    @Value("${jdbc.url}")
                    private String url;
                    Connection connection;
                
                    public Connection getConnection(){
                        try {
                            connection = DriverManager.getConnection(url, user, password);
                            System.out.println(connection.hashCode());
                        }catch (Exception e){
                            System.out.println(e);
                        }
                        return connection;
                    }
                
                    public static void main(String[] args) {
                        AnnotationConfigApplicationContext context= new AnnotationConfigApplicationContext(Config.class);
                        ConnectionFactory connectionFactory= context.getBean(ConnectionFactory.class);
                        connectionFactory.getConnection();
                    }
                }
                

                【讨论】:

                  猜你喜欢
                  • 2016-12-13
                  • 2016-09-29
                  • 2016-03-04
                  • 2021-02-07
                  • 1970-01-01
                  • 2017-02-16
                  • 2019-03-18
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多