applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder 错误解决方法
1.使用场景
springboot使用mybatis开启redis二级缓存,使用的代码如下:
ApplicationContextHolder.java
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 | import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @Component public class ApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext applicationContext; /** * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量. */ @Override public void setApplicationContext(ApplicationContext applicationContext) { ApplicationContextHolder.applicationContext = applicationContext; // NOSONAR } /** * 取得存储在静态变量中的ApplicationContext. */ public static ApplicationContext getApplicationContext() { checkApplicationContext(); return applicationContext; } /** * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型. */ @SuppressWarnings ( "unchecked" ) public static <T> T getBean(String name) { checkApplicationContext(); return (T) applicationContext.getBean(name); } /** * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型. */ @SuppressWarnings ( "unchecked" ) public static <T> T getBean(Class<T> clazz) { checkApplicationContext(); return (T) applicationContext.getBeansOfType(clazz); } /** * 清除applicationContext静态变量. */ public static void cleanApplicationContext() { applicationContext = null ; } private static void checkApplicationContext() { if (applicationContext == null ) { throw new IllegalStateException( "applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder" ); } } } |
RedisCacheServiceImpl.java
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 | import dgis.lite.usgs.ApplicationContextHolder; import dgis.lite.usgs.utils.SpringUtils; import org.apache.ibatis.cache.Cache; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Configuration; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class RedisCacheServiceImpl implements Cache { // 读写锁 private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock( true ); private RedisTemplate<String, Object> redisTemplate = ApplicationContextHolder.getBean( "redisTemplate" ); private String id; public RedisCacheServiceImpl( final String id) { if (id == null ) { throw new IllegalArgumentException( "Cache instances require an ID" ); } this .id = id; } @Override public String getId() { return this .id; } @Override public void putObject(Object key, Object value) { if (value != null ) { // 向Redis中添加数据,有效时间是1小时 redisTemplate.opsForValue().set(key.toString(), value, 1 , TimeUnit.HOURS); } } @Override public Object getObject(Object key) { try { if (key != null ) { Object obj = redisTemplate.opsForValue().get(key.toString()); return obj; } } catch (Exception e) { } return null ; } @Override public Object removeObject(Object key) { try { if (key != null ) { redisTemplate.delete(key.toString()); } } catch (Exception e) { } return null ; } @Override public void clear() { try { Set<String> keys = redisTemplate.keys( "*:" + this .id + "*" ); if (!CollectionUtils.isEmpty(keys)) { redisTemplate.delete(keys); } } catch (Exception e) { } } @Override public int getSize() { Long size = (Long) redisTemplate.execute( new RedisCallback<Long>() { @Override public Long doInRedis(RedisConnection connection) throws DataAccessException { return connection.dbSize(); } }); return size.intValue(); } @Override public ReadWriteLock getReadWriteLock() { return this .readWriteLock; } } |
2.出现问题
applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.
这个异常其实是在 ApplicationContextHolder.java 中我们自己写的异常,出现原因是因为 mapper中定义的缓存类型加载的比ApplicationContextHolder快,也就是说ApplicationContextHolder还没有初始化好,mapper就开始初始化了。
3.解决方法
网上搜了一大堆方法,都是复制粘贴的,最后处理方法其实比较简单,就是不使用ApplicationContextHolder这个类,直接使用SpringUtils.getBean类初始化redisTemplate。即:
1 | private RedisTemplate<String, Object> redisTemplate = SpringUtils.getBean( "redisTemplate" ); |
修改后的RedisCacheServiceImpl.java
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 | import dgis.lite.usgs.ApplicationContextHolder; import dgis.lite.usgs.utils.SpringUtils; import org.apache.ibatis.cache.Cache; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Configuration; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class RedisCacheServiceImpl implements Cache { // 读写锁 private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock( true ); private RedisTemplate<String, Object> redisTemplate = SpringUtils.getBean( "redisTemplate" ); private String id; public RedisCacheServiceImpl( final String id) { if (id == null ) { throw new IllegalArgumentException( "Cache instances require an ID" ); } this .id = id; } @Override public String getId() { return this .id; } @Override public void putObject(Object key, Object value) { if (value != null ) { // 向Redis中添加数据,有效时间是1小时 redisTemplate.opsForValue().set(key.toString(), value, 1 , TimeUnit.HOURS); } } @Override public Object getObject(Object key) { try { if (key != null ) { Object obj = redisTemplate.opsForValue().get(key.toString()); return obj; } } catch (Exception e) { } return null ; } @Override public Object removeObject(Object key) { try { if (key != null ) { redisTemplate.delete(key.toString()); } } catch (Exception e) { } return null ; } @Override public void clear() { try { Set<String> keys = redisTemplate.keys( "*:" + this .id + "*" ); if (!CollectionUtils.isEmpty(keys)) { redisTemplate.delete(keys); } } catch (Exception e) { } } @Override public int getSize() { Long size = (Long) redisTemplate.execute( new RedisCallback<Long>() { @Override public Long doInRedis(RedisConnection connection) throws DataAccessException { return connection.dbSize(); } }); return size.intValue(); } @Override public ReadWriteLock getReadWriteLock() { return this .readWriteLock; } } |
SpringUtils.java
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 122 123 124 125 126 127 128 129 | import org.apache.commons.lang.StringUtils; import org.springframework.aop.framework.AopContext; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware { /** * Spring 应用上下文环境 */ private static ConfigurableListableBeanFactory beanFactory; private static ApplicationContext applicationContext; public SpringUtils() { } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { SpringUtils.beanFactory = beanFactory; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringUtils.applicationContext = applicationContext; } /** * 获取对象 * * @param name * @return Object 一个以所给名字注册的 bean 的实例 * @throws BeansException */ @SuppressWarnings ( "unchecked" ) public static <T> T getBean(String name) throws BeansException { return (T) beanFactory.getBean(name); } /** * 获取类型为 requiredType 的对象 * * @param clz * @return * @throws BeansException */ public static <T> T getBean(Class<T> clz) throws BeansException { T result = (T) beanFactory.getBean(clz); return result; } /** * 如果 BeanFactory 包含一个与所给名称匹配的 bean 定义,则返回 true * * @param name * @return boolean */ public static boolean containsBean(String name) { return beanFactory.containsBean(name); } /** * 判断以给定名字注册的 bean 定义是一个 singleton 还是一个 prototype。 如果与给定名字相应的 bean 定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) * * @param name * @return boolean * @throws NoSuchBeanDefinitionException */ public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { return beanFactory.isSingleton(name); } /** * @param name * @return Class 注册对象的类型 * @throws NoSuchBeanDefinitionException */ public static Class<?> getType(String name) throws NoSuchBeanDefinitionException { return beanFactory.getType(name); } /** * 如果给定的 bean 名字在 bean 定义中有别名,则返回这些别名 * * @param name * @return * @throws NoSuchBeanDefinitionException */ public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { return beanFactory.getAliases(name); } /** * 获取 aop 代理对象 * * @param invoker * @return */ @SuppressWarnings ( "unchecked" ) public static <T> T getAopProxy(T invoker) { return (T) AopContext.currentProxy(); } /** * 获取当前的环境配置,无配置返回 null * * @return 当前的环境配置 */ public static String[] getActiveProfiles() { return applicationContext.getEnvironment().getActiveProfiles(); } /** * 获取当前的环境配置,当有多个环境配置时,只获取第一个 * * @return 当前的环境配置 */ public static String getActiveProfile() { final String[] activeProfiles = getActiveProfiles(); return StringUtils.isNotEmpty(String.valueOf(activeProfiles)) ? activeProfiles[ 0 ] : null ; } } |
现在打包jar,运行正常。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」