Spring boot @值注释字段返回@Service注释类的null方法

Spring boot @值注释字段返回@Service注释类的null方法,spring-boot,spring-annotations,Spring Boot,Spring Annotations,在Spring Boot 2.2.1.RELEASE的@Service注释类中使用@Value注释访问属性时,我遇到了一个奇怪的问题。该字段正在解析为null,我不确定如何调试它 @Service public class MyService { @Value("${my.username}") private String username; @Value("${my.password}") private String password; priva

在Spring Boot 2.2.1.RELEASE的@Service注释类中使用@Value注释访问属性时,我遇到了一个奇怪的问题。该字段正在解析为null,我不确定如何调试它

@Service
public class MyService {
    @Value("${my.username}")
    private String username;
    @Value("${my.password}")
    private String password;

    private RestTemplate restTemplate = getRestTemplate();


    private RestTemplate getRestTemplate() {
    final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    log.debug("Generating NTCredentials for RestTemplate using user: {} and password: {}", username, password);
    credentialsProvider
        .setCredentials(AuthScope.ANY,
            new NTCredentials(username, password, null, "DOMAIN"));

    HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(credentialsProvider).build();
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
    clientHttpRequestFactory.setHttpClient(client);
    return new RestTemplate(clientHttpRequestFactory);
    }

}
在这段代码中,getRestTemplate()方法中的用户名和密码总是为null。 我已确认属性存在于application.properties文件中

任何帮助都将不胜感激

编辑1:


@Slf4j
@Service
public class MyService {

    @Value("${my.url}")
    private String url;

    private String username;
    private String password;

    private RestTemplate restTemplate  = getRestTemplate();

    public MyService(@Value("${my.username}") String username, @Value("${my.password}") String password) {
    System.out.println(">> Inside Constructor");
    this.username = username;
    this.password = password;
    }

    public String updateDetails(String data) {
    HttpEntity<String> entity = new HttpEntity<>(data);
    ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
    return response.getBody();

    }

    private RestTemplate getRestTemplate() {
    System.out.println(">> Inside RestTemplate Method");
    final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    log.debug("Generating NTCredentials for RestTemplate using user: {} and password: {}", username, password);
    credentialsProvider.setCredentials(AuthScope.ANY, new NTCredentials(username, password, null, "DOMAIN"));

    HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(credentialsProvider).build();
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
    clientHttpRequestFactory.setHttpClient(client);
    return new RestTemplate(clientHttpRequestFactory);
    }

}

如您所见,getRestTemplate()是在调用构造函数之前被调用的。此外,在getRestTemplate()方法中,用户值和密码值都是null。但是,如果我在构造函数中初始化restTemplate,那么一切都可以正常工作

this.restTemplate = getRestTemplate();

我以为构造函数总是先被调用的。有人能解释一下吗?

我认为这与访问restTemplate以实例化私有变量的方式有关。我是这样做的

@Autowire private RestTemplate restTemplate;

@Bean public RestTemplate restTemplate() {
  ...
}

通过这种方式,Spring可以控制何时实例化变量。

我认为这与访问restTemplate以实例化私有变量的方式有关。我是这样做的

@Autowire private RestTemplate restTemplate;

@Bean public RestTemplate restTemplate() {
  ...
}

通过这种方式,Spring可以控制何时实例化变量。

您正在调用
getRestTemplate()同时声明类级别字段,这是在Spring框架对类进行膨胀之前,因此属性还不可用

尝试在类的构造函数中设置值。您可以通过将变量声明更改为:
private restemplate restemplate并添加此构造函数:

public MyService() {
    this.restTemplate = getRestTemplate();
}

您正在调用
getRestTemplate()同时声明类级别字段,这是在Spring框架对类进行膨胀之前,因此属性还不可用

尝试在类的构造函数中设置值。您可以通过将变量声明更改为:
private restemplate restemplate并添加此构造函数:

public MyService() {
    this.restTemplate = getRestTemplate();
}

使用构造函数注入

@Service
public class MyService {

    private String username;
    private String password;

    @Autowired // optional if it is only single constructor
    public MyService(@Value("${my.username}") String username, @Value("${my.password}") String password){
        this.username=username;
        this.password=password;
         ///its already here
    }
通过这种方式,您可以保证在对象构造中必须提供和可用的值,因此稍后您将调用该类的任何方法


如果未提供值或SpEL无效,应用程序将无法启动。

使用构造函数注入

@Service
public class MyService {

    private String username;
    private String password;

    @Autowired // optional if it is only single constructor
    public MyService(@Value("${my.username}") String username, @Value("${my.password}") String password){
        this.username=username;
        this.password=password;
         ///its already here
    }
通过这种方式,您可以保证在对象构造中必须提供和可用的值,因此稍后您将调用该类的任何方法


如果未提供值或SpEL无效,应用程序将无法启动。

完全膨胀MyService类以及任何其他bean,这都是错误的。我尝试了此操作,但用户名和密码字段仍然为空。@noobCoder属性是否成功拉入任何其他类?您是否验证了属性文件位于src/main/resources中?@NickJordan是的,其他类工作正常。事实上,在同一个类中,我有另一个方法,它使用@Value注释的方法,工作正常。@noobCoder好的,明白了,因此,如果在同一个类中有另一个使用@Value的方法,我将假设该方法不会作为类级变量实例化的一部分被调用,而是在类全部膨胀后在正常处理中被调用。问题是,当类膨胀时,这些属性的值在Spring的ApplicationContext中还不可用。你可以使用构造函数注入来回答这个问题,就像你在上面一个答案的评论中提到的那样,或者你可以…完全膨胀MyService类以及任何其他简单错误的bean,用户名和密码字段为空。@noobCoder属性是否成功拉入任何其他类?您是否验证了属性文件位于src/main/resources中?@NickJordan是的,其他类工作正常。事实上,在同一个类中,我有另一个方法,它使用@Value注释的方法,工作正常。@noobCoder好的,明白了,因此,如果在同一个类中有另一个使用@Value的方法,我将假设该方法不会作为类级变量实例化的一部分被调用,而是在类全部膨胀后在正常处理中被调用。问题是,当类膨胀时,这些属性的值在Spring的ApplicationContext中还不可用。你可以使用构造函数注入来回答这个问题,就像你在上述答案之一的评论中提到的那样,或者你可以…使用构造函数注入,你会没事的。使用构造函数注入,你会没事的。谢谢!我尝试按照您的建议使用构造函数注入,但问题仍然存在。然而,我能够通过结合您和@Nick Jordan的解决方案得到这些值。我使用了构造函数注入,然后从构造函数中调用getRestTemplate()方法。另外,在我上面发布的代码片段中,我添加了一个带有print语句的构造函数,并向getRestTemplate()方法添加了一个print语句。我看到getRestTemplate()方法在构造函数之前执行。我以为会先调用构造函数。你能帮我理解吗?我没有看到相关代码。是的,构造器的性质永远是第一位的。谢谢!我尝试按照您的建议使用构造函数注入,但问题仍然存在。然而,我能够通过结合您和@Nick Jordan的解决方案得到这些值。我使用了构造函数注入,然后从构造函数中调用getRestTemplate()方法。另外,在我上面发布的代码片段中,我添加了一个带有print语句的构造函数,并向getRestTemplate()方法添加了一个print语句。