SpringBoot使用@Autowired和@Value方式注入static属性
在日常工作中,我们有时会碰到这样的问题,想提取出工具类来处理某些问题,但工具类中的方法又必须注入某个Service,但我们又不想用注入的方式注入工具类,这时我们就需要解决static属性的注入问题。@value和@Autowired本质都是注入,下面我们就一起来总结一下。
一、场景构建
在这里我们的需求是通过一个TestUtil工具类来校验一下用户名是否合法,用户名合法的标准是是否含有yml中定义的一个字符串。我们要求传入一个id,让工具类通过注入的ServiceImpl拿到用户名进行校验。这里我们给出部分代码。
1.yml
server:
port: 9999
passStr: "00"
2.ServiceImpl.java
@Service
public class ServiceImpl {
/**
* 根据id拿到姓名
* @param id id
* @return java.lang.String
* @author xiepeng
* @date 2021/7/5 13:48
*/
public String getName(String id){
return id+"张三";
}
3.单元测试方法
@Test
void testStaticAutowired(){
System.out.println(TestUtils.checkName("111111"));
System.out.println(TestUtils.checkName("111100"));
}
二、静态依赖注入
1.方法一:set注入法
即@Autowired和@Value不标注在属性上而标注在set方法上,注意,set方法不能是static类型! 且工具类要标注 @Component 注解
@Component
public class TestUtils {
/**
* 用于校验的str
*/
private static String passStr;
private static ServiceImpl service;
@Value("${passStr}")
public void setPassStr(String passStr) {
TestUtils.passStr = passStr;
}
@Autowired
public void setService(ServiceImpl service) {
TestUtils.service = service;
}
/**
* 检查返回的名字中是否含有通过字符串
* @param id id
* @return java.lang.Boolean
* @author xiepeng
* @date 2021/7/5 13:52
*/
public static Boolean checkName(String id){
return service.getName(id).contains(passStr);
}
}
单元测试结果:
2.方法二:使用@PostConstruct注解
被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。PreDestroy()方法在destroy()方法知性之后执行。
详情请参照如下链接
@PostConstruct的详细应用
本方法的本质是通过@PostConstruct注解在容器构建完成之后通过applicationContext拿到实例并注入到staic属性中,这种方式依旧需要工具类要标注 @Component 注解。具体代码如下:
@Component
public class TestUtils {
private static String passStr;
private static ServiceImpl service;
@Autowired
ApplicationContext applicationContext;
@Value("${passStr}")
public void setPassStr(String passStr) {
TestUtils.passStr = passStr;
}
@PostConstruct
public void init(){
System.out.println("准备执行init方法");
TestUtils.service = applicationContext.getBean(ServiceImpl.class);
}
/**
* 检查返回的名字中是否含有通过字符串
* @param id id
* @return java.lang.Boolean
* @author xiepeng
* @date 2021/7/5 13:52
*/
public static Boolean checkName(String id){
return service.getName(id).contains(passStr);
}
单元测试结果如下:
3.方法三:手动实例化
本模块参考YourBatman的博客,十分感谢他的启发,具体链接如下
想用@Autowired注入static静态成员?官方不推荐你却还偏要这么做
在这种方式里不需要在工具类上加上@Component,而是我们手动实例化这个工具类,具体代码如下
- AutowireStaticSmartInitializingSingleton.java
@Component
public class AutowireStaticSmartInitializingSingleton implements SmartInitializingSingleton {
@Autowired
private AutowireCapableBeanFactory beanFactory;
/**
* 当所有的单例Bena初始化完成后,对static静态成员进行赋值
*/
@Override
public void afterSingletonsInstantiated() {
// 因为是给static静态属性赋值,因此这里new一个实例做注入是可行的
beanFactory.autowireBean(new TestUtils());
}
}
- TestUtils.java
public class TestUtils {
private static String passStr;
private static ServiceImpl service;
@Autowired
public void setService(ServiceImpl service) {
TestUtils.service = service;
}
@Value("${passStr}")
public void setPassStr(String passStr) {
TestUtils.passStr = passStr;
}
/**
* 检查返回的名字中是否含有通过字符串
* @param id id
* @return java.lang.Boolean
* @author xiepeng
* @date 2021/7/5 13:52
*/
public static Boolean checkName(String id){
return service.getName(id).contains(passStr);
}
}
单元测试结果:
四、总结
- @Autowired和@Value方式注入static属性本质上差不多,本文总结了@Autowired三种方法,但官方并不建议我们这么做,因为他打破了优先级关系、生命周期关系,如果有多个实例还会出现问题。
- 这里在放上一个在静态块中@Value注入的链接以供参考。
SpringBoot 注解@Value的各种条件下使用方法