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

目录
  • Spring @Autowired注解静态实例对象
    • 问题
    • 原因
    • 解决方案
      • 方式一
      • 方式二
      • 方式三
      • 方式四
      • 总结
  • @Autowired注解和静态方法
    • 一、业务场景
    • 二、原理剖析
    • 三、解决方法
      • 1、将@Autowire加到构造方法上
      • 2、用@PostConstruct注解

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

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

(0)

相关推荐

  • 关于Spring的@Autowired依赖注入常见错误的总结

    做不到雨露均沾 经常会遇到,required a single bean, but 2 were found. 根据ID移除学生 DataService是个接口,其实现依赖Oracle: 现在期望把部分非核心业务从Oracle迁移到Cassandra,自然会先添加上一个新的DataService实现: @Repository @Slf4j public class CassandraDataService implements DataService{ @Override public void

  • 浅谈SpringBoot @Autowired的两种注入方式

    Autowired有两种注入方式 by type by name 默认使用的是byType的方式向Bean里面注入相应的Bean.例如: @Autowired private UserService userService; 这段代码会在初始化的时候,在spring容器中寻找一个类型为UserService的bean实体注入,关联到userService的引入上. 但是如果UserService这个接口存在多个实现类的时候,就会在spring注入的时候报错,例如: public class Us

  • 详解Spring bean的注解注入之@Autowired的原理及使用

    一.@Autowired 概念: @Autowired 注释,它可以对类成员变量.方法及构造函数进行标注,完成自动装配的工作. 通过 @Autowired的使用来消除 set ,get方法. 在使用@Autowired之前,我们对一个bean配置起属性时,用的是 <property name="属性名" value=" 属性值"/> 使用@Autowired之后,我们只需要在需要使用的地方使用一个@Autowired 就可以了. 代码使用: public

  • Java Spring @Autowired的这些骚操作,你都知道吗

    目录 前言 1. @Autowired的默认装配 2. 相同类型的对象不只一个时 3. @Qualifier和@Primary 4. @Autowired的使用范围 4.1 成员变量 4.2 构造器 4.3 方法 4.4 参数 4.5 注解 5. @Autowired的高端玩法 6. @Autowired一定能装配成功? 6.1 没有加@Service注解 6.2 注入Filter或Listener 6.3 注解未被@ComponentScan扫描 6.4 循环依赖问题 7. @Autowire

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

    目录 Spring @Autowired注解静态实例对象 问题 原因 解决方案 方式一 方式二 方式三 方式四 总结 @Autowired注解和静态方法 一.业务场景 二.原理剖析 三.解决方法 1.将@Autowire加到构造方法上 2.用@PostConstruct注解 Spring @Autowired注解静态实例对象 问题 最近项目小组在重新规划工程的业务缓存,其中涉及到部分代码重构,过程中发现有些工具类中的静态方法需要依赖别的对象实例(该实例已配置在xml成Spring bean,非静

  • Spring使用@Autowired注解实现自动装配方式

    目录 Spring支持注解配置 引入注解依赖 启用注解 使用@Autowired注解实现自动装配 1.IOC容器配置 2.实体类使用@Autowired注解注入属性 3.测试结果 @Autowired注解的使用和注入规则 1.使用在变量域上面 2.@Autowired注解使用在构造器上面 Spring支持注解配置 引入注解依赖 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="ht

  • 一文详解Spring的Enablexxx注解使用实例

    目录 引言 @Enable 注解 @Import 注解 为什么要使用 @Import 注解呢 总结 引言 layout: post categories: Java title: 一文带你了解 Spring 的@Enablexxx 注解 tagline: by 子悠 tags: - 子悠 前面的文章给大家介绍 Spring 的重试机制的时候有提到过 Spring 有很多 @Enable 开头的注解,平时在使用的时候也没有注意过为什么会有这些注解,今天就给大家介绍一下. @Enable 注解 首先

  • Spring Data JPA 映射VO/DTO对象方式

    目录 Spring Data JPA 映射VO/DTO对象 HQL方式 原生SQL的形式 Spring Data Jpa 自定义repository转DTO Spring Data JPA 映射VO/DTO对象 在项目开发中,时常需要根据业务需求来映射VO/DTO对象(这两个概念理解感觉很模糊- .- ),本文将简单介绍以Spring Data JPA的方式处理实体类映射 HQL方式 public interface MusicTypeRepository extends JpaReposito

  • Spring为什么不推荐使用@Autowired注解详析

    目录 引言 Spring的三种注入方式 属性(filed)注入 构造器注入 set方法注入 属性注入可能出现的问题 问题一 问题二 问题三 spring建议 使用@Resource代替@Autowired 使用@RequiredArgsConstructor构造器方式注入 总结 引言 使用IDEA开发时,同组小伙伴都喜欢用@Autowired注入,代码一片warning,看着很不舒服,@Autowired作为Spring的亲儿子,为啥在IDEA中提示了一个警告:Field injection i

  • 为什么Spring和IDEA都不推荐使用 @Autowired 注解

    目录 前言 Spring为什么不推荐使用@Autowired 注解 背景 原因 解决 思考 @Autowired, @Qualifier, @Resource, 三者有何区别 参考文档 前言 请看下面几个问题 Spring为什么不推荐使用@Autowired 注解? 为什么推荐使用@Resource 代替 @Autowired 注解? 如何快速使用构造注入代替 @Autowired ? @Autowired, @Qualifier, @Resource, 三者有何区别? 下面, 我们带着以上问题

  • 理解Java注解及Spring的@Autowired是如何实现的

    首先我们可以自己写一个注解: @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AnnoSample { String value(); } 注解使用 @interface来标识.这个注解定义了一个属性value,只能作用于方法上,生命周期是运行时. @Target用于指定可以放置注解的位置,这里指定的METHOD说明该注解只能放置到方法上面,还可以指定TYPE(类.接口.枚举类),

  • 使用@Autowired注解有错误提示的解决

    目录 使用@Autowired注解有错误提示 处理方式 @Resource注解与@Autowired注解的异同点 Spring的@Autowired注解报错改为警告 使用@Autowired注解有错误提示 使用Spring boot +mybatis框架时,在service实现类中使用Mapper类,给Mapper类添加@Autowired注解时发现 有错误提示:could not autowire,no beans of "XXX" type found 但程序的编译和运行都正常.

  • spring AOP自定义注解方式实现日志管理的实例讲解

    今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在applicationContext-mvc.xml中要添加的 <mvc:annotation-driven /> <!-- 激活组件扫描功能,在包com.gcx及其子包下面自动扫描通过注解配置的组件 --> <context:component-scan base-package=&qu

随机推荐