我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

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;
    }    
}

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

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Spring使用注解方式实现创建对象

这篇文章主要介绍了Spring使用注解方式实现创建对象,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
2023-02-06

Java spring 通过注解方式创建对象的示例详解

这篇文章主要介绍了java spring 通过注解方式创建对象,本文结合示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-02-08

Spring Boot中单例类实现对象的注入方式是什么

本篇内容介绍了“Spring Boot中单例类实现对象的注入方式是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Spring Boot
2023-06-20

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录