优雅地在工具类中使用@Autowired注解
大家好,我是欧阳方超,可以扫描下方二维码关注我的公众号“欧阳方超”,后续内容将在公众号首发。

1、概述
在Spring Boot中,使用@Autowired注解来注入Bean是一个常见的做法。然而,当我们需要在工具类中使用静态方法时,直接使用@Autowired注解会遇到一些挑战。本文将详细探讨如何在工具类中优雅地使用@Autowired注解注入Bean,并在静态方法中使用这些Bean。
2、理解@Autowired基本用法
@Autowired注解用于自动装配Spring Bean,能够简化依赖管理,通常情况下,我们会在实例变量、构造函数或setter方法上使用此注解。下面是一个简单示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
// 其他业务逻辑
}
3、静态方法与@Autowired的冲突
由于Spring管理的是实例对象,而静态方法术语类本身,因此不能直接在静态上下文中使用@Autowired注解,这意味着如果我们尝试在工具类中直接注入静态变量,将会导致空指针异常。
示例:
@Component
public class FileUtil {
@Autowired
private static MyService myService; // 不推荐
public static void performAction() {
myService.doSomething(); // 可能导致空指针异常
}
}
4、优雅解决方案
4.1、使用@PostConstruct
可以使用@PostConstruct注解来初始化静态变量,确保bean被创建并完成依赖注入后进行赋值,下面以在工具类中注入RestTemplate为例进行说明,代码如下:
package com.xxx;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xxx.lawknowledge.common.util.dateutil.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
@Component
public class RequestUtils {
@Autowired
private RestTemplate restTemplate;//非静态变量
private static RestTemplate realRestTemplate;
@PostConstruct
public void init() {
realRestTemplate = restTemplate;//在初始化方法中赋值
}
/**
* 发送请求,通过xx能力中心调用用户中心接口
* @param url
* @param httpHeaders
* @param requestBody
* @return
*/
public static String sendRequest(String url, HttpHeaders httpHeaders, JSONObject requestBody) {
// 调用接口
/*String url = "http://203.48.0.235:9091/yhzx_yh/LoginService/getSfByToken?tokenStr=" + tokenStr;
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
String appCode = "xxx";//授权应用CODE
String appKey = "sss";//授权应用KEY
String appSecret = "sff"; //授权应用SECRET
httpHeaders.set("ag-key", appKey);
httpHeaders.set("ag-secret", appSecret);
httpHeaders.set("ag-app-id", appCode);
httpHeaders.set("ag-timestamp", DateUtils.getCurrentDateTimeString());
JSONObject jsonObject = new JSONObject();
jsonObject.put("tokenStr", tokenStr);*/
HttpEntity<String> stringHttpEntity = new HttpEntity<>(JSON.toJSONString(requestBody), httpHeaders);
String responseStr = realRestTemplate.postForObject(url, stringHttpEntity, String.class);
return responseStr;
}
}
解释
使用@Component注解把当前工具类声明为Spring的组件;定义一个非静态restTemplate变量,并使用@Autowired注入;在init()方法中,使用@PostConstruct注解将非静态的restTemplate赋值给静态变量realRestTemplate,@PostConstruct注解是Java EE规范中的一部分,用于标记一个方法,该方法将在依赖注入完成后被自动调用。
具体执行过程是这样的,Spring首先创建RequestUtils对象,调用其构造函数;接着Spring将RestTemplate的实例注入到非静态变量restTemplate中;然后Spring调用init()方法,此时可以安全地将非静态变量restTemplate赋值给静态变量realRestTemplate,这样在静态方法中就可以使用realRestTemplate了。
注意事项
@PostConstruct标记的方法必须是非静态的,并且不能有参数,返回类型必须为void。
每个Bean只能有一个被标记为@PostConstruct的方法。
4.2、使用构造器注入
如果可能,尽量避免使用静态方法,改用实例方法和构造器注入。这种方式符合Spring的依赖注入原则:
package com.xxx;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xxx.lawknowledge.common.util.dateutil.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
@Component
public class RequestUtils {
private RestTemplate restTemplate;
@Autowired
public RequestUtils(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
/**
* 发送请求,通过xx能力中心调用用户中心接口
* @param url
* @param httpHeaders
* @param requestBody
* @return
*/
public String sendRequest(String url, HttpHeaders httpHeaders, JSONObject requestBody) {
// 调用接口
/*String url = "http://203.48.0.235:9091/yhzx_yh/LoginService/getSfByToken?tokenStr=" + tokenStr;
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
String appCode = "xxx";//授权应用CODE
String appKey = "sss";//授权应用KEY
String appSecret = "sff"; //授权应用SECRET
httpHeaders.set("ag-key", appKey);
httpHeaders.set("ag-secret", appSecret);
httpHeaders.set("ag-app-id", appCode);
httpHeaders.set("ag-timestamp", DateUtils.getCurrentDateTimeString());
JSONObject jsonObject = new JSONObject();
jsonObject.put("tokenStr", tokenStr);*/
HttpEntity<String> stringHttpEntity = new HttpEntity<>(JSON.toJSONString(requestBody), httpHeaders);
String responseStr = realRestTemplate.postForObject(url, stringHttpEntity, String.class);
return responseStr;
}
}
5、总结
在Spring Boot中,尽量避免在工具类中使用静态方法。如果需要使用,可以通过@PostConstruct来初始化静态变量,或者考虑使用构造器注入和实例方法来保持代码的清晰和可维护性。这些做法不仅符合Spring的设计理念,还能提高代码的可测试性和灵活性。通过理解和合理运用@PostConstruct,可以有效地管理Spring Bean的初始化过程,从而提高应用程序的稳定性和可维护性。
我是欧阳方超,把事情做好了自然就有兴趣了,如果你喜欢我的文章,欢迎点赞、转发、评论加关注。我们下次见。