How to use Spring cache Manager with redis 1.6.2.RELEASE - java

We are using Spring Cache Manager with spring-data-redis 1.5.2. These days we want to upgrade spring-data-redis to latest release i.e:1.6.2.RELEASE.
For some weird reason everything works good with 1.5.2 but when upgrading to 1.6.2 we get
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'cacheManager' defined in ServletContext
resource [/WEB-INF/spring-cache.xml]: Unsatisfied dependency
expressed through constructor argument with index 0 of type
[org.springframework.data.redis.core.RedisOperations]: Ambiguous
constructor argument types - did you specify the correct bean
references as constructor arguments?
This message seems like a mistake as redisTemplate is RedisTemplate which implements RedisOperations.
Any idea how to solve it?
P.S
note that when removing the cache configuration the 1.6.2 version seems to work good. So the issue is with the cache.
Configuration
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-redis.xml
/WEB-INF/spring-cache.xml
</param-value>
</context-param>
spring-redis.xml
<context:annotation-config />
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" />
<bean
class="org.springframework.security.web.session.HttpSessionEventPublisher" />
<!-- end of seesion managment configuration -->
<bean id="redisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="port" value="${app.redis.port}" />
<property name="hostName" value="${app.redis.hostname}" />
<property name="password" value="${app.redis.password}" />
<property name="usePool" value="true" />
</bean>
<!-- for publishing string over redis channels -->
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="redisConnectionFactory" />
</bean>
<!-- for storing object into redis key,value -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="redisConnectionFactory" />
</bean>
spring-cache.xml
<!-- This file must load after spring-redis.xml -->
<cache:annotation-driven />
<!-- declare Redis Cache Manager -->
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"
c:template-ref="redisTemplate" />
</beans>

It seems the reason for this bug is that RedisCacheManager has two constructors. Both of them has RedisOperations as parameter. Forsome reason Spring couldnot understand its related to the first constructor and not to the second one. a work around is mention constructor-arg index
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg index="0" ref="redisTemplate"></constructor-arg>
</bean>

While upgrading from Spring Data Redis 1.5.2.RELEASE to 1.6.2.RELEASE, we need to use the below config for RedisCacheManager. Previous releases were using redis-template-ref instead of redis-operations-ref.
<beans:bean id='cacheManager'
class='org.springframework.data.redis.cache.RedisCacheManager'
c:redis-operations-ref='redisTemplate'>
</beans:bean>

This is an old question, but for those who reach this page.
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager" factory-method="create" c:connection-factory-ref="jedisConnectionFactory" p:transaction-aware="true" />
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnectionFactory" />
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${cache.redis.host}" p:port="${cache.redis.port}" p:use-pool="true">
<constructor-arg ref="jedisPoolConfig"></constructor-arg>
</bean>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" p:maxTotal="${cache.redis.pool.maxTotal}" p:maxIdle="${cache.redis.pool.maxIdle}" p:maxWaitMillis="${cache.redis.pool.maxWaitMillis}" p:testOnBorrow="true" />

Related

Two beans with same name in different contexts

I have the following beans in my contexs:
<!-- Context 1 -->
<beans profile="ldap">
<bean id="activeDirectoryAuthProvider" class="com.production.ActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
</beans>
<!-- Context 2 -->
<bean id="activeDirectoryAuthProvider" class="com.test.TestActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
My goal is to use the first bean only for production version another one for test purposes.
Namely when I start test based on production context I expect that production bean would be replaced by test bean with needed configuration.
But unfortunately when I tried to create two beans with same name only production bean is created and another one is ignored. Another thing that I noticed that when I tried to change test bean name to: activeDirectoryAuthProvider1 then both beans are successfully created. Can anyone explain why it happen and suggest possible solution how it can be bypassed?
You need to use different contexts for development and production. In each context you define only the relevant bean (i.e. only 1 bean with a certain name). If you use maven you can put the test/development context under src/test/resources and the production context under src/main/resources
If you do not use maven there are other approaches. You can find an example here: http://mrhaki.blogspot.it/2009/02/use-spring-configurator-to-support.html
Take a look at Spring Profiles you can have one for test and one for prod.
<beans profile="test">
<!-- Context 1 -->
<bean id="activeDirectoryAuthProvider" class="com.production.ActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
</beans>
<beans profile="prod">
<!-- Context 2 -->
<bean id="activeDirectoryAuthProvider" class="com.test.TestActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
</beans>
You can set the active profile in a various ways. Check the docs.

SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization

I've got an app running on Tomcat 7, using Spring, Mybatis, and .. Mybatis-spring.
Here's the setup for the DB and transactions in servlet-context.xml:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDS" />
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath*:maps/*.xml" />
<property name="transactionFactory">
<bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />
</property>
</bean>
<mybatis:scan base-package="com.domain.dao.mappers" />
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
The error I'm getting when I run a method that uses the SqlSession is the following:
org.springframework.dao.TransientDataAccessResourceException: SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization
at org.mybatis.spring.SqlSessionUtils.getSqlSession(SqlSessionUtils.java:136)
What am I doing wrong?
My goal, really, is just to use transactions with this setup. I don't think I necessarilly need JTA. But if that's easy enough to setup on Tomcat, I'm willing to take a swing at it.
And I solved the problem myself. Really simple solution. In case anyone runs into the same issue, all I needed to do is remove the following from the sqlSessionFactory bean:
<property name="transactionFactory">
<bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />
</property>
I must have somehow entered it thinking I needed it, but apparently it's only needed if you're not using CMT (Container Managed Transactions).
You can solve this by changing the transaction factory to
<property name="transactionFactory">
<bean class="org.mybatis.spring.transaction.SpringManagedTransactionFactory" />
</property>

Spring MVC Default View Resolver Not Working?

I would like any requests that do not resolve to specific controller mappings to go to a view with a name derived from the request path.
Eg localhost/success should end up rendering a view located at /WEB-INF/view/freemarker/success.ftl. I gather from the Spring documentation that this behaviour should be enabled by default, by it doesn't appear to be working with my setup.
<mvc:annotation-driven />
<mvc:interceptors>
<!-- On pre-handle, resolve the device that originated the web request -->
<bean
class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor" />
</mvc:interceptors>
<!-- Spring Mobile -->
<bean
class="org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver">
<constructor-arg>
<!-- Freemarker -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="false" />
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
</bean>
</constructor-arg>
<property name="mobilePrefix" value="mobile/" />
<property name="tabletPrefix" value="tablet/" />
</bean>
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/view/freemarker/" />
</bean>
Turns out there was no HandlerMapping implementation found for these requests, and so DispatcherServlet never called the DefaultRequestToViewNameTranslator.
Adding the following provided the appropriate HandlerMapping, and thus filled in the missing link. The only downside now is that it's throwing exceptions logging at SEVERE for any requests that can't be satisfied, as opposed to DispatcherServlet's more polite WARNING.
<mvc:view-controller path="/*" />

<mvc:annotation-driven /> with un-annotated controllers

My project includes older un-annotated controllers together with newer annotation-based controllers.
I am using the latest Spring jars (3.0.5) and in my dispatcher-servlet.xml there's <mvc:annotation-driven />.
The problem is that <mvc:annotation-driven /> causes the request mapping (through the name property of the controller beans in the dispatcher-servlet.xml) to my un-annotated controllers not to work... each time I direct the request to an un-annotated controller I am getting an error message such as:
org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [/some_path/some_page.htm] in DispatcherServlet with name 'dispatcher'
How can I keep the un-annotated controllers as they are but tell spring to recognize their (old style) mapping?
I am looking for solutions with minimum change to the Java code of the controllers that I already have.
Thanks!
When you add <mvc:annotation-driven /> to your config, it replaces the default set of handler mappings and handler adapters, and those defaults were the ones that handled the old-style controllers.
You have 2 options. First thing to try is to remove <mvc:annotation-driven />. You can still use annotated controllers without this. It does add extra features like Jackson JSON support, but if you don't need those extra features, then you don't need it. So try your app without <mvc:annotation-driven /> and see if it still works.
Failing that, you can reinstate the mappings and adapters for your old controllers. You didn't say how your controllers used to have their URLs mapped, but try adding these to your config:
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.handler.ControllerClassNameHandlerMapping"/>
If you used SimpleUrlHandlerMapping, then that should be working already.
You also need to add the HandlerAdapter back in:
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
Don't just add these in blindly. Try them individually, and see what the minimal set is to get your old controllers working alongside the new ones.
I found that by exploding the mvc:annotation-driven into it's actual replacement, it was easier to figure out.
<mvc:annotation-driven /> explodes to this:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="0" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="validator" ref="validator" />
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
</list>
</property>
</bean>
<!-- Configures a validator for spring to use -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="messageInterpolator">
<bean class="com.eps.web.spring.validation.SpringMessageSourceMessageInterpolator" />
</property>
</bean>
<bean id="conversion-service" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
Once the magic was gone, I got this error trying to load an "Old" controller:
javax.servlet.ServletException: No adapter for handler [org.springframework.web.servlet.mvc.ParameterizableViewController#
From that point, I added
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
And all my old controllers worked.

Embedding HornetQ in Spring

I am trying to evaluate HornetQ and the possibility of embedding it in a spring application. To start with a simple setup I am just trying to initialize it as follows. I didn't find much documentation about how to do this, apart from the fact that 'you can'.
I am using Spring 3 and HornetQ 2.1.1GA
My Spring configuration looks like this, however if theres a simpler cleaner configuration it would be better. I want the minimalistic approach first and then build on it.:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="mbeanServer" class="java.lang.management.ManagementFactory" factory-method="getPlatformMBeanServer" />
<bean name="fileConfiguration" class="org.hornetq.core.config.impl.FileConfiguration" init-method="start" destroy-method="stop" />
<bean name="hornetQSecurityManagerImpl" class="org.hornetq.spi.core.security.HornetQSecurityManagerImpl" />
<!-- The core server -->
<bean name="hornetQServerImpl" class="org.hornetq.core.server.impl.HornetQServerImpl">
<constructor-arg ref="fileConfiguration" />
<constructor-arg ref="mbeanServer" />
<constructor-arg ref="hornetQSecurityManagerImpl" />
</bean>
<!-- The JMS server -->
<bean name="jmsServerManagerImpl" class="org.hornetq.jms.server.impl.JMSServerManagerImpl" init-method="start" destroy-method="stop" >
<constructor-arg ref="hornetQServerImpl" />
</bean>
<bean name="connectionFactory" class="org.hornetq.jms.client.HornetQConnectionFactory" >
<constructor-arg>
<bean class="org.hornetq.api.core.TransportConfiguration">
<constructor-arg value="org.hornetq.integration.transports.netty.NettyConnectorFactory" />
<constructor-arg>
<map key-type="java.lang.String" value-type="java.lang.Object">
<entry key="port" value="5445"></entry>
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
<bean name="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"></property>
</bean>
</beans>
With this config I am getting the error:
SEVERE: Unable to deploy node [queue: null] DLQ
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
...
29-Dec-2010 18:16:34 org.hornetq.core.logging.impl.JULLogDelegate error
SEVERE: Unable to deploy node [queue: null] ExpiryQueue
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
...
9-Dec-2010 18:16:34 org.hornetq.core.logging.impl.JULLogDelegate error
SEVERE: Unable to deploy node [queue: null] ExampleQueue
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:325)
Its must be something obvious related to JNDI, but I would appreciate the proper minimalistic configuration to start with and then expand on it afterwards. The HornetQ configuration files are the default ones that come with the distribution (default queues, default users etc.)
You need to define the JMS queues you want to add to the server, and specify an empty list of JNDI bindings for each queue. To do this, add a JMSConfigurationImpl to your JMSServerManagerImpl bean definition. For example, if you need to define a queue called "testqueue":
<bean id="hornetQJmsConfig" class="org.hornetq.jms.server.config.impl.JMSConfigurationImpl">
<constructor-arg index="0">
<list/>
</constructor-arg>
<!-- Queue configurations -->
<constructor-arg index="1">
<list>
<bean class="org.hornetq.jms.server.config.impl.JMSQueueConfigurationImpl">
<!-- Name -->
<constructor-arg index="0" value="testqueue"/>
<!-- Selector -->
<constructor-arg index="1"><null/></constructor-arg>
<!-- Durable queue -->
<constructor-arg index="2" value="true"/>
<!-- JNDI bindings, empty list for none -->
<constructor-arg index="3"><list/></constructor-arg>
</bean>
</list>
</constructor-arg>
<!-- Topic configurations -->
<constructor-arg index="2">
<list/>
</constructor-arg>
</bean>
Since the second and third constructor args take a list of queue and topic configurations, you can add as many queues and topics as you like. For more than one or two, it's probably best to create a Spring template object.

Categories

Resources