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 <K, V> RMap<K, V> getRMap(String objectName) { RMap<K, V> map = (objectName); return map; } //Set map according to name and value public static void setMap(String objectName,Object key,Object value){ RMap<Object, Object> map =(objectName); (key,value); } //Get set according to name public static <V> RSet<V> getSet(String objectName) { RSet<V> set = (objectName); return set; } //Set set according to name and value public static void setSet(String objectName,Object value){ RSet<Object> set = (objectName); (value); } //Get list based on name public static <V> RList<V> getRList(String objectName) { RList<V> rList = (objectName); return rList; } //Set list according to name and value public static void setList(String objectName, int index,Object element ){ RList<Object> objectRList = (objectName); (index,element); } //Get bucket based on name public static <T> RBucket<T> getRBucket(String objectName) { RBucket<T> bucket = (objectName); return bucket; } //Set the corresponding bucket according to the name and value public static <T> T setBucket(String objectName,String value){ RBucket<Object> 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 <K, V> RMap<K, V> getRMap(String objectName) { RMap<K, V> map = (objectName); return map; } //Set map according to name and value public static void setMap(String objectName,Object key,Object value){ RMap<Object, Object> map =(objectName); (key,value); } //Get set according to name public static <V> RSet<V> getSet(String objectName) { RSet<V> set = (objectName); return set; } //Set set according to name and value public static void setSet(String objectName,Object value){ RSet<Object> set = (objectName); (value); } //Get list based on name public static <V> RList<V> getRList(String objectName) { RList<V> rList = (objectName); return rList; } //Set list according to name and value public static void setList(String objectName, int index,Object element ){ RList<Object> objectRList = (objectName); (index,element); } //Get bucket based on name public static <T> RBucket<T> getRBucket(String objectName) { RBucket<T> bucket = (objectName); return bucket; } //Set the corresponding bucket according to the name and value public static <T> T setBucket(String objectName,String value){ RBucket<Object> 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 <K, V> RMap<K, V> getRMap(String objectName) { RMap<K, V> map = (objectName); return map; } //Set map according to name and value public static void setMap(String objectName,Object key,Object value){ RMap<Object, Object> map =(objectName); (key,value); } //Get set according to name public static <V> RSet<V> getSet(String objectName) { RSet<V> set = (objectName); return set; } //Set set according to name and value public static void setSet(String objectName,Object value){ RSet<Object> set = (objectName); (value); } //Get list based on name public static <V> RList<V> getRList(String objectName) { RList<V> rList = (objectName); return rList; } //Set list according to name and value public static void setList(String objectName, int index,Object element ){ RList<Object> objectRList = (objectName); (index,element); } //Get bucket based on name public static <T> RBucket<T> getRBucket(String objectName) { RBucket<T> bucket = (objectName); return bucket; } //Set the corresponding bucket according to the name and value public static <T> T setBucket(String objectName,String value){ RBucket<Object> 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 <T> T getBean(String name) throws BeansException { return (T) (name); } /** * Get an object of type requiredType. * * <br>🌹param: clz * <br>🌹return: * @throws BeansException */ public static <T> T getBean(Class<T> 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<?> 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.