Project

General

Profile

Sample-spring-hibernate » History » Version 5

Henning Blohm, 18.09.2012 10:43

1 1 Henning Blohm
h1. A sample using Hibernate and Spring on Z2
2
3 2 Henning Blohm
This sample is very similar to [[Sample-hibernate-basic]] but differs in that we use the Spring framework throughout...
4
5
* for assembly within the modules and to wire services between modules
6
* for declarative transaction demarcation
7
* for JPA entity manager injection 
8
9 3 Henning Blohm
This is another practical application of [[How to Spring]].
10
11 2 Henning Blohm
This sample is stored in "z2-samples.spring-hibernate":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-hibernate.
12
13
h2. Prerequisites
14
15
You need the *z_tx_tests* database on a local MySQL database system. Start the MySQL client as the root user and run:
16
17
<pre><code class="SQL">
18
create database z_tx_tests;
19
grant all on z_tx_tests.* to tx@localhost identified by 'tx';
20
</code></pre>
21
22
h2. Run it
23
24
Like all samples, also this sample can be run as in [[How to run a sample]]. If you have the database, the fastest way to verify whether it runs is:
25
26
<pre><code class="ruby">
27
mkdir install
28
cd install 
29
git clone -b master http://git.z2-environment.net/z2-base.core
30
git clone -b master http://git.z2-environment.net/z2-samples.spring-hibernate
31
32
# on Linux / Mac OS:
33
cd z2-base.core/run/bin
34
./gui.sh
35
36
# on Windows:
37
cd z2-base.core\run\bin
38
gui.bat
39
</code></pre>
40
41
When running, go to http://localhost:8080/spring-hibernate. You should see this:
42
43
!spring-hibernate.png!
44 3 Henning Blohm
45
h2. Details
46
47
Similar to [[Sample-hibernate-basic]], the assumption of this example is that of a re-use domain module *com.zfabrik.samples.spring-hibernate.domain* that implements a "Thingy Repository" and is used from a web application that is in another module *com.zfabrik.samples.spring-hibernate.web*. The domain module exposes the Thingy Repository as a Z2 component - from a Spring application context defined bean -  that is imported into the application context of the Web application and injected into the controller filter by Spring. The controller uses declarative transaction demarcation.
48
49
The domain module makes use of Hibernate's JPA implementation using Spring's entity manager injection and integrates with the transaction management provided by *com.zfabrik.jta*.
50
51
h3. The domain module and its persistence context
52
53
The domain module *com.zfabrik.samples.spring-hibernate.domain* defines a persistence unit "thingies" in "java/src.impl/META-INF/persistence.xml":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-hibernate/revisions/master/entry/com.zfabrik.samples.spring-hibernate.domain/java/src.impl/META-INF/persistence.xml, i.e. in its implementation. That makes sense, as the XML file will be looked up with a class loader and we do not intent to retrieve from another module. Or, put differently, the persistence unit is not part of the module's API.
54
55
In order to integrate with the built-in transaction management the <code>persistence.xml</code> declares the JTA data source 
56
57
<pre><code class="xml">
58
<jta-data-source>components:com.zfabrik.samples.hibernate-basic.domain/DB</jta-data-source>
59
</code></pre>
60
61
and the _Transaction Manager Lookup_ 
62
63
<pre><code class="xml">
64
<property name="hibernate.transaction.manager_lookup_class" value="com.zfabrik.hibernate.TransactionManagerLookup" />
65
</code></pre>
66
67
The former points to the data source component "com.zfabrik.samples.spring-hibernate.domain/DB":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/DB.properties, while the latter makes sure Hibernate can register with the transaction manager implementation. 
68
69
The persistence unit defines only one entity. The Thingy as in "Thingy.java":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-hibernate/revisions/master/entry/com.zfabrik.samples.spring-hibernate.domain/java/src.api/com/zfabrik/samples/spring_hibernate/thingies/Thingy.java. That is an API-exposed type. We use the simplified pattern of exposing persistent objects in the API rather than using Data Transfer Objects (DTOs).
70
71
The application context of the module is defined in "java/src.impl/META-INF/applicationContext.xml":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-hibernate/revisions/master/entry/com.zfabrik.samples.spring-hibernate.domain/java/src.impl/META-INF/applicationContext.xml and looks like this:
72
73
<pre><code class="xml">
74
<?xml version="1.0" encoding="UTF-8"?>
75
<beans xmlns="http://www.springframework.org/schema/beans"
76
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
77
	xmlns:context="http://www.springframework.org/schema/context"
78
	xmlns:aop="http://www.springframework.org/schema/aop"
79
	xsi:schemaLocation="
80
	http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
81
	http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-3.0.xsd  
82
	http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
83
	http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
84
85
	<!-- annotation based config -->
86
	<context:component-scan base-package="com.zfabrik.samples.spring_hibernate" />
87
	<context:annotation-config />
88
89
	<!-- EntityManager injection -->
90
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
91
92
	<!-- The actual EMF we use -->
93
	<bean id="entityManagerFactory"	class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
94
		<property name="persistenceUnitName" value="thingies" />
95
	</bean>
96
    
97
</beans>
98
</code></pre>
99
100
In short: 
101
* We make sure we can use annotations
102
* We enable entity manager injection
103
* We initialize the entity manager factory from Spring
104
105
In the implementation class "ThingyRepositoryImpl":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-hibernaterevisions/master/entry/com.zfabrik.samples.spring-hibernate.domain/java/src.impl/com/zfabrik/samples/spring_hibernate/impl/thingies/ThingyRepositoryImpl.java we make use of these capabilities and declare a Spring bean "thingyRepository":
106
107
<pre><code class="java">
108
@Repository("thingiesRepository")
109
public class ThingyRepositoryImpl implements ThingyRepository {
110
	@PersistenceContext
111
	private EntityManager em;
112
113
	@Override
114
	public void store(Thingy thingy) {
115
		this.em.persist(thingy);
116
	}
117
118
	@SuppressWarnings("unchecked")
119
	@Override
120
	public Collection<Thingy> findAll() {
121
		return this.em.createQuery("select t from Thingy t").getResultList();
122
	}
123
124
	@Override
125
	public void delete(int id) {
126
		Thingy t = this.em.find(Thingy.class, id);
127
		if (t != null) {
128
			this.em.remove(t);
129
		}
130
	}
131
}
132
</code></pre>
133
134
In order to expose that bean as a Z2 component for re-use from other modules, we declare a component "com.zfabrik.samples.spring-hibernate/repository":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-hibernate/revisions/master/entry/com.zfabrik.samples.spring-hibernate.domain/repository.properties:
135
136
<pre><code class="ruby"> 
137
com.zfabrik.component.type=org.springframework.bean
138
139
#
140
# Expose Spring defined data source
141
#
142
143
#
144
# the context that defines the bean (more than one
145
# bean can be exposed like this)
146
#
147
bean.context=com.zfabrik.samples.spring-hibernate.domain/applicationContext
148
149
#
150
# the bean name
151
#
152
bean.name=thingiesRepository
153
</code></pre>
154
155
that is based on the application context component "com.zfabrik.samples.spring-hibernate/applicationContext":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-hibernate/revisions/master/entry/com.zfabrik.samples.spring-hibernate.domain/applicationContext.properties:
156
157
<pre><code class="ruby"> 
158
com.zfabrik.component.type=org.springframework.context
159
160
#
161
# context config location is where the context is 
162
# actually defined. 
163
#
164
context.contextConfigLocation=classpath:META-INF/applicationContext.xml
165
</code></pre>
166
167
See also [[How to Spring]] for more details on these component types.
168 4 Henning Blohm
169
h3. The web module, transaction boundaries, and service re-use
170
171
Let's turn to the Web application in *com.zfabrik.samples.spring-hibernate.web/web*. This one is also Spring configured. In contrast to the service module, its application context is not initialized from a Z2 component but rather from the Web app context (see "web/WebContent/WEB-INF/web.xml":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-hibernate/revisions/master/entry/com.zfabrik.samples.spring-hibernate.web/web/WebContent/WEB-INF/web.xml). It is stored in "web/WebContent/WEB-INF/applicationContext.xml":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-hibernate/revisions/master/entry/com.zfabrik.samples.spring-hibernate.web/web/WebContent/WEB-INF/applicationContext.xml and looks like this:
172
173
<pre><code class="xml">
174
<?xml version="1.0" encoding="UTF-8"?>
175
<beans xmlns="http://www.springframework.org/schema/beans"
176
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
177
	xmlns:context="http://www.springframework.org/schema/context"
178
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:security="http://www.springframework.org/schema/security"
179
	xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
180
	http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-3.0.xsd  
181
	http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
182
	http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
183
	http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
184
185
	<!-- Annotation Support -->
186
	<context:component-scan base-package="com.zfabrik.samples.spring_hibernate" />
187
	<context:spring-configured />
188
	<context:annotation-config />		
189
190
	<!--  
191
	This binds to java:comp/UserTransaction, which is ok in a Web app and considering
192
	that we configured Jetty JTA (see the transaction manager how-to in the Z2 Wiki and check environment/webServer/jetty.xml)
193
    -->
194
	
195
	<tx:jta-transaction-manager/>
196
197
    <!-- outside of a web app we would bind to com.zfabrik.jta transaction manager like this
198
199
	<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
200
	    <property name="userTransaction">
201
	        <bean class="com.zfabrik.tx.UserTransaction"/>
202
	    </property>
203
	</bean>
204
	 -->
205
206
	<!-- make sure we can use @transactional with the Spring aspect -->
207
	<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
208
209
	<!-- import external services -->
210
    <bean id="thingyRepository" class="com.zfabrik.springframework.ComponentFactoryBean">
211
        <property name="componentName"  value="com.zfabrik.samples.spring-hibernate.domain/repository" />
212
        <property name="className"  value="com.zfabrik.samples.spring_hibernate.thingies.ThingyRepository" />
213
    </bean>
214
	
215
</beans>
216
217
</code></pre>
218
219
In short:
220
221
* We enable annotation based configuration
222
* We make the transaction manager available (for in-depth details see [[How to transaction manager]])
223
* We enabled annotation based transaction demarcation (i.e. the use of <code>@transactional</code>)
224
* We import the Thingy Repository as a bean into this context.
225
226 5 Henning Blohm
The "ControllerFilter":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-hibernate/revisions/master/entry/com.zfabrik.samples.spring-hibernate.web/java/src.impl/com/zfabrik/samples/spring_hibernate/impl/web/ControllerFilter.java is configured by Spring, although it is instantiated by the Jetty Web container. That is happening because we use the Spring aspect (see [[How to Spring]] once more) and it is annotated with <code>@configurable</code>. We let Spring inject the Thingy Repository and we mark the <code>doFilter</code> method as transactional. Here is its skeleton:
227 4 Henning Blohm
228 5 Henning Blohm
<pre><code class="java">
229
@Configurable
230
public class ControllerFilter implements Filter {
231 4 Henning Blohm
232 5 Henning Blohm
  @Autowired
233
  private ThingyRepository thingyRepository;
234
	
235
  @Transactional
236
  public void doFilter(ServletRequest sreq, ServletResponse sres,	FilterChain chain) throws IOException, ServletException {
237
    
238
    // do some work here
239 1 Henning Blohm
240 5 Henning Blohm
  }
241
242
  @Override
243
  public void init(FilterConfig cfg) throws ServletException {}
244
  
245
  @Override
246
  public void destroy() {}
247
}
248
</code></pre>