Spring context initialization even on JNDI error - java

I have Spring configuration below. How I can make Spring content initialization even if DB_JNDI does not exist in Application server?
<jee:jndi-lookup id="friends.db" jndi-name="DB_JNDI"/>
<bean name="friendsDbDaoImpl" class="com.tims.db.friendsDbDaoImpl" init-method="init" >
<property name="dataSource" ref="friends.db" />
<property name="queryTimeout" value="${imos.db.friends.querytimeout}" />
</bean>

You can use Spring profiles. They were implemented with this kind of requirement (conditional configuration) in mind.

Related

What is the proper way to create a datasource in a spring web application?

I have two ways to create datasource:
Inside spring context
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mkyongjava" />
<property name="username" value="root" />
<property name="password" value="password" />
Tomcat JNDI
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/UsersDB"/>
What are the benefits and problems of creating the datasource using spring or using tomcat jndi ?
There is nothing like good practice among this. The good one is the one which is good for use case. They both have pros and cons.
When u have use cases where u are trying to deploy the apps on a server environment where multiple apps share a common datasource or datasource components are managed by the Server administration then probably the best way to use is through a JNDI context. The server has the DataSource kept ready so that the application can directly get that object, bind to itself and use the datasource.
When u have use case where application runs inside a embedded server container or cloud containers where the server also is embedded along the build packs creating datasource with in the application and using them would be a good solution. Also in non web application environments creating datasource would be good.
To summarize, use cases where datasource is non managed by the application better to go for a JNDI context.
Try to figure out what is the deployment model of your application and figure out what is good for u. Also try to use a datasourcepool implementations to improve performance like DBCP, C3P0 or Hikarcp.
The first approach, using the class DriverManagerDataSource, is useful for test or standalone environments outside of j2ee container.
The second approach, using the jndi data soure, is recommended to be used in the j2ee container.
The below reference clearly states these approaches.
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/datasource/DriverManagerDataSource.html
I am using it as below. Works for me since project is configured at the time of architecture design. And its live in production.
<!-- Local Apache Commons DBCP DataSource that refers to a combined database -->
<!-- (see dataAccessContext-jta.xml for an alternative) -->
<!-- The placeholders are resolved from jdbc.properties through -->
<!-- the PropertyPlaceholderConfigurer in applicationContext.xml -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="validationQuery" value="${jdbc.validationquery}"/>
<property name="testOnBorrow" value="${jdbc.testonborrow}"/>
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- Transaction manager for a single JDBC DataSource -->
<!-- (see dataAccessContext-jta.xml for an alternative) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
you can also refer to this. Best contribution of Genious to java developers.
https://www.mkyong.com/spring-boot/spring-boot-jdbc-oracle-database-commons-dbcp2-example/
The best practice is to not to expose the database configuration in any of the code that you have written. It is always best to configure inside the server console and expose it as a jndi. Inside spring configuration file, get the database instance as:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc"/>
and configure the database transaction manager as:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
The key note here is do not expose the database configuration.

How to use Spring cache Manager with redis 1.6.2.RELEASE

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" />

jmx mbean server throw InstanceAlreadyExistsException when change c3p0 version

What are the differences between c3p0-0.9.1.2 and c3p0-0.9.5 that mean that when I want to register an MBean with DynamicPooledDataSourceManagerMBean in 0.9.1.2 everything is okay, but when I use 0.9.5 then com.sun.jmx.mbeanserver.Repository throws an javax.management.InstanceAlreadyExistsException.
I use spring as my container so the bean definition for DynamicPooledDataSourceManagerMBean is like this:
<bean id="register" class="com.mchange.v2.c3p0.management.DynamicPooledDataSourceManagerMBean">
<constructor-arg index="0" ref="dataSource"/>
<constructor-arg index="1" value="my.pool.connection:type=c3p0,name=Main"/>
<constructor-arg index="2" ref="mbeanServer"/>
</bean>
which the dataSource ref definition is a com.mchange.v2.c3p0.ComboPooledDataSource and defined like this:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" lazy-init="true" >
and a lot of datasource config
and the mbeanSever is a Spring org.springframework.jmx.support.MBeanServerFactoryBean which is defined like this:
<bean name="mbeanServer"
class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true" />
<property name="registerWithFactory" value="true"></property>
</bean>
The problem, as #SteveWaldman said, was I tried to register my datasources into MBean server which c3p0 registered them before. So what I should have done was nothing.
But there were some modification need to be done to what c3p0 registed.
c3p0 register datasource with a name like this:
com.mchange.v2.c3p0:type=PooledDataSource,identityToken=1hgeowz961y14x0ldebkgx|1‌​23f9b8,name=Main
I would like to avoid adding identityToken so as said here I create a c3p0.properties file and put this line into it:
com.mchange.v2.c3p0.management.ExcludeIdentityToken=true
That was pretty much everything I had to do for my case. Thanks to #StevenWaldman.

spring -- are beans in application context binded to PropertyPlaceholderConfigurer dynamically?

I want to know if beans in my application context are binded dynamically. Specifically, if I have
<bean id="mySpringRemoteService"
class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceInterface"
value="foo.bar.services.mySpringRemoteService" />
<property name="serviceUrl" value="${spring.remote.service.url}"/>
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:some.properties"/>
</bean>
if i change the property for the service url in my properties file, will retrieving the bean later reflect this change?
Well, I think it is easy for you to have a try yourself.
The answer is No (Unless behavior of Spring changed in 3.x )
I believe you have to implement runtime update behavior for config files. Take a look in Apache Commons Configurations.

<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.

Categories

Resources