Spring Boot application.properties giá trị không điền


97

Tôi có một ứng dụng Spring Boot rất đơn giản mà tôi đang cố gắng làm việc với một số cấu hình bên ngoài. Tôi đã cố gắng làm theo thông tin trên tài liệu khởi động mùa xuân nhưng tôi đang gặp phải một đoạn đường.

Khi tôi chạy ứng dụng bên dưới cấu hình bên ngoài trong tệp application.properties không được điền vào biến trong bean. Tôi chắc chắn rằng tôi đang làm điều gì đó ngu ngốc, cảm ơn vì bất kỳ gợi ý nào.

MyBean.java (nằm trong / 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 (nằm trong / 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 (nằm trong / src / main / resources /)

some.prop=aabbcc

Ghi đầu ra khi thực thi ứng dụng 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

4
Và làm thế nào nên @Valueđược thay thế trước khi đậu được xây dựng? Cách của bạn để "phát hiện" nếu giá trị được đặt là sai. Tại thời điểm đó, nó luôn là null vì @Valuesẽ được xử lý SAU KHI xây dựng đối tượng.
M. Deinum

Câu trả lời:


164

Cách bạn đang thực hiện việc tiêm thuộc tính sẽ không hoạt động, bởi vì việc tiêm được thực hiện sau khi phương thức khởi tạo được gọi.

Bạn cần thực hiện một trong những thao tác sau:

Giải pháp tốt hơn

@Component
public class MyBean {

    private final String prop;

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

Giải pháp sẽ hoạt động nhưng khó kiểm tra hơn và hơi khó đọc

@Component
public class MyBean {

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

    public MyBean() {

    }

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

Cũng lưu ý rằng không phải Spring Boot cụ thể nhưng áp dụng cho bất kỳ ứng dụng Spring nào


Tôi đã có thêm một chú thích @Autowired để các nhà xây dựng để làm cho nó làm việc
Sébastien Tromp

1
Cảm ơn vì tiền hỗ trợ. Điều này cần được trong tài liệu Mùa xuân nơi nó nói về chú thích @value - nhưng những chàng trai dường như không được quan tâm đến phản hồi về tài liệu của họ :(
Alex Worden

1
Đã tiết kiệm cho tôi một số frsutration. Cảm ơn!
Robert Moskal

1
@geoand Điều gì sẽ xảy ra nếu bạn có hơn 10 giá trị, bạn có phải nhập cả 10 như cách bạn đã làm không? Hoặc có cách nào sạch sẽ hơn
Jesse

1
@Jackie Quả thực có một cách sạch sẽ hơn! Kiểm tra @ConfigurationProperties@EnableConfigurationPropertieschú thích
địa lý

5

Người dùng "geoand" đã đúng khi chỉ ra những lý do ở đây và đưa ra giải pháp. Nhưng một cách tiếp cận tốt hơn là đóng gói cấu hình của bạn thành một lớp riêng biệt, chẳng hạn như lớp SystemContiguration java và sau đó đưa lớp này vào những dịch vụ mà bạn muốn sử dụng các trường đó.

Cách hiện tại của bạn (@grahamrb) để đọc các giá trị cấu hình trực tiếp vào các dịch vụ dễ xảy ra lỗi và sẽ gây đau đầu khi cấu trúc lại nếu tên cài đặt cấu hình bị thay đổi.


Làm thế nào sẽ không ít đau đầu hơn nếu bạn có một lớp riêng cho tài sản đó? Bạn vẫn sẽ có một chuỗi cần được ghi nhớ khi tái cấu trúc
dot_Sp0T

4
Chỉ có một chỗ bạn cần "nhớ", không phải số N. Các giá trị vô hướng tồn tại trên SystemContiguration cho phép bạn gõ mạnh. Ngoài ra, nếu có logic nghiệp vụ có "ngã ba" ~~~ dựa trên các giá trị đến từ cấu hình ~~~ ..... thì tốt hơn là nên đưa một thứ gì đó vào lớp / businessLogic cần các giá trị. Aka, việc giả lập SystemContiguration dễ dàng hơn nhiều, sau đó cố gắng làm cho @Value hoạt động khắp nơi.
granadaCoder

3

Trên thực tế, đối với tôi dưới đây hoạt động tốt.

@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 + "================== ");
   }

}

Bây giờ bất cứ khi nào tôi muốn, chỉ cần gọi

MyBean.prop

nó sẽ trả về giá trị.


2

Câu trả lời này có thể áp dụng hoặc không thể áp dụng cho trường hợp của bạn ... Một khi tôi gặp phải triệu chứng tương tự và tôi đã kiểm tra lại mã của mình nhiều lần và tất cả đều ổn nhưng @Valuecài đặt vẫn không có hiệu lực. Và sau khi làm File > Invalidate Cache / Restartvới IntelliJ(IDE của tôi), vấn đề đã biến mất ...

Cách này rất dễ thử nên có thể rất đáng để thử


1

Sử dụng lớp Môi trường, chúng ta có thể nhận được ứng dụng. Giá trị thuộc tính

@ Không mong muốn,

private Environment env;

và truy cập bằng cách sử dụng

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

0

làm theo các bước sau. 1: - tạo lớp cấu hình của bạn như bên dưới, bạn có thể thấy

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: - khi bạn có một lớp cấu hình thì hãy đưa vào biến từ một cấu hình mà bạn cần.

@Component
public class YourService {

    @Autowired
    private String getsomePro;

    // now you have a value in getsomePro variable automatically.
}

0

Nếu bạn đang làm việc trong một dự án nhiều mô-đun lớn, với nhiều application.propertiestệp khác nhau , thì hãy thử thêm giá trị của bạn vào tệp thuộc tính của dự án mẹ .

Nếu bạn không chắc đâu là dự án mẹ của mình, hãy kiểm tra pom.xmltệp của dự án để tìm <parent>thẻ.

Điều này đã giải quyết vấn đề cho tôi.


0

Bạn có thể sử dụng EnvironmentClass để lấy dữ liệu:

@Autowired
private Environment env;
String prop= env.getProperty('some.prop');
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.