I'm currently getting started on a project that uses spring-data in combination with JPA/Hibernate.
Right now, I'm injecting JpaRepositories using #Autowired annotations on the properties in question, e.g.:
#Component
public class EmployeeGenerator implements IDataGenerator {
...
#Autowired
private IEmployeeDao dao;
...
}
.. where IEmployeeDao is an interface extending JpaRepository that is annotated as #Repository:
#Repository
public interface IEmployeeDao extends JpaRepository<Employee, Integer> {
/**
* Finds employees by username.
*
* #param username the username
* #return the list of employees
*/
List<Employee> findByUsername(String username);
Everything works fine using this approach - However, I'm rather used to doing most of my spring configuration work in XML because I personally like the idea of all relevant confguration being in the same place and visible at the first glance.
Now, as far as I understand JPA and spring-data, the repository instances are somehow created by the JPA entity manager, so I should be able to specify them as beans in the spring config xml using.. some kind of factory method?
I guess I'm looking for something along the lines of:
<import resource="classpath:spring/db-context.xml"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="..."/>
<property name="dataSource" ref="..."/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>
</props>
</property>
</bean>
...
<bean id="employeeDaoImpl" class="IEmployeeDao">
<factory-method="?????"> <!-- Is something like this possible??? -->
</bean>
After some reading I guess that autowiring the repositories is the "recommended" approach, and I do see some benefits doing it like that,
but still, out of interest, I'd like to get it working with pure-xml configuration (or at least without #Autowired, that is)
You can declare the repositories using <jpa:repositories />. Then you can use the repository references in your XML configuration.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<repositories base-package="com.acme.repositories" />
</beans:beans>
In this case we instruct Spring to scan com.acme.repositories and all its sub packages for interfaces extending Repository or one of its sub-interfaces. For each interface found it will register the persistence technology specific FactoryBean to create the according proxies that handle invocations of the query methods. Each of these beans will be registered under a bean name that is derived from the interface name, so an interface of UserRepository would be registered under userRepository. The base-package attribute allows the use of wildcards, so that you can have a pattern of scanned packages.
You can read more about it in the docs: http://docs.spring.io/spring-data/jpa/docs/1.3.0.RELEASE/reference/html/repositories.html#repositories.create-instances
Related
I'm new to Spring and I'm wondering if its possible to use numerous transaction managers in the same application?
I have two data access layers - one for both of the databases. I'm wondering, how do you go about using one transaction managers for one layer and different transaction manager for the other layer. I don't need to perform transactions across both databases - yet. But I do need perform transactions on each database individually. I've created an image to help outline my problem:
Here is my application context configuration:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:component-scan base-package="cheetah.repositories" />
<tx:annotation-driven />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="accounts" />
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
Here is an example that uses this configuration:
#Repository
public class JpaAccountRepository implements AccountRepository {
#PersistenceContext(unitName = "cheetahAccounts")
private EntityManager accountManager;
#Override
#Transactional
public Account findById(long id) {
Account account = accountManager.find(Account.class, id);
return account;
}
}
So for the account repository, I want to use an entity manager factory with the persistence unit set to accounts. However, with my BusinessData Repository, I want to use an entity manager factory with a different persistence unit. Since I can only define one transaction manager bean, how can I go about using different transaction managers for the different repositories?
Thanks for any help.
Where you use a #Transactional annotation, you can specify the transaction manager to use by adding an attribute set to a bean name or qualifier. For example, if your application context defines multiple transaction managers with qualifiers:
<bean id="transactionManager1"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory1" />
<qualifier value="account"/>
</bean>
<bean id="transactionManager2"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory2" />
<qualifier value="businessData"/>
</bean>
You can use the qualifier to specify the transaction manager to use:
public class TransactionalService {
#Transactional("account")
public void setSomethingInAccount() { ... }
#Transactional("businessData")
public void doSomethingInBusinessData() { ... }
}
This Spring Jira entry discusses the issue a bit:
https://jira.spring.io/browse/SPR-3955
I think it could be one transaction manager per connection if you're not using two-phase commit. You just need to create two transaction managers and inject them with the appropriate connection.
But I must ask the question: why do you think you need two transaction managers? You can have more than one database connection. The DAOs that use the connections can and should be instantiated by different services, each of which can be annotated with their own transactional settings. One manager can accommodate both. Why do you think you need two?
I can't get #Transactional annotation to work with xml-defined bean. I don't know if xml definition has anything to do with it. Maybe it's the issue with OSGi.
<bean id="myDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager"/>
<property name="target" ref="myDao_t"/>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_MANDATORY,
timeout_60,
-Exception
</prop>
</props>
</property>
</bean>
When I specify a proxy with xml like above it works.
I have <tx:annotation-driven transaction-manager="txManager" /> specified in the same bundle-context.xml where the bean definition is.
MyDao is just a simple class implementing interface with one method.
There is no exception, it just doesn't create proxy for myDao.
What might be missing?
<bean id="myPlanner" class="com.something.planner.MyPlanner">
<property name="myDao" ref="myDao" />
</bean>
Try this:
The class of the bean myDao should be MyDao (the type of the DAO instead of TransactionProxyFactoryBean).
Put the annotation #Transactional on each public method in MyDao.java.
Spring should then automatically create a proxy for you. The approach in your question looks like "I try to create and configure the proxy factory myself".
While there surely is away to do that, I don't know exactly how you would do that. Instead, I rely on <tx:annotation-driven> and the #Transactional annotation.
EDIT You're using Spring 2.5.6A.
I just checked and #Transactional was added with Spring 1.2. But I'm not sure when <tx:annotation-driven> was added. The related EnableTransactionManagement was added with 3.1.
But the XML element is in this schema: http://www.springframework.org/schema/tx/spring-tx-2.5.xsd so it should be available in 2.5.
Maybe you're missing the necessary AOP libraries (cglib) on the classpath?
I am studyng Spring MVC and I have find this simple Hello World tutorial: http://www.tutorialspoint.com/spring/spring_hello_world_example.htm
In this tutorial the author creat a Bean Configuration file named Beans.xml, something like this:
<?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-3.0.xsd">
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
</beans>
Using tis file the Spring Framework can create all the beans defined and assign them a unique ID as defined in tag. And I can use tag to pass the values of different variables used at the time of object creation.
Is this the well know Bean Factory?
My doubt is related to the following thing: in my previous example I don't use a Bean Configuration file to define my bean, but I use the annotation to define what is a Spring bean and how this bean work (for example I use #Controller annotation to say Spring that a class act as a Controller Bean)
Use the bean configuration file and use the annotation have the same meaning?
Can I use both?
For example, if I have to configure JDBC can I configure it inside beans.xml file and at the same time can I use annotaions for my Controller class?
Tnx
Yes you can do that thing. Find a example below where controller has written with annotation and sessionFactory and data source has been created as xml bean which is wired into services -
<beans ...>
<!-- Controller & service base package -->
<context:component-scan base-package="com.test.employeemanagement.web" />
<context:component-scan base-package="com.test.employeemanagement.service"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
...
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<!-- <value>com.vaannila.domain.User</value> -->
<value>com.test.employeemanagement.model.Employee</value>
...
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
...
</props>
</property>
</bean>
...
</beans>
Services Example where SessionFactory is injected.
#Repository
public class EmployeeDaoImpl implements EmployeeDao {
#Autowired
private SessionFactory sessionFactory;
}
I hope it helps you. :)
You can use both bean configuration through xml and through annotation. You can even define your controller in xml configuration files.
Using the #Controller annotation allows you to use component scanning to find your bean. A Controller is a simple stereotype bean (that's why you can simply declare it your xml files).
More details about usage/semantic of #Controller here
I have a JSF 2.0 application and I am integrating Spring so I can make use of the hibernateTemplate. I already consulted the Spring documentation on JSF integration and have taken steps to set it up. All of my bean classes extend an abstract super class called SuperBean. SuperBean is the desired point of injection, saving me from having to declare all of my beans in Spring. I was hoping to just declare it as abstract="true" and any subclass bean extending the SuperBean class would have the dao injected. At runtime it is null.
<bean id="serviceTemplate" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="*"/>
</props>
</property>
</bean>
<bean id="daoServiceTarget" class="com.example.service.DaoService">
<property name="mainDAO" ref="mainDAO"/>
</bean>
<bean id="daoService" parent="serviceTemplate">
<property name="target" ref="daoServiceTarget"/>
</bean>
<bean id="superBean" class="com.example.beans.SuperBean" abstract="true">
<property name="daoService" ref="daoService"/>
</bean>
Am I able to simply declare this superclass SuperBean and expect Spring to inject the dao? I don't want to have to declare every bean class in spring.
I suppose the alternative option (from a performance perspective) would be to not use Spring beans but declare the DAO's as #applicationScoped and inject them into the SuperBean class using JEE's CDI. Would this be better performance-wise?
In the example above it looks serviceTemplate is providing an example of what you want. Note the parent="serviceTemplate". You need to do something similar to those who inherit from superbean. There are other options but since you have working code in the serviceTemplate that might be the best place to start. Then read here for more details:
I have a repository class that is created in XML like so:
<bean id="stuffRepositoryTarget" class="my.stuff.RepositoryImpl">
<!-- some params -->
</bean>
<bean id="stuffRepository" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" primary="true">
<property name="target" ref="stuffRepositoryTarget" />
<property name="transactionAttributes">
<prop key="*">PROPAGATION_REQUIRED</prop>
</property>
</bean>
And then I have a class that uses the repository like this:
#Autowired Repository repository;
It appears that the #Autowired annotation is referring to my Impl object and not my transaction interceptor. What am I doing wrong?
The most likely explanation is that the bean created by the TransactionProxyFactoryBean does not implement Repository.
Just checking, but Repository is an interface, right?
Another thing to try is to mark stuffRepositoryTarget with autowire-candidate="false", which will prevent it from being accidentally auto-wired.
There may be confusion over which bean to inject... Add a qualifier to your bean reference with which you can specify the exact bean id that you wish to have injected.
Something like:
#Qualifier("stuffRepository")
#Autowired Repository repository;