SoFunction
Updated on 2025-03-08

Spring's solution to inject static variables

Spring cannot inject static variables

question

Today, during the learning process, I wanted to write a JDBCUtils tool class that is bound to the connection and thread, but during the test, I found that the null pointer exception has been reported. After checking online, Spring does not support injection of static member variables, so it is definitely not possible to try @Autowired.

However, when we write tool classes, we must use static variables and methods. Let me summarize the methods I have used to implement injection of static member variables.

@Component
public class JDBCUtils {
    @Autowired
    private static ComboPooledDataSource dataSource;
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
    public static Connection getThreadConnection(){
        Connection conn = ();
        if (conn == null){
            conn = getConnection();
            (conn);
        }
        return conn;
    }
    public static DataSource getDataSource(){
        return dataSource;
    }
    public static Connection getConnection(){
        Connection connection = null;
        try {
            connection = ();
        } catch (SQLException e) {
            ();
        }
        return connection;
    }
    public static void removeThreadConnection(){
        ();
    }
}

Set method injection

Annotation method

Add @Component annotation before the class and @Autowired annotation on the set method. Pay attention to two points here

1. The relevant parameters of variables have been configured in the configuration file

2. When static variables are automatically generated, there will be static modifications. They need to be removed, otherwise they will still not be injected.

@Component
public class JDBCUtils {
    private static ComboPooledDataSource dataSource;
    @Autowired
    public void setDataSource(ComboPooledDataSource dataSource) {
         = dataSource;
    }

xml method

Also pay attention to removing the static on the set method

public class JDBCUtils {
    private static   ComboPooledDataSource dataSource;
    public void setDataSource(ComboPooledDataSource dataSource) {
         = dataSource;
    }
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
    public static Connection getThreadConnection(){
        Connection conn = ();
        if (conn == null){
            conn = getConnection();
            (conn);
        }
        return conn;
    }
    public static DataSource getDataSource(){
        return dataSource;
    }
    public static Connection getConnection(){
        Connection connection = null;
        try {
            connection = ();
        } catch (SQLException e) {
            ();
        }
        return connection;
    }
    public static void removeThreadConnection(){
        ();
    }
}
   <bean  class="">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

@PostConstruct annotation method injection

Use @PostConstruct to add it to the init method, execute the method after class initialization, and assign values ​​to member variables. Before this, we need to modify the tool class and remove the static modifiers we want to inject variables, so that we can inject it with @Autowired.

Then add a static reference object of the class itself, and when we want a variable, we obtain it through this reference object.

@Component
public class JDBCUtils {
    @Autowired
    private  ComboPooledDataSource dataSource;
    private static JDBCUtils jdbcUtils;
    @PostConstruct
    public void init(){
        jdbcUtils = this;
         = dataSource;
    }
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
    public static Connection getThreadConnection(){
        Connection conn = ();
        if (conn == null){
            conn = getConnection();
            (conn);
        }
        return conn;
    }
    public static DataSource getDataSource(){
        return ;
    }
    public static Connection getConnection(){
        Connection connection = null;
        try {
            connection = ();
        } catch (SQLException e) {
            ();
        }
        return connection;
    }
    public static void removeThreadConnection(){
        ();
    }
}

Of course, this initialization method can also be configured in XML, and the principle is the same.

public class JDBCUtils {
    private  ComboPooledDataSource dataSource;
    public void setDataSource(ComboPooledDataSource dataSource) {
         = dataSource;
    }
    private static JDBCUtils jdbcUtils;
    public void init(){
        jdbcUtils = this;
         = dataSource;
    }
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
    public static Connection getThreadConnection(){
        Connection conn = ();
        if (conn == null){
            conn = getConnection();
            (conn);
        }
        return conn;
    }
    public static DataSource getDataSource(){
        return ;
    }
    public static Connection getConnection(){
        Connection connection = null;
        try {
            connection = ();
        } catch (SQLException e) {
            ();
        }
        return connection;
    }
    public static void removeThreadConnection(){
        ();
    }
}
<bean  class="" init-method="init">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

Causes of static method injection bean failure

Today, when writing a tool class for redission, I wrote the following code casually

package ;  
import .*;
import ;
import ; 
import ; 
@Component
public class RedissionUtilserror { 
    @Autowired
   private static RedissonClient redissonClient; 
 
    public static RLock getRLock(String objectName) {
        RLock rLock =(objectName);
        return rLock;
    } 
 
    //Get map based on name    public static  &lt;K, V&gt; RMap&lt;K, V&gt; getRMap(String objectName) {
        RMap&lt;K, V&gt; map = (objectName);
        return map;
    }
 
    //Set map according to name and value    public static void setMap(String objectName,Object key,Object value){
        RMap&lt;Object, Object&gt; map =(objectName);
        (key,value);
    } 
 
    //Get set according to name    public static &lt;V&gt; RSet&lt;V&gt; getSet(String objectName) {
        RSet&lt;V&gt; set = (objectName);
        return set;
    }
 
    //Set set according to name and value    public static void setSet(String objectName,Object value){
        RSet&lt;Object&gt; set = (objectName);
        (value);
    }
 
    //Get list based on name    public static  &lt;V&gt; RList&lt;V&gt; getRList(String objectName) {
        RList&lt;V&gt; rList = (objectName);
        return rList;
    } 
 
    //Set list according to name and value    public static void setList(String objectName, int  index,Object element ){
        RList&lt;Object&gt; objectRList = (objectName);
        (index,element);
    }
 
    //Get bucket based on name    public static &lt;T&gt; RBucket&lt;T&gt; getRBucket(String objectName) {
        RBucket&lt;T&gt; bucket = (objectName);
        return bucket;
    }
 
    //Set the corresponding bucket according to the name and value    public static  &lt;T&gt; T setBucket(String objectName,String value){
        RBucket&lt;Object&gt; bucket = (objectName);
        (value);
        T t= (T) (); //The value type is determined by the return value        return  t;
    } 
}

At first glance, it seems that there is no problem. I write a static method and then use the static variable redissonClient in the method. Wow..., everything looks so normal

When I started testing, NPE....................what happened? I was thinking that this was unscientific and why there was a null pointer, so I started looking for the reason

Finally, I found that the foundation was not solid..... I almost didn't consider the class loading mechanism of jvm. Briefly, the reason for the error

When jvm is loading, it will first load class variables, class methods, which are the methods that I have been modified by static. Then when I call static methods for use, I will use redissionClient. Note that this redissionClient comes in through autowired. The key problem is here. The underlying layer of autowired is injected into beans through the constructor and the set method.

RedissionClient is modified statically and is also an interface. It is definitely not instantiated when it is called.

The following are three ways to use correctly

Method one

package ;  
import .*;
import ;
import ; 
import ; 
@Component
public class RedissionUtils { 
    private static RedissonClient redissonClient; 
    @Autowired
    public  RedissionUtils(RedissonClient redissonClient){
        =redissonClient;
    }  
 
    public static RLock getRLock(String objectName) {
        RLock rLock = (objectName);
        return rLock;
    } 
 
    //Get map based on name    public static  &lt;K, V&gt; RMap&lt;K, V&gt; getRMap(String objectName) {
        RMap&lt;K, V&gt; map = (objectName);
        return map;
    }
 
    //Set map according to name and value    public static void setMap(String objectName,Object key,Object value){
        RMap&lt;Object, Object&gt; map =(objectName);
        (key,value);
    } 
 
    //Get set according to name    public static &lt;V&gt; RSet&lt;V&gt; getSet(String objectName) {
        RSet&lt;V&gt; set = (objectName);
        return set;
    }
 
    //Set set according to name and value    public static void setSet(String objectName,Object value){
        RSet&lt;Object&gt; set = (objectName);
        (value);
    }
 
    //Get list based on name    public static  &lt;V&gt; RList&lt;V&gt; getRList(String objectName) {
        RList&lt;V&gt; rList = (objectName);
        return rList;
    } 
 
    //Set list according to name and value    public static void setList(String objectName, int  index,Object element ){
        RList&lt;Object&gt; objectRList = (objectName);
        (index,element);
    }
 
    //Get bucket based on name    public static &lt;T&gt; RBucket&lt;T&gt; getRBucket(String objectName) {
        RBucket&lt;T&gt; bucket = (objectName);
        return bucket;
    }
 
    //Set the corresponding bucket according to the name and value    public static  &lt;T&gt; T setBucket(String objectName,String value){
        RBucket&lt;Object&gt; bucket = (objectName);
        (value);
        T t= (T) (); //The value type is determined by the return value        return  t;
    } 
}

Method 2

package ;  
import .*;
import ;
import ; 
import ; 
@Component
public class RedissionUtils2 {
 
    @Autowired
    RedissonClient redissonClient; 
    public  static RedissionUtils2 redissionUtils; 
    @PostConstruct
    public  void  init(){
        redissionUtils=this;
        =;
    } 
 
    public static RLock getRLock(String objectName) {
        RLock rLock = (objectName);
        return rLock;
    } 
 
    //Get map based on name    public static  &lt;K, V&gt; RMap&lt;K, V&gt; getRMap(String objectName) {
        RMap&lt;K, V&gt; map = (objectName);
        return map;
    }
 
    //Set map according to name and value    public static void setMap(String objectName,Object key,Object value){
        RMap&lt;Object, Object&gt; map =(objectName);
        (key,value);
    } 
 
    //Get set according to name    public static &lt;V&gt; RSet&lt;V&gt; getSet(String objectName) {
        RSet&lt;V&gt; set = (objectName);
        return set;
    }
 
    //Set set according to name and value    public static void setSet(String objectName,Object value){
        RSet&lt;Object&gt; set = (objectName);
        (value);
    }
 
    //Get list based on name    public static  &lt;V&gt; RList&lt;V&gt; getRList(String objectName) {
        RList&lt;V&gt; rList = (objectName);
        return rList;
    } 
 
    //Set list according to name and value    public static void setList(String objectName, int  index,Object element ){
        RList&lt;Object&gt; objectRList = (objectName);
        (index,element);
    }
 
    //Get bucket based on name    public static &lt;T&gt; RBucket&lt;T&gt; getRBucket(String objectName) {
        RBucket&lt;T&gt; bucket = (objectName);
        return bucket;
    }
 
    //Set the corresponding bucket according to the name and value    public static  &lt;T&gt; T setBucket(String objectName,String value){
        RBucket&lt;Object&gt; bucket = (objectName);
        (value);
        T t= (T) (); //The value type is determined by the return value        return  t;
    } 
}

Method 3 Obtain through spring context

package ;  
import ;
import ;
import ;
import ;
import ;
import ;
import ; 
import ;
 
/**
  * Spring Context tool class.
  *
  * @author:Hohn
  */
@Component
@Scope("singleton")
public class SpringUtil implements ApplicationContextAware {
 
    /**
      * Spring application context.
      */
    private static ApplicationContext applicationContext;
 
    /**
      * Implement the callback method of the ApplicationContextAware interface and set the context environment
      *
      * <br>🌹param: applicationContext
      * @throws BeansException
      */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		 = applicationContext;
    }
 
    /**
      * Get ApplicationContext.
      *
      * <br>🌹return: ApplicationContext
      */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
 
    /**
      * Get the object.
      *
      * <br>🌹param: name
      * <br>🌹return: Object An instance of a bean registered with the given name
      * @throws BeansException
      */
    @SuppressWarnings("unchecked")
    public static &lt;T&gt; T getBean(String name) throws BeansException {
        return (T) (name);
    }
 
    /**
      * Get an object of type requiredType.
      *
      * <br>🌹param: clz
      * <br>🌹return:
      * @throws BeansException
      */
    public static &lt;T&gt; T getBean(Class&lt;T&gt; clz) throws BeansException {
        return (T)(clz);
    }
 
    /**
      * Return true if the BeanFactory contains a bean definition that matches the given name
      *
      * <br>🌹param: name
      * <br>🌹return: boolean
      */
    public static boolean containsBean(String name) {
        return (name);
    }
 
    /**
      * Determine whether the bean definition registered with a given name is a singleton or a prototype.
      * If the bean definition corresponding to the given name is not found, an exception will be thrown (NoSuchBeanDefinitionException)
      * <br>🌹param: name
      * <br>🌹return: boolean
      * @throws NoSuchBeanDefinitionException
      */
    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
        return (name);
    }
 
    /**
      * <br>🌹param: name
      * <br>🌹return: Class The type of registered object
      * @throws NoSuchBeanDefinitionException
      */
    public static Class&lt;?&gt; getType(String name) throws NoSuchBeanDefinitionException {
        return (name);
    }
 
    /**
      * If the given bean name has alias in the bean definition, these aliases are returned.
      *
      * <br>🌹param: name
      * <br>🌹return:
      * @throws NoSuchBeanDefinitionException
      */
    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
        return (name);
    } 
 
	/**
	  * Request header to get request token
	  * @param servletRequest
	  * @return
	  */
	public static String getJwtToken(HttpServletRequest servletRequest, String tokenId) {
		String token = (tokenId);
		if ((token)) {
			token = (tokenId);
		}
		return token;
	}
}

The above is personal experience. I hope you can give you a reference and I hope you can support me more.