Spring使用@Autowired注解静态实例对象方式

 更新时间:2021年8月26日 16:00  点击:1509

Spring @Autowired注解静态实例对象

问题

最近项目小组在重新规划工程的业务缓存,其中涉及到部分代码重构,过程中发现有些工具类中的静态方法需要依赖别的对象实例(该实例已配置在xml成Spring bean,非静态可以用@Autowired加载正常使用),而我们知道,类加载后静态成员是在内存的共享区,静态方法里面的变量必然要使用静态成员变量,这就有了如下代码:

@Component
public class TestClass {
    @Autowired
    private static AutowiredTypeComponent component;
    // 调用静态组件的方法
    public static void testMethod() {
        component.callTestMethod();
    }
}

编译正常,但运行时报java.lang.NullPointerException: null异常,显然在调用testMethod()方法时,component变量还没被初始化,报NPE。

原因

所以,在Springframework里,我们是不能@Autowired一个静态变量,使之成为一个Spring bean的。为什么?其实很简单,因为当类加载器加载静态变量时,Spring上下文尚未加载。所以类加载器不会在bean中正确注入静态类,并且会失败。

解决方案

方式一

将@Autowired 注解到类的构造函数上。很好理解,Spring扫描到AutowiredTypeComponent的bean,然后赋给静态变量component。示例如下:

@Component
public class TestClass {
    private static AutowiredTypeComponent component;
    @Autowired
    public TestClass(AutowiredTypeComponent component) {
        TestClass.component = component;
    }
    // 调用静态组件的方法
    public static void testMethod() {
        component.callTestMethod();
    }
}

方式二

给静态组件加setter方法,并在这个方法上加上@Autowired。Spring能扫描到AutowiredTypeComponent的bean,然后通过setter方法注入。示例如下:

@Component
public class TestClass {
    private static AutowiredTypeComponent component;
    @Autowired
    public void setComponent(AutowiredTypeComponent component){
        TestClass.component = component;
    }
    // 调用静态组件的方法
    public static void testMethod() {
        component.callTestMethod();
    }
}

方式三

定义一个静态组件,定义一个非静态组件并加上@Autowired注解,再定义一个初始化组件的方法并加上@PostConstruct注解。这个注解是JavaEE引入的,作用于servlet生命周期的注解,你只需要知道,用它注解的方法在构造函数之后就会被调用。示例如下:

@Component
public class TestClass {
   private static AutowiredTypeComponent component;
   @Autowired
   private AutowiredTypeComponent autowiredComponent;
   @PostConstruct
   private void beforeInit() {
      component = this.autowiredComponent;
   }
   // 调用静态组件的方法
   public static void testMethod() {
      component.callTestMethod();
   }
}

方式四

直接用Spring框架工具类获取bean,定义成局部变量使用。但有弊端:如果该类中有多个静态方法多次用到这个组件则每次都要这样获取,个人不推荐这种方式。示例如下:

public class TestClass {
    // 调用静态组件的方法
   public static void testMethod() {
      AutowiredTypeComponent component = SpringApplicationContextUtil.getBean("component");
      component.callTestMethod();
   }
}

总结

在上面的代码示例中,我每个类都加了@Component注解,其实可以根据需要进行变更,比如这个类是处理业务逻辑,可以换成@Service;这个类是处理请求进行转发或重定向的,可以换成@Controller(是Spring-mvc的注解);这个类是专门用来操作Dao的就@Repository。

Spring的注解帮你做了一件很有意义的事:就是它们对应用进行了分层,这样就能将请求处理、业务逻辑处理、数据库操作处理分离出来,为代码解耦,也方便了项目的开发和维护。

Spring容器bean加载机制用到了Java的反射,这里先不作赘述,以后会专门写一篇文章来总结Java反射在Spring的IoC和AoP中的应用。

@Autowired注解和静态方法

一、业务场景

spring框架应用中有些静态方法需要依赖被容器管理的类,就像这样:

@Component
public class Test {    
    @Autowired
    private static UserService userService;    
    public static void test() {
        userService.test();
    }
}

这样一定会报java.lang.NullPointerException: null异常。

二、原理剖析

静态变量、类变量不是对象的属性,而是一个类的属性,所以静态方法是属于类(class)的,普通方法才是属于实体对象(也就是New出来的对象)的,spring注入是在容器中实例化对象,所以不能使用静态方法。

而使用静态变量、类变量扩大了静态方法的使用范围。静态方法在spring是不推荐使用的,依赖注入的主要目的,是让容器去产生一个对象的实例,然后在整个生命周期中使用他们,同时也让testing工作更加容易。

一旦你使用静态方法,就不再需要去产生这个类的实例,这会让testing变得更加困难,同时你也不能为一个给定的类,依靠注入方式去产生多个具有不同的依赖环境的实例,这种static field是隐含共享的,并且是一种global全局状态,spring同样不推荐这样去做。

三、解决方法

1、将@Autowire加到构造方法上

@Component
public class Test {    
    private static UserService userService;    
    @Autowired
    public Test(UserService userService) {
        Test.userService = userService;
    }
}

2、用@PostConstruct注解

@Component
public class Test {    
    private static UserService userService;    
    @Autowired
    private UserService userService2;    
    @PostConstruct
    public void beforeInit() {
        userService = userService2;
    }    
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • Spring AOP 对象内部方法间的嵌套调用方式

    这篇文章主要介绍了Spring AOP 对象内部方法间的嵌套调用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-08-29
  • Spring Cloud 中@FeignClient注解中的contextId属性详解

    这篇文章主要介绍了Spring Cloud 中@FeignClient注解中的contextId属性详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-25
  • Springboot如何实现Web系统License授权认证

    这篇文章主要介绍了Springboot如何实现Web系统License授权认证,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-05-28
  • Swagger中@ApiIgnore注解的使用详解

    这篇文章主要介绍了Swagger中@ApiIgnore注解的使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-21
  • 校验非空的注解@NotNull如何取得自定义的message

    这篇文章主要介绍了校验非空的注解@NotNull如何取得自定义的message,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-29
  • 如何在Spring WebFlux的任何地方获取Request对象

    这篇文章主要介绍了如何在Spring WebFlux的任何地方获取Request对象,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下...2021-01-26
  • 详解SpringCloudGateway内存泄漏问题

    这篇文章主要介绍了详解SpringCloudGateway内存泄漏问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-07-16
  • Spring为什么不推荐使用@Autowired注解详析

    @Autowired 注解的主要功能就是完成自动注入,使用也非常简单,但这篇文章主要给大家介绍了关于Spring为什么不推荐使用@Autowired注解的相关资料,需要的朋友可以参考下...2021-11-03
  • Springboot如何使用mybatis实现拦截SQL分页

    这篇文章主要介绍了Springboot使用mybatis实现拦截SQL分页,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-19
  • Java中lombok的@Builder注解的解析与简单使用详解

    这篇文章主要介绍了Java中lombok的@Builder注解的解析与简单使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-06
  • 处理@PathVariable注解允许参数为空、允许不传参数的问题

    这篇文章主要介绍了处理@PathVariable注解允许参数为空、允许不传参数的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-23
  • SpringMVC文件上传原理及实现过程解析

    这篇文章主要介绍了SpringMVC文件上传原理及实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-07-15
  • Mybatis用注解写in查询的实现

    这篇文章主要介绍了Mybatis用注解写in查询的实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-13
  • Spring Data JPA 关键字Exists的用法说明

    这篇文章主要介绍了Spring Data JPA 关键字Exists的用法说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-10
  • 解决@Transactional注解事务不回滚不起作用的问题

    这篇文章主要介绍了解决@Transactional注解事务不回滚不起作用的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-23
  • tomcat启动完成执行 某个方法 定时任务(Spring)操作

    这篇文章主要介绍了tomcat启动完成执行 某个方法 定时任务(Spring)操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-25
  • 使用Maven 搭建 Spring MVC 本地部署Tomcat的详细教程

    这篇文章主要介绍了使用Maven 搭建 Spring MVC 本地部署Tomcat,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-08-16
  • Java Spring Cloud 负载均衡详解

    这篇文章主要介绍了Spring Cloud负载均衡及远程调用实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2021-09-18
  • SpringMvc自动装箱及GET请求参数原理解析

    这篇文章主要介绍了SpringMvc自动装箱及GET请求参数原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-19
  • Springboot使用thymeleaf动态模板实现刷新

    这篇文章主要介绍了Springboot使用thymeleaf动态模板实现刷新,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-08-31