Nilai properti aplikasi Spring Boot tidak terisi


97

Saya memiliki aplikasi Spring Boot yang sangat sederhana yang saya coba gunakan dengan beberapa konfigurasi eksternal. Saya telah mencoba untuk mengikuti informasi pada dokumentasi sepatu bot musim semi namun saya menemui hambatan.

Ketika saya menjalankan aplikasi di bawah konfigurasi eksternal di file application.properties tidak diisi ke dalam variabel di dalam kacang. Saya yakin saya melakukan sesuatu yang bodoh, terima kasih atas sarannya.

MyBean.java (terletak di / 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 (terletak di / 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 (terletak di / src / main / resources /)

some.prop=aabbcc

Keluaran log saat menjalankan aplikasi 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
Dan bagaimana cara @Valuemengganti sebelum biji dibuat? Cara Anda "mendeteksi" jika nilainya disetel salah. Pada saat itu selalu nol karena @Valueakan diproses SETELAH konstruksi objek.
M. Deinum

Jawaban:


165

Cara Anda melakukan injeksi properti tidak akan berfungsi, karena injeksi dilakukan setelah konstruktor dipanggil.

Anda perlu melakukan salah satu dari berikut ini:

Solusi yang lebih baik

@Component
public class MyBean {

    private final String prop;

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

Solusi yang akan berfungsi tetapi kurang dapat diuji dan sedikit kurang dapat dibaca

@Component
public class MyBean {

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

    public MyBean() {

    }

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

Perhatikan juga bahwa ini tidak khusus Spring Boot tetapi berlaku untuk aplikasi Spring apa pun


Saya harus menambahkan anotasi @Autowired ke konstruktor untuk membuatnya berfungsi
SĂ©bastien Tromp

1
Terima kasih atas tipnya. Ini seharusnya ada dalam dokumentasi Musim Semi yang membahas tentang anotasi @Value - tetapi orang-orang itu tampaknya tidak tertarik dengan umpan balik tentang dokumentasi mereka :(
Alex Worden

1
Menghemat saya beberapa frsutration. Terima kasih!
Robert Moskal

1
@geoand Bagaimana jika Anda memiliki lebih dari 10 nilai, apakah Anda harus mengetik semua 10 seperti yang Anda lakukan? Atau apakah ada cara yang lebih bersih
Jesse

1
@Jackie Memang ada cara yang lebih bersih! Periksa @ConfigurationPropertiesdan @EnableConfigurationPropertiesanotasi
geoand

5

Pengguna "geoand" benar dalam menunjukkan alasannya di sini dan memberikan solusi. Tetapi pendekatan yang lebih baik adalah merangkum konfigurasi Anda ke dalam kelas yang terpisah, katakanlah kelas java SystemContiguration dan kemudian masukkan kelas ini ke dalam layanan apa pun yang Anda inginkan untuk menggunakan bidang tersebut.

Cara Anda saat ini (@grahamrb) membaca nilai konfigurasi secara langsung ke layanan rawan kesalahan dan akan menyebabkan sakit kepala refactoring jika nama pengaturan config diubah.


Bagaimana tidak ada sakit kepala yang berkurang jika Anda memiliki kelas terpisah untuk properti itu? Anda masih memiliki string yang perlu diingat saat refactoring
dot_Sp0T

4
Hanya ada satu tempat yang perlu Anda "ingat", bukan nomor N. Nilai skalar yang ada di SystemContiguration memberi Anda pengetikan yang kuat. Juga, jika ada logika bisnis yang memiliki "percabangan" ~~~ berdasarkan nilai yang berasal dari konfigurasi ~~~ ..... lebih baik memasukkan sesuatu ke dalam class / businessLogic yang membutuhkan nilai. Aka, jauh lebih mudah untuk memalsukan SystemContiguration kemudian mencoba membuat @Value berfungsi di semua tempat.
granadaCoder

3

Sebenarnya, Bagi saya di bawah ini berfungsi dengan baik.

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

}

Sekarang dimanapun saya mau, panggil saja

MyBean.prop

itu akan mengembalikan nilai.


2

Jawaban ini mungkin atau mungkin tidak berlaku untuk kasus Anda ... Suatu kali saya memiliki gejala yang sama dan saya memeriksa kembali kode saya berkali-kali dan semuanya tampak bagus tetapi @Valuepengaturannya masih tidak berpengaruh. Dan kemudian setelah melakukan File > Invalidate Cache / Restartdengan IntelliJ(IDE saya) saya, masalahnya hilang ...

Ini sangat mudah untuk dicoba sehingga mungkin patut dicoba


1

Menggunakan kelas Lingkungan kita bisa mendapatkan aplikasi. Nilai properti

@Tokopedia,

private Environment env;

dan akses menggunakan

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

0

ikuti langkah ini. 1: - buat kelas konfigurasi Anda seperti di bawah ini, Anda dapat melihat

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: - ketika Anda memiliki kelas konfigurasi, masukkan variabel dari konfigurasi yang Anda perlukan.

@Component
public class YourService {

    @Autowired
    private String getsomePro;

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

0

Jika Anda bekerja dalam proyek multi-modul besar, dengan beberapa application.propertiesfile berbeda , coba tambahkan nilai Anda ke file properti proyek induk .

Jika Anda tidak yakin mana proyek induk Anda, periksa pom.xmlfile proyek Anda , untuk melihat <parent>tag.

Ini memecahkan masalah saya.


0

Anda dapat menggunakan EnvironmentKelas untuk mendapatkan data:

@Autowired
private Environment env;
String prop= env.getProperty('some.prop');
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.