gpt4 book ai didi

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

转载 作者:qq735679552 更新时间:2022-09-27 22:32:09 26 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章Spring使用@Autowired注解静态实例对象方式由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

Spring @Autowired注解静态实例对象

问题

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

?
1
2
3
4
5
6
7
8
9
@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。示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
@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方法注入。示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
@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生命周期的注解,你只需要知道,用它注解的方法在构造函数之后就会被调用。示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@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,定义成局部变量使用。但有弊端:如果该类中有多个静态方法多次用到这个组件则每次都要这样获取,个人不推荐这种方式。示例如下:

?
1
2
3
4
5
6
7
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注解和静态方法

1、业务场景

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

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

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

2、原理剖析

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

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

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

3、解决方法

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

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

2、用@PostConstruct注解

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

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

原文链接:https://blog.csdn.net/RogueFist/article/details/79575665 。

最后此篇关于Spring使用@Autowired注解静态实例对象方式的文章就讲到这里了,如果你想了解更多关于Spring使用@Autowired注解静态实例对象方式的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com