经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
Spring使用@Autowired注解静态实例对象方式
来源:jb51  时间:2021/8/26 17:21:19  对本文有异议

Spring @Autowired注解静态实例对象

问题

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

  1. @Component
  2. public class TestClass {
  3. @Autowired
  4. private static AutowiredTypeComponent component;
  5. // 调用静态组件的方法
  6. public static void testMethod() {
  7. component.callTestMethod();
  8. }
  9. }

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

原因

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

解决方案

方式一

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

  1. @Component
  2. public class TestClass {
  3. private static AutowiredTypeComponent component;
  4. @Autowired
  5. public TestClass(AutowiredTypeComponent component) {
  6. TestClass.component = component;
  7. }
  8. // 调用静态组件的方法
  9. public static void testMethod() {
  10. component.callTestMethod();
  11. }
  12. }

方式二

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

  1. @Component
  2. public class TestClass {
  3. private static AutowiredTypeComponent component;
  4. @Autowired
  5. public void setComponent(AutowiredTypeComponent component){
  6. TestClass.component = component;
  7. }
  8. // 调用静态组件的方法
  9. public static void testMethod() {
  10. component.callTestMethod();
  11. }
  12. }

方式三

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

  1. @Component
  2. public class TestClass {
  3. private static AutowiredTypeComponent component;
  4. @Autowired
  5. private AutowiredTypeComponent autowiredComponent;
  6. @PostConstruct
  7. private void beforeInit() {
  8. component = this.autowiredComponent;
  9. }
  10. // 调用静态组件的方法
  11. public static void testMethod() {
  12. component.callTestMethod();
  13. }
  14. }

方式四

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

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

总结

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

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

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

@Autowired注解和静态方法

一、业务场景

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

  1. @Component
  2. public class Test {
  3. @Autowired
  4. private static UserService userService;
  5. public static void test() {
  6. userService.test();
  7. }
  8. }

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

二、原理剖析

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

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

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

三、解决方法

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

  1. @Component
  2. public class Test {
  3. private static UserService userService;
  4. @Autowired
  5. public Test(UserService userService) {
  6. Test.userService = userService;
  7. }
  8. }

2、用@PostConstruct注解

  1. @Component
  2. public class Test {
  3. private static UserService userService;
  4. @Autowired
  5. private UserService userService2;
  6. @PostConstruct
  7. public void beforeInit() {
  8. userService = userService2;
  9. }
  10. }

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

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号