Another CacheManager with same name 'cacheManager' already exists in the same VM - spring

I receive this error when starting tomcat with ehcache and Spring.
Another CacheManager with same name 'cacheManager' already exists in the same VM. Please
provide unique names for each CacheManager in the config or do one of following:
1. Use one of the CacheManager.create() static factory methods to reuse same
CacheManager with same name or create one if necessary
2. Shutdown the earlier cacheManager before creating new one with same name.
Spring 3.1
ehcache 2.9.0
No test context using this.
This is a web JSF app.
ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true"
monitoring="autodetect"
dynamicConfig="true"
name="ehcacheManager"
>
....
</ehcache>
cache-context.xml
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" scope="singleton">
<property name="shared" value="true"/>
<property name="configLocation">
<value>classpath:ehcache.xml</value>
</property>
</bean>
I do have and old dependency to hibernate-ehcache, that unfortunately I can not delete. Could this be the issue?
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>3.5.0-Final</version>
</dependency>
Any suggestions?
Thank you!

Some solutions are discussed here here
and you might need to provide a ehcache.xml or set the cache name otherwise as you can see here
Edit : ApplicationContext loaded twice
If you hit the breakpoint, go up the stacktrace and you may discover why spring is loading the context twice.

There are two possiblites.
someother application installed on the semesever with same cache name
Application may deployed twice when you start the server due to ContextLoaderListener. So remove ContextLoaderListener from your web.xml.

Following will solve the problem:
hibernate.cache.region.factory_class = org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
hibernate.cache.provider_class = net.sf.ehcache.hibernate.SingletonEhCacheProvider

Related

Configure singleton CacheManager for multiple web applications with Spring Caching

I have multiple web applications deployed in Tomcat and service jar shared in TOMCAT_HOME/lib/ext. All of the application are using Spring, and in the service jar I have beans, annotated with Spring 3.1 Caching annotations . I am using Ehcache provider. And I want to have one single CacheManager used by all the web applications. If I define spring cache configurations at web application level, caching works, but separate cacheManager is created for every app/context. 'Shared' Cache Manager is causing problems, because if one the those applications gets undeployed, this shared cacheManager is shut down. So I want a single CacheManager , configured in my service jar, and used for all the calls to methods made from beans from the web apps. My current try is to define following confuguration in service.jar's applicationContext.xml:
<context:annotation-config/>
<context:component-scan base-package="com.mycompany.app" />
<context:component-scan base-package="com.mycompany.portal.service" />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehCacheManager"/>
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="ehcache.xml" ></bean>
<cache:annotation-driven cache-manager="cacheManager"/>
I have defined parent application context via beanRefContext.xml:
<bean id="service.parent.context" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>applicationContext.xml</value>
</list>
</constructor-arg>
</bean>
And I am using this context as a parent context for all of my web apps with following contextParam in web app's web.xml:
<context-param>
<param-name>parentContextKey</param-name>
<param-value>service.parent.context</param-value>
</context-param>
The result is that this parentContext is loaded, but caching doesn't work at all
How can I solve this? Am I on the right way with the defining of the parentContext in the service.jar?
I don't think so. It looks like you are trying to have a single cache for multiple applications by "hacking" the root classloader.
If you need to share your cache across several applications, use a cache manager that supports that use case (i.e. that provides you a service you can reach from each application).

Loading Bean without explicitly referencing or retrieving it

In my application I use an XML Application Context to configure and build Spring beans.
I have a bean which is an observer and an observed bean. The configuration looks something like
<bean class="com.example.Observer">
<property name="observedBean">
<bean class="com.example.Observed" />
</property>
</bean>
My problem is, that there is nobody explicitly asking for a reference of the observer neither the observer nor the observed bean will be created.
Since there is no need of an explicit reference I would like to avoid just asking the ApplicationContext for a reference to just ignore it again.
Is there any solution for my problem or do I have a problem with my concept?

Multi-tenant webapp using Spring MVC and Hibernate 4.2.0.Final

I have developed a small webapp using and SpringMVC(3.1.3.RELEASE) and Hibernate 4.2.0.Final.
I'm trying to convert it to be a multi-tenant application.
Similar topics have been covered in other threads, but I couldn't find a definitive solution to my problem.
What I am trying to achieve is to design a web app which is able to:
Read a datasource configuration at startup (an XML file containing multiple datasource definitions, which is placed outside the WAR file and it's not the application-context or hibernate configuration file)
Create a session factory for each one of them (considering that each datasource is a database with a different schema).
How can i set my session factory scope as session? ( OR Can i reuse the same session factory ?) .
Example:
Url for client a - URL: http://project.com/a/login.html
Url for client b - URL: http://project.com/b/login.html
If client "a" make request,read the datasource configuration file and Create a session factory using that XML file for the client "a".
This same process will be repeating if the client "b" will send a request.
What I am looking, how to implement datasource creation upon customer subscription without editing the Spring configuration file. It needs to be automated.
Here is my code ,that i have done so far.
Please anyone tell me,What modifications i need to be made?
Please give an answer with some example code..I am quite new in spring and hibernate world.
Spring.xml
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}"
p:username="${jdbc.username}" p:password="${jdbc.password}" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
JDBC.properties File
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.dialect=org.hibernate.dialect.MySQLDialect
jdbc.databaseurl=jdbc:mysql://localhost:3306/Logistics
jdbc.username=root
jdbc.password=rot#pspl#12
hibernate.cfg.xml File
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping class="pepper.logis.organizations.model.Organizaions" />
<mapping class="pepper.logis.assets.model.Assets" />
</session-factory>
</hibernate-configuration>
Thanks,
First create a table for Tenant with tenant_id and associate it with all users.Now, you can fetch this details while the user logs in and set it in session.
We are using AbstractRoutingDataSource to switch DataSource for every request on Spring Boot. I think it is Hot Swapable targets/datasource mentioned by #bhantol above.
It solves our problems but I don't think it is sound solution. I guess JNDI could be a better one than AbstractRoutingDataSource.
Wondering what you ended up with.
Here are some ideas for you.
Option 1) Single Application Instance.
It is somewhat ambitious to to this using what you are actually trying to achieve.
The gist is to simply deploy the same exact application with different context root on the same JVM. You can still tune the JVM as a whole like you would have if you had a truely multi-tenant application. But this comes at the expense of duplication of classes, contexts, local caching, start up times etc.
But as of today the Spring Framework 4.0 does not provide much of an multi-tenancy support (other than Hot Swapable targets/datasource) etc. I am looking for a good framework but it may be a wash to move away from Spring at this time for me.
Option 2) Multiple deployments of same application (more practical as of today)
Just have your same exact application deploy to the same application server JVM instance or even different.
If you use the same instance you may now need to bootstrap your app to pickup a DataSource based on what the instance should serve e.g. client=a property would be enough to pickup a **a**DataSource" or **b**DataSource I myself ended up going this approach.
If you have a different application server instance you could just configure a different JNDI path and treat things generically. No need for client="a" property because you have liberty to define your datasource differently with the same name.

context:property-placeholder doesn't resolve references

I have next applicationContext.xml file on the root of classpath:
<context:annotation-config />
<context:property-placeholder location="classpath:props/datasource.properties" />
<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource"
p:username="${jdbc.username}"
p:password="${jdbc.password}"
p:url="${jdbc.url}"
p:driverClassName="${jdbc.driverclass}"
p:validationQuery="SELECT sysdate FROM dual" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="datasource"
p:mapperLocations="classpath:mappers/*-mapper.xml" />
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="datasource" />
<bean id="mappeScannerConfigurere" class="org.mybatis.spring.mapper.MapperScannerConfigurer"
p:sqlSessionFactory-ref="sqlSessionFactory"
p:basePackage="com.mypackage" />
props/datasource.properties also exists on the root of classpath with such content:
jdbc.url=myjdbcurl
jdbc.driverclass=myClass
jdbc.username=myUserName
jdbc.password=myPassword
I have a spring managed test where I declare to use previously mentioned applicationContext.xml via next annotations:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
When I invoke test method i get next error from spring:
org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class '${jdbc.driverclass}'
As I understand sping didn't resolve reference to jdbc.driverclass.
What have I done wrong?
PS: I'm using spring 3.2.3.RELEASE
**
EDIT
**
Perhaps the problem may be in MapperScannerConfigurer. It is a BeanDefinitionRegistryPostProcessor and as Javadoc says:
Extension to the standard BeanFactoryPostProcessor SPI,
allowing for the registration of further bean definitions
before regular BeanFactoryPostProcessor detection kicks in
So MapperScannerConfigurer instantiates datasource object via sqlSessionFactory with BeanFacoryPostProcessor(which is responsible for <context:property-placeholder/>) have not been utilized.
So my question transforms to how to reorder BeanFacoryPostProcessor from <context:property-placeholder/> and BeanDefinitionRegistryPostProcessor(MapperScannerConfigurer)?
Resolved
After a couple hours of investigation I found the solution:
As I said earlier MapperScannerConfigurer is a BeanDefinitionRegistryPostProcessor which fires before BeanFactoryPostProcessor which is responsible for <context:property-placeholder/>. So, during the creation of MapperScannerConfigurer references to external properties will not be resolved. In this case we have to defer the creation of datasource to the time after BeanFactoryPostProcessorhave been applied. We can do that in several ways:
remove p:sqlSessionFactory-ref="sqlSessionFactory" from MapperScannerConfigurer. In this case datasource object will not be created before MapperScannerConfigurer, but after BeanFactoryPostProcessor which is responsible for <context:property-placeholder/>. If you have more than one sqlSessionFactory in applicationContext, than can be some troubles
In versions of mybatis-spring module higher than 1.0.2 there is a possibility to set sqlSessionFactoryBeanName instead of sqlSessionFactory. It helps to resolve PropertyPlaceHolder issue with BeanFactoryPostProcessor. It is a recommended way to solve this issue described in mybatis-spring doc
I was having the same issue and came across this post but I was unable to resolve it the same way maks did. What ended up working for me was to set the ignoreUnresolvablePlaceholders property value to true.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:database.properties</value>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
I am using Spring 3.2.3.RELEASE as well. I realize this post is over 4 months old but I figured someone might find it useful.
Short form: What is the proper way to load an implementation of: BeanDefinitionRegistryPostProcessor?
Expanded form: Is there a way to load BeanDefinitionRegistryPostProcessor before any beans have been created. If you look at the javadoc:
Extension to the standard {#link BeanFactoryPostProcessor} SPI, allowing for
the registration of further bean definitions before regular
BeanFactoryPostProcessor detection kicks in.
So it's meant to be loaded when bean definitions have been created but before any beans have been created. If we just create it as a regular bean in the application xml then it defeats the purpose of having this bean in the first place.

external config based on context path

I would like to deploy multiple independent copies of a particular web-app on the same tomcat server under different context paths. Each web-app will need different configuration settings (database name, password, etc), but I would like to keep the wars exactly identical.
My plan was to have the app figure out its context path on startup, then read a specific .properties file outside of tomcat identified by the context path. For example, if a war was deployed to {tomcat path}/webapps/pineapple, then I would want to read /config/pineapple.properties
I've been trying to find a way to inject an instance of ServletContext via spring (3), but all the advice I've seen so far use the deprecated ServletContextFactoryBean.
Is there a better way to get the context path injected or better way to load external files based on the context path?
With the help of ServletContextAttributeFactoryBean and Spring EL, you can reference ServletContext init parameters (<context-param> in web.xml) like that:
#{contextAttributes.myKey}
This allows you to use PropertyPlaceHolderConfigurer and load property files from arbitrary, user-defined locations:
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="#{contextParameters.APP_HOME}/conf/app.properties"/>
</bean>
The corresponding definition of the ServletContext init parameter in Tomcat's context.xml:
<Parameter name="APP_HOME" value="file:/test" override="false"/>
Or in your app's web.xml:
<context-param>
<param-name>APP_HOME</param-name>
<param-value>file:/test</param-value>
</context-param>
This should be the solution.
<bean name="envConfig" class="EnvironmentConfiguration">
<property name="locations">
<list>
<value>file:///#{servletContext.contextPath}.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
Extend Propertyplaceholderconfigurer to use DB to pick up the values. Example here
Load the actual values of the settings (database name, password etc) to the db as part of seed data
When your web-app's app ctx is being initialized, the properties are resolved from the DB
This is the approach we have been following and works great. If you can switch to Spring 3.1 then it has support for Environment Profiles which may be useful for you.

Resources