How can I create bean definition of multiple classes in spring? I know the spring TS helps to create bean definition but can it used to create for multiple classes at one time?
<bean id="class1" class="com.test.Class1">
</bean>
<bean id="class2" class="com.test.Class2">
</bean>
<bean id="class3" class="com.test.Class3">
</bean>
Yes, following bean configuration file is perfectly valid:
<bean id="class1a" class="com.test.Class1">
</bean>
<bean id="class1b" class="com.test.Class1">
</bean>
You will get 2 instances of Class1 with different bean name. You just need to be careful when autowiring (esp. by type)
Related
I'm working on an existing Spring application that uses JDBC (DAO's extend NamedParameterJdbcDaoSupport). There were four datasources configured, each with it's own DataSourceTransactionManager. (though only one was registered with tx:annotation-driven for some reason)
I've recently added JPA (Spring-data-JPA) into the application and configured two entityManagerFactories (for now I don't need the other two datasources). I also configured two JpaTransactionManagers and removed the corresponding DataSourceTransactionManagers for these dataSources, since the JpaTransactionManagers can also be used for JDBC transactions. (correct me if I'm wrong)
It appears I need to be able to have distributed transactions, since the two datasources (to two different databases) need to be accessed (through JPA) in one service method. Since I did not have all I need to set up JTA (missing XA-driver for one of the databases) I've decided to give the Spring ChainedTransactionManager a try. Sadly this didn't work out as expected. All works fine if I just call a service method that only uses JPA.
Though when I call an existing service method that uses a JDBC find that has a class level #transactional annotation with it's propagation set to NOT_SUPPORTED and call another service method after that with a JPA call and a #transactional, I get an exception:
Caused by: java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder#462cf9d9] for key [org.jboss.jca.adapters.jdbc.WrapperDataSource#3fbb4c32] bound to thread [http-/127.0.0.1:8080-5]
at org.springframework.transaction.support.TransactionSynchronizationManager.bindResource(TransactionSynchronizationManager.java:189) [spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:403) [spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
After some debugging, I found out that the transactions in Spring get added to a map on a ThreadLocal in the "TransactionSynchronizationManager.bindResource" method. The problem is that when using a JDBC call with #transactional and propogation NOT_SUPPORTED, a transaction is made anyway and registered through that method. When the JpaTransactionManager tries to bind it's resource, it is already on the map (and not marked as void) which causes the error to occur.
Changing the propagation to the default "REQUIRED" for the service call that encapsulates the JDBC call fixes the problem.
I have no idea why Spring is still creating that transaction when the transactional annotation is NOT_SUPPORTED. And if it creates that transaction, it should not bypass the JpaTransactionManager.
So what I'd like to know is if there is some way to tell Spring to use the JpaTransactionManager also when it creates a transaction itself inside the NamedParameterJdbcDaoSupport. (Well actually the JdbcDaoSupport... Well actually the DataSourceUtils)
We're using Spring 3.2.5, spring-data-jpa 1.6.0 and I've used Hibernate 4.2.0 as JpaVendor.
This problem doesn't occur without the ChainedTransactionManager.
Datasources:
<bean id="dataSourceCompta" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/datasources/comptaDS"/>
</bean>
<bean id="dataSourceUnisys" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/datasources/insoverDS"/>
</bean>
<bean id="dataSourceInsoverwebMysql" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/datasources/insoverWebDS"/>
</bean>
<bean id="dataSourceBatch" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/datasources/batchDS"/>
</bean>
Single remaining JDBC transaction manager (no JPA counterpart):
<bean id="transactionManagerBatch" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceBatch"/>
</bean>
JPA Transaction Managers:
<bean id="jpaUnisysTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryUnisys"/>
<qualifier value="unisys" />
</bean>
<bean id="jpaMysqlTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryMysql"/>
<qualifier value="mysql" />
</bean>
My ChainedTransactionManager:
<bean id="chainedTransactionManager" class="org.springframework.data.transaction.ChainedTransactionManager">
<constructor-arg>
<list>
<ref bean="jpaUnisysTransactionManager" />
<ref bean="jpaMysqlTransactionManager" />
</list>
</constructor-arg>
</bean>
JPA Entity manager factories:
<bean name="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<bean id="entityManagerFactoryUnisys" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/some-persistence.xml"/>
<property name="dataSource" ref="dataSourceUnisys"/>
<property name="persistenceUnitName" value="unisysPU"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<!-- properties -->
</property>
</bean>
<bean id="entityManagerFactoryMysql" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/some-persistence.xml"/>
<property name="dataSource" ref="dataSourceCompta"/>
<property name="persistenceUnitName" value="mysqlPU"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<!-- properties -->
</property>
</bean>
For now I've "fixed" this, by changing all the class-level transactional annotations to have propagation.REQUIRED (default) instead of NOT_SUPPORTED. Though I do not really like this solutions, since it might be somebody set those propagations to NOT_SUPPORTED with a good reason. I've also tried SUPPORTED, but using that had the same issue as NOT_SUPPORTED: a transaction was being made anyway by the Spring DataSourceUtils when the query was being executed by the NamedParameterJdbcDaoSupport DAO.
When no transactional annotation is set on the service, all works well too.
i build async jersey web services, and now i need to make some operations with ldap.
I have configure Spring beam.xml in this mode:
<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="${ldap.url}" />
<property name="base" value="${ldap.base}" />
<property name="userDn" value="${ldap.userDn}" />
<property name="password" value="${ldap.password}" />
<property name="pooled" value="false" />
</bean>
<bean id="contextSource"
class="org.springframework.ldap.pool.factory.PoolingContextSource">
<property name="contextSource" ref="contextSourceTarget" />
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<bean id="ldapTreeBuilder" class="com.me.ldap.LdapTreeBuilder">
<constructor-arg ref="ldapTemplate" />
</bean>
<bean id="personDao" class="com.me.ldap.PersonDaoImpl">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
But when i try to use ldap i have this error:
Error creating bean with name 'contextSource' defined in class path resource [config/Beans.xml]: Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool/KeyedPoolableObjectFactory
In my project i have commons-pool2-2.2.jar lib, but still i have this error..i try to add commons-pool2-2.2.jar in TOMCAT_PATH/lib but not works..
UPDATE:
If i put commons-pool-1.6.jar it works.. but if i want to use pool2 how i can do? only i must change class inn commons-pool2-2.2.jar?
Updated Answer:
Since at least Spring LDAP 2.3.2 you can now use commons-pool2. Spring LDAP now provides two classes:
For commons-pool 1.x:
org.springframework.ldap.pool.factory.PoolingContextSource
For commons-pool 2.x:
org.springframework.ldap.pool2.factory.PooledContextSource
Details can be found here:
https://github.com/spring-projects/spring-ldap/issues/351#issuecomment-586551591
Original Answer:
Unfortunately Spring-Ldap uses commons-pool and not commons-pool2. As you have found the class org.apache.commons.pool.KeyedPoolableObjectFactory does not exist in commons-pool2 (it has a different package structure), hence the error.
There is a Jira issue for the Spring-ldap project asking them to upgrade/support commons-pool2:
https://jira.spring.io/browse/LDAP-316
Until that has been completed you will have to use commons-pool 1.6.
I'm developping an application using spring and hibernate.
When I run my application I get this error message:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'transactionManager' is defined
In my context application file I have this :
<bean id="tansactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
I googled about the problem and I found a solution that I have to change this line :
<bean id="tansactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
By :
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
But I got another problem :
org.springframework.beans.NotWritablePropertyException: Invalid property 'sessionFactory' of bean class [org.springframework.orm.jpa.JpaTransactionManager]: Bean property 'sessionFactory' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
How can I solve this problem ?
You have a typo in your annotation "tansactionManager" is missing and 'r', "transactionManager". I made the correction and it worked just fine for me.
If you are using session factory, so this should work
<bean id="tansactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
but if you want to use JPA EntityManager, so you need
<bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
Please refer to migrating-to-spring-3-1-and-hibernate-4-1 it contains nice example for the required configurations
I am working on a Spring WebFlow project which has a lot of property values in XML files, as any Spring programmer knows. I have database user names, password, URLs, etc.
We are using Eclipse with Spring WebFlow and Maven. We are trying to have an SA do the builds but the SA does not want to go into the XML files to change the values, but on the other hand, we don't know the production values. How do we work with this?
Most SA are more willing and confident to deal with .properties file rather than .xml.
Spring provide PropertyPlaceholderConfigurer to let you define everything into one or several .properties file and substitute the placeholder in applicationContext.xml.
Create a app.properties under src/main/resources/ folder:
... ...
# Dadabase connection settings:
jdbc.driverClassName=org.postgresql.Driver
jdbc.url=jdbc:postgresql://localhost:5432/app_db
jdbc.username=app_admin
jdbc.password=password
... ...
And use PropertyPlaceholderConfigurer in applicationContext.xml like so:
... ...
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>app.properties</value>
</property>
</bean>
... ...
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<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>
Check out Spring PropertyPlaceholderConfigurer Example for more details.
In addition, from application deployment perspective, we usually package app in some executable format and the .properties files are usually packed inside the executable war or ear file. A simple solution is to configure your PropertyPlaceholderConfigurer bean to resolve properties from multiple location in a pre-defined order, so in the deployment environment, you can use a fixed location or environment variable to specify the properties file, also note that in order to simplify the deploy/configure task for SA, we usually use a single external .properties file define all runtime configuration, like so:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<!-- Default location inside war file -->
<value>classpath:app.properties</value>
<!-- Environment specific location, a fixed path on server -->
<value>file:///opt/my-app/conf/app.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true"/>
</bean>
Hope this helps.
Another simple way is Spring Expression Language (SpEL)
for example
<property name="url" value="#{ systemProperties['jdbc.url'] }" />
Documentation
spring documentations
Also you can define a propertyConfigurer programmatically in configuration class:
#Configuration
#PropertySource("classpath:application.properties")
public class PropertiesConfiguration {
#Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(Environment env) {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setEnvironment(env);
return configurer;
}
}
I am trying modify default ValidationMessages.properties to other. But I not get it.
My setup:
In Spring.
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>text</value>
<value>error</value>
</list>
</property>
</bean>
<bean name="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationMessageSource">
<ref bean="messageSource"/>
</property>
</bean>
In text.properties and tex_XX.properties.
edit.profile.password.size=Password must be between {min} and {max}
Annotation example.
#Size(min=4, max=8, message="{edit.profile.password.size}")
You should have Hibernate Validator 4.1 or higher on the classpath even if you use a different validation provider.