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的各种条件下使用方法
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
假设我们有一个Spring Boot应用程序,需要从外部配置文件加载某些属性。我们可以使用@PropertySource注释将外部属性文件加载到Spring Boot应用程序中。 例如,假设我们有一个名为application.properties的属性文件,其中包含以下属性: ``` server.port=8080 database.url=jdbc:mysql://localhost:3306/mydb database.username=root database.password=password ``` 我们可以在Spring Boot应用程序中使用@PropertySource注释来加载这些属性文件,如下所示: ```java @Configuration @PropertySource("classpath:application.properties") public class AppConfig { @Value("${server.port}") private int serverPort; @Value("${database.url}") private String databaseUrl; @Value("${database.username}") private String databaseUsername; @Value("${database.password}") private String databasePassword; // getters and setters } ``` 在这个示例中,我们使用@Configuration注释将类标记为配置类,并使用@PropertySource注释将属性文件加载到Spring Boot应用程序中。我们还使用@Value注释将属性注入到应用程序中的变量中。 现在,我们可以使用这些属性来配置我们的应用程序,如下所示: ```java @SpringBootApplication public class MyApp { public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } @Autowired private AppConfig appConfig; @Bean public TomcatServletWebServerFactory servletContainer() { TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(); tomcat.setPort(appConfig.getServerPort()); return tomcat; } @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl(appConfig.getDatabaseUrl()); dataSource.setUsername(appConfig.getDatabaseUsername()); dataSource.setPassword(appConfig.getDatabasePassword()); return dataSource; } } ``` 在这个示例中,我们使用@Autowired注释将AppConfig类注入到MyApp类中,然后使用属性值来配置Tomcat服务器和数据源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值