I tried to integrate spring boot + redis into my application.
Related settings in pom.xml is as below,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Application main is as below,
@SpringBootApplication
@EnableTransactionManagement
@ImportResource({"classpath*:applicationContext.xml"})
public class ExamsCenterApplication {
public static void main(String[] args) {
SpringApplication.run(ExamsCenterApplication.class, args);
}
}
Contents of applicationContext.xml is as below,
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"
xmlns:mybatis="http://mybatis.org/schema/mybatis-spring" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring.xsd">
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login.jsp" />
<property name="successUrl" value="/index.jsp" />
<property name="unauthorizedUrl" value="/unauthorized.jsp" />
<property name="filters">
<util:map>
<entry key="authc">
<bean
class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" />
</entry>
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/marktask/list/ = authc, perms[scoretask:view]
/marktask/view/ = authc, perms[scoretask:view]
/** = anon
</value>
</property>
</bean>
<bean id="examCenter" class="org.apache.tomcat.jdbc.pool.DataSource"
destroy-method="close">
<property name="poolProperties">
<bean class="org.apache.tomcat.jdbc.pool.PoolProperties">
<property name="url"
value="jdbc:mysql://192.168.100.21:13306/ustudy?characterEncoding=UTF-8&serverTimezone=UTC" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="username" value="root" />
<property name="password" value="mysql" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="true" />
<property name="validationInterval" value="30000" />
<property name="testOnReturn" value="false" />
<property name="validationQuery" value="/* ping */" />
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<property name="maxActive" value="100" />
<property name="initialSize" value="10" />
<property name="maxWait" value="10000" />
<!-- <property name="removeAbandonedTimeout" value="60"/> <property name="minEvictableIdleTimeMillis"
value="30000"/> <property name="minIdle" value="10"/> <property name="logAbandoned"
value="true"/> <property name="removeAbandoned" value="true"/> <property
name="jdbcInterceptors" value="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"/> -->
</bean>
</property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- Single realm app. If you have multiple realms, use the 'realms' property
instead. -->
<property name="realm" ref="authRealm" />
<!-- By default the servlet container sessions will be used. Uncomment
this line to use shiro's native sessions (see the JavaDoc for more): -->
<!-- <property name="sessionMode" value="native"/> -->
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<!-- Define the Shiro Realm implementation you want to use to connect to
your back-end -->
<!-- security datasource: -->
<bean id="authRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="dataSource" ref="examCenter" />
<property name="permissionsLookupEnabled" value="true" />
<property name="authenticationQuery"
value="select passwd from ustudy.teacher where teacid = ?" />
<property name="userRolesQuery"
value="select role_name from ustudy.teacherroles where teac_id = ?" />
<property name="permissionsQuery"
value="select perm from ustudy.perms where role_name = ?" />
</bean>
<bean
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor" />
<bean
class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
<!-- Secure Spring remoting: Ensure any Spring Remoting method invocations
can be associated with a Subject for security checks. -->
<bean id="secureRemoteInvocationExecutor"
class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
<property name="securityManager" ref="securityManager" />
</bean>
<!-- Noted: Two methods for enabling spring transaction managent with jdbc.
Above is XML based configuration. Declaring with @Transactional in java source
code is also very flexible. -->
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="examCenter" />
</bean>
<!-- sql session factory for mybatis -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="examCenter" />
<property name="mapperLocations" value="classpath:com/ustudy/exam/mapping/*.xml"></property>
</bean>
<!-- scan for mappers and make them autowired -->
<mybatis:scan base-package="com.ustudy.exam.mapper" />
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ustudy.exam.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
<!-- spring data redis related configurations -->
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:use-pool="true" p:database="0" p:host-name="192.168.100.21" p:port="6379"
p:timeout="100" />
<!-- redis template definition -->
<bean id="stringSerializer"
class="org.springframework.data.redis.serializer.StringRedisSerializer" />
<bean id="jdkSerializer"
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
<bean id="jsonSerializer"
class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnectionFactory">
<property name="keySerializer" ref="stringSerializer" />
<property name="valueSerializer" ref="jsonSerializer" />
</bean>
<context:annotation-config />
<bean
class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" />
My service code is as below,
@Service
public class MetaInfo {
private static final Logger logger = LogManager.getLogger(MetaInfo.class);
@Autowired
@Qualifier("redisTemplate")
private RedisTemplate<String, Object> redisT;
/*
* only need basic information about this question, assign mode. not sure whether other info needed.
*/
public QuesMeta getMetaTaskInfo(String quesid) {
logger.debug("getMetaTaskInfo() hitted");
QuesMeta qm = new QuesMeta("redistest", "auto");
redisT.opsForValue().set("001", qm);
if (redisT == null) {
logger.debug("getMetaTaskInfo(), redisTemplate is not initialized.");
return null;
}
redisT.opsForValue().set("redistest", "hello");
logger.debug("getMetaTaskInfo(), stored data in redis");
return null;
}
Then run the program and got the following exception,
java.lang.NullPointerException: null
at com.ustudy.cache.MetaInfo.getMetaTaskInfo(MetaInfo.java:42) ~[classes/:0.0.1-SNAPSHOT]
at com.ustudy.exam.controller.MarkTaskController.getMarkTask(MarkTaskController.java:37) ~[classes/:0.0.1-SNAPSHOT]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151]
It seemed that following code went wrong.
@Autowired
private RedisTemplate<String, String> redisT;
redisT is null and not initialized as expected.
How should I do to fix this issue?
Thanks a lot.
You are creating a
RedisTemplate<String,Object>
bean and trying to autowire it toRedisTemplate<String,String>
fieldIf you want Redis
value
also to be serialized asString
useStringRedisSerializer
forRedisTemplate
'svalueSerializer
property. Change yourredistemplate
bean as below:OR even better create a bean of
StringRedisTemplate
, so you don't have to createStringRedisSerializer
on your own.Change
@Autowired private RedisTemplate<String, String> redisT
to@Autowired private StringRedisTemplate redisT
I really made a mistake in my controller code. My origin controller code is as below,
The code "new MetaInfo()" is not correct. It should also be autowired as below,
Then everything works well.
Thanks @Chacko a lot for help on this issue.