gpt4 book ai didi

Spring对静态变量无法注入的解决方案

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

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

这篇CFSDN的博客文章Spring对静态变量无法注入的解决方案由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

Spring对静态变量无法注入

问题

今天在学习的过程中想写一个连接和线程绑定的JDBCUtils工具类,但测试时发现一直报空指针异常,上网查了之后Spring并不支持对静态成员变量注入,所以光试用@Autowired肯定是不行的.

可是我们编写工具类时肯定是要使用静态变量和方法的,我总结一下我用过可以实现对静态成员变量注入的方法.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Component
public class JDBCUtils {
     @Autowired
     private static ComboPooledDataSource dataSource;
     private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
     public static Connection getThreadConnection(){
         Connection conn = tl.get();
         if (conn == null ){
             conn = getConnection();
             tl.set(conn);
         }
         return conn;
     }
     public static DataSource getDataSource(){
         return dataSource;
     }
     public static Connection getConnection(){
         Connection connection = null ;
         try {
             connection = dataSource.getConnection();
         } catch (SQLException e) {
             e.printStackTrace();
         }
         return connection;
     }
     public static void removeThreadConnection(){
         tl.remove();
     }
}

set方法注入

注解方式

在类前加@Component注解,在set方法上加 @Autowired注解,这里注意两点 。

1.配置文件里已经配置了变量的相关参数 。

2.静态变量自动生成set方法时会有static修饰,要去掉,否则还是无法注入 。

?
1
2
3
4
5
6
7
@Component
public class JDBCUtils {
     private static ComboPooledDataSource dataSource;
     @Autowired
     public void setDataSource(ComboPooledDataSource dataSource) {
         JDBCUtils.dataSource = dataSource;
     }

xml方式

同样注意将set方法上的static去掉 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class JDBCUtils {
     private static   ComboPooledDataSource dataSource;
     public void setDataSource(ComboPooledDataSource dataSource) {
         this .dataSource = dataSource;
     }
     private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
     public static Connection getThreadConnection(){
         Connection conn = tl.get();
         if (conn == null ){
             conn = getConnection();
             tl.set(conn);
         }
         return conn;
     }
     public static DataSource getDataSource(){
         return dataSource;
     }
     public static Connection getConnection(){
         Connection connection = null ;
         try {
             connection = dataSource.getConnection();
         } catch (SQLException e) {
             e.printStackTrace();
         }
         return connection;
     }
     public static void removeThreadConnection(){
         tl.remove();
     }
}
?
1
2
3
< bean id = "JDBCUtils" class = "com.cc.utils.JDBCUtils" >
      < property name = "dataSource" ref = "dataSource" ></ property >
  </ bean >

@PostConstruct注解方式注入

用@PostConstruct加在init方法上,在类初始化后执行该方法,对成员变量赋值。在这之前,我们要改造一下工具类,去掉我们想注入变量的static的修饰符,这样我们就可以用@Autowired实现对其注入.

然后加一个静态的类自身的引用对象,当我们想要变量时通过这个引用对象来获取.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Component
public class JDBCUtils {
     @Autowired
     private  ComboPooledDataSource dataSource;
     private static JDBCUtils jdbcUtils;
     @PostConstruct
     public void init(){
         jdbcUtils = this ;
         this .dataSource = dataSource;
     }
     private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
     public static Connection getThreadConnection(){
         Connection conn = tl.get();
         if (conn == null ){
             conn = getConnection();
             tl.set(conn);
         }
         return conn;
     }
     public static DataSource getDataSource(){
         return jdbcUtils.dataSource;
     }
     public static Connection getConnection(){
         Connection connection = null ;
         try {
             connection = jdbcUtils.dataSource.getConnection();
         } catch (SQLException e) {
             e.printStackTrace();
         }
         return connection;
     }
     public static void removeThreadConnection(){
         tl.remove();
     }
}

当然这种用初始化方法也可以用xml配置,原理一样.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class JDBCUtils {
     private  ComboPooledDataSource dataSource;
     public void setDataSource(ComboPooledDataSource dataSource) {
         this .dataSource = dataSource;
     }
     private static JDBCUtils jdbcUtils;
     public void init(){
         jdbcUtils = this ;
         this .dataSource = dataSource;
     }
     private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
     public static Connection getThreadConnection(){
         Connection conn = tl.get();
         if (conn == null ){
             conn = getConnection();
             tl.set(conn);
         }
         return conn;
     }
     public static DataSource getDataSource(){
         return jdbcUtils.dataSource;
     }
     public static Connection getConnection(){
         Connection connection = null ;
         try {
             connection = jdbcUtils.dataSource.getConnection();
         } catch (SQLException e) {
             e.printStackTrace();
         }
         return connection;
     }
     public static void removeThreadConnection(){
         tl.remove();
     }
}
?
1
2
3
< bean id = "JDBCUtils" class = "com.cc.utils.JDBCUtils" init-method = "init" >
         < property name = "dataSource" ref = "dataSource" ></ property >
     </ bean >

静态方法注入bean失败原因

今天在写redission 的一个工具类的时候,随手写出下面的代码 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.wt.redission.wtredission.utils; 
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class RedissionUtilserror {
     @Autowired
    private static RedissonClient redissonClient;
 
     public static RLock getRLock(String objectName) {
         RLock rLock =redissonClient.getLock(objectName);
         return rLock;
     }
 
     //根据名字获取map
     public static  <K, V> RMap<K, V> getRMap(String objectName) {
         RMap<K, V> map = redissonClient.getMap(objectName);
         return map;
     }
 
     //根据名字和值设置map
     public static void setMap(String objectName,Object key,Object value){
         RMap<Object, Object> map =redissonClient.getMap(objectName);
         map.put(key,value);
     }
 
     //根据名字获取set
     public static <V> RSet<V> getSet(String objectName) {
         RSet<V> set = redissonClient.getSet(objectName);
         return set;
     }
 
     //根据名字和值设置set
     public static void setSet(String objectName,Object value){
         RSet<Object> set = redissonClient.getSet(objectName);
         set.add(value);
     }
 
     //根据名字获取list
     public static  <V> RList<V> getRList(String objectName) {
         RList<V> rList = redissonClient.getList(objectName);
         return rList;
     }
 
     //根据名字和值设置list
     public static void setList(String objectName, int  index,Object element ){
         RList<Object> objectRList = redissonClient.getList(objectName);
         objectRList.set(index,element);
     }
 
     //根据名字获取bucket
     public static <T> RBucket<T> getRBucket(String objectName) {
         RBucket<T> bucket = redissonClient.getBucket(objectName);
         return bucket;
     }
 
     //根据名字和值 设置对应的bucket
     public static  <T> T setBucket(String objectName,String value){
         RBucket<Object> bucket = redissonClient.getBucket(objectName);
         bucket.set(value);
         T t= (T) bucket.get(); //值类型由返回值确定
         return  t;
     }
}

乍一看好像没问题 我写一个静态方法 然后在方法中使用静态变量redissonClient ,哇....,一切看得如此正常 。

当我开始测试时,NPE.............,我去这是怎么回事,自己在想这不科学啊,怎么会空指针,于是我开始找原因 。

最后发现是基础不牢啊............,对jvm的类加载机制几乎就没考虑,简要说要错误的原因 。

jvm在进行类加载的时候,首先会加载类变量,类方法,也就是我这里被static修饰的方法,然后当我调用静态方法进行使用的时候,会使用到redissionClient,注意这个redissionClient是通过autowired进来的,关键问题就在这里,autowired的底层是通过构造器和set方法注入bean的 。

redissionClient被static修饰 并且还是一个接口 在被调用的时候肯定没有实例化 。

下面提供三种方式正确使用 。

方式一

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.wt.redission.wtredission.utils; 
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class RedissionUtils {
     private static RedissonClient redissonClient;
     @Autowired
     public  RedissionUtils(RedissonClient redissonClient){
         RedissionUtils.redissonClient=redissonClient;
    
 
     public static RLock getRLock(String objectName) {
         RLock rLock = redissonClient.getLock(objectName);
         return rLock;
     }
 
     //根据名字获取map
     public static  <K, V> RMap<K, V> getRMap(String objectName) {
         RMap<K, V> map = redissonClient.getMap(objectName);
         return map;
     }
 
     //根据名字和值设置map
     public static void setMap(String objectName,Object key,Object value){
         RMap<Object, Object> map =redissonClient.getMap(objectName);
         map.put(key,value);
     }
 
     //根据名字获取set
     public static <V> RSet<V> getSet(String objectName) {
         RSet<V> set = redissonClient.getSet(objectName);
         return set;
     }
 
     //根据名字和值设置set
     public static void setSet(String objectName,Object value){
         RSet<Object> set = redissonClient.getSet(objectName);
         set.add(value);
     }
 
     //根据名字获取list
     public static  <V> RList<V> getRList(String objectName) {
         RList<V> rList = redissonClient.getList(objectName);
         return rList;
     }
 
     //根据名字和值设置list
     public static void setList(String objectName, int  index,Object element ){
         RList<Object> objectRList = redissonClient.getList(objectName);
         objectRList.set(index,element);
     }
 
     //根据名字获取bucket
     public static <T> RBucket<T> getRBucket(String objectName) {
         RBucket<T> bucket = redissonClient.getBucket(objectName);
         return bucket;
     }
 
     //根据名字和值 设置对应的bucket
     public static  <T> T setBucket(String objectName,String value){
         RBucket<Object> bucket = redissonClient.getBucket(objectName);
         bucket.set(value);
         T t= (T) bucket.get(); //值类型由返回值确定
         return  t;
     }
}

方式二

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.wt.redission.wtredission.utils; 
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class RedissionUtils2 {
 
     @Autowired
     RedissonClient redissonClient;
     public  static RedissionUtils2 redissionUtils;
     @PostConstruct
     public  void  init(){
         redissionUtils= this ;
         redissionUtils.redissonClient= this .redissonClient;
     }
 
     public static RLock getRLock(String objectName) {
         RLock rLock = redissionUtils.redissonClient.getLock(objectName);
         return rLock;
     }
 
     //根据名字获取map
     public static  <K, V> RMap<K, V> getRMap(String objectName) {
         RMap<K, V> map = redissionUtils.redissonClient.getMap(objectName);
         return map;
     }
 
     //根据名字和值设置map
     public static void setMap(String objectName,Object key,Object value){
         RMap<Object, Object> map =redissionUtils.redissonClient.getMap(objectName);
         map.put(key,value);
     }
 
     //根据名字获取set
     public static <V> RSet<V> getSet(String objectName) {
         RSet<V> set = redissionUtils.redissonClient.getSet(objectName);
         return set;
     }
 
     //根据名字和值设置set
     public static void setSet(String objectName,Object value){
         RSet<Object> set = redissionUtils.redissonClient.getSet(objectName);
         set.add(value);
     }
 
     //根据名字获取list
     public static  <V> RList<V> getRList(String objectName) {
         RList<V> rList = redissionUtils.redissonClient.getList(objectName);
         return rList;
     }
 
     //根据名字和值设置list
     public static void setList(String objectName, int  index,Object element ){
         RList<Object> objectRList = redissionUtils.redissonClient.getList(objectName);
         objectRList.set(index,element);
     }
 
     //根据名字获取bucket
     public static <T> RBucket<T> getRBucket(String objectName) {
         RBucket<T> bucket = redissionUtils.redissonClient.getBucket(objectName);
         return bucket;
     }
 
     //根据名字和值 设置对应的bucket
     public static  <T> T setBucket(String objectName,String value){
         RBucket<Object> bucket = redissionUtils.redissonClient.getBucket(objectName);
         bucket.set(value);
         T t= (T) bucket.get(); //值类型由返回值确定
         return  t;
     }
}

方式三 通过spring上下文获取

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package com.wt.redission.wtredission.utils; 
import io.micrometer.core.instrument.util.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
 
/**
  * Spring Context工具类.
  *
  * @author:Hohn
  */
@Component
@Scope ( "singleton" )
public class SpringUtil implements ApplicationContextAware {
 
     /**
      * Spring应用上下文环境.
      */
     private static ApplicationContext applicationContext;
 
     /**
      * 实现ApplicationContextAware接口的回调方法,设置上下文环境
      *
      * <br>
  • spring
  • 静态变量
  • 无法注入
  • 延伸 · 阅读

    • 2021-09-29Spring@Value使用获取配置信息为null的操作
    • 2021-09-29Spring容器中添加bean的5种方式
    • 2021-09-29Spring的@Scheduled 如何动态更新cron表达式
    • 2021-09-29浅谈Spring AOP中args()和argNames的含义
    • 2021-09-28Spring注解@Value及属性加载配置文件方式
    • 2021-09-28SpringBoot使用@Value实现给静态变量注入值
    精彩推荐
    • Java教程spring MVC中传递对象参数示例详解

      spring MVC中传递对象参数示例详解

      这篇文章主要给大家介绍了在spring MVC中传递对象参数的相关资料,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面... 。

      大朋展翅 458 2020-11-19
    • Java教程浅谈java内存管理与内存溢出异常

      浅谈java内存管理与内存溢出异常

      下面小编就为大家带来一篇浅谈java内存管理与内存溢出异常。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧... 。

      Wilange 950 2021-01-21
    • Java教程SpringBoot集成Mybatis过程步骤图解

      SpringBoot集成Mybatis过程步骤图解

      这篇文章主要介绍了SpringBoot集成Mybatis过程步骤图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参... 。

      IT特工 549 2020-07-30
    • Java教程【面试】Spring事务面试考点吐血整理(建议珍藏)

      【面试】Spring事务面试考点吐血整理(建议珍藏)

      本文是小编给大家收藏整理的Spring事务面试考点,非常不错,值得收藏,感兴趣的朋友参考下吧... 。

      李新杰 1176 2021-08-01
    • Java教程java图片缩放实现图片填充整个屏幕

      java图片缩放实现图片填充整个屏幕

      这篇文章主要介绍了java图片缩放实现图片填充整个屏幕,本文提供了两种解决方法,供大家参考,感兴趣的小伙伴们可以看一下... 。

      Alex_MaHao 335 2020-05-01
    • Java教程Java静态方法和实例方法区别详解

      Java静态方法和实例方法区别详解

      这篇文章主要为大家详细介绍了Java静态方法和实例方法的区别,具有一定的参考价值,感兴趣的小伙伴们可以参考一下... 。

      Java开发-搁浅 234 2020-07-17
    • Java教程谈谈Java类型中ParameterizedType,GenericArrayType,TypeVariabl,WildcardType

      谈谈Java类型中ParameterizedType,GenericArrayType,TypeVariabl,WildcardT

      这篇文章主要介绍Java类型中ParameterizedType,GenericArrayType,TypeVariabl,WildcardType的相关资料,需要的朋友可以参考下... 。

      mrr 169 2020-01-10
    • Java教程SpringBoot实现异步事件驱动的方法

      SpringBoot实现异步事件驱动的方法

      本文主要介绍了SpringBoot实现异步事件驱动的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 。

      飘渺Jam 780 2021-09-16

    最后此篇关于Spring对静态变量无法注入的解决方案的文章就讲到这里了,如果你想了解更多关于Spring对静态变量无法注入的解决方案的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

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