Project

General

Profile

How to Spring » History » Version 52

Henning Blohm, 08.11.2013 22:28

1 39 Henning Blohm
h1. How to use the Spring framework in Z2
2 16 Henning Blohm
3 37 Henning Blohm
There is actually nothing really particular about using Spring in Z2. But when knowing how Z2 modularity works, there is much to gain by spending a few minutes reading this Howto. We assume however that you are familiar with the Spring framework as such.
4 2 Henning Blohm
5 35 Henning Blohm
It may be best to inspect the the basic [[sample-spring-basic]] sample in parallel to reading this page, as that makes use of most of what you will find here and is still really simple. Plus, running the sample requires no more than Eclipse and five minutes of your time.
6
7 44 Henning Blohm
Please also check the add-on page [[Spring add-on]].
8
9 38 Henning Blohm
h2. Pre-requisites
10 1 Henning Blohm
11 43 Henning Blohm
In order to have the Spring libraries available you need to add the add-on [[Spring add-on]] via the repository "z2-addons.spring":http://redmine.z2-environment.net/projects/z2-addons/repository/z2-addons-spring to your environment (the samples do so in their _environment_).  To use the master branch version, add a *springRepository.properties* component descriptor to your *environment* module saying
12 2 Henning Blohm
13 17 Henning Blohm
<pre><code class="python">
14 15 Henning Blohm
com.zfabrik.systemStates.participation=com.zfabrik.boot.main/sysrepo_up
15 3 Henning Blohm
16
# git stored component repository
17
com.zfabrik.component.type=com.zfabrik.gitcr
18
19
# true <=> optional repository. If gitcr.uri is invalid, then this gitcr will be ignore silently  
20
gitcr.optional=true
21
22
# this can also point to a remote repository like 
23
# ssh://myserver/some/git/repo
24
gitcr.uri=http://git.z2-environment.net/z2-addons.spring
25
26
# the git branch to use (e.g. 'master')
27
gitcr.branch=master
28
</code></pre>
29 15 Henning Blohm
30 3 Henning Blohm
For your own system, you may need to adapt the repository URL and the branch selection accordingly.
31
32 45 Henning Blohm
If that sounds like meaningless gibberish to you - sorry! Please consult the documentation at http://www.z2-environment.eu/v21doc and go back to [[First_steps_with_z2]].
33 3 Henning Blohm
34
35 9 Henning Blohm
When you added that repository the following modules are available:
36 4 Henning Blohm
37
* org.springframework.orm
38
* org.springframework.security
39
* org.springframework.foundation   
40
* org.springframework.transaction
41
* org.springframework.jdbc         
42
* org.springframework.web
43
* com.zfabrik.springframework      
44
* com.zfabrik.springframework.web  
45
46 1 Henning Blohm
47
With the exception of those starting with "com.zfabrik", these do, more or less, correspond to the typical Spring modules found out there. 
48
49 18 Henning Blohm
Before you get frustrated by the amount of details in this Howto, please remember that there is practical samples available to help you check how things can really be assembled to work nicely:
50 10 Henning Blohm
51 40 Henning Blohm
* [[sample-spring-basic]]
52
* [[sample-jta-spring]]
53 10 Henning Blohm
54 38 Henning Blohm
h2. Using Spring in Web applications
55 2 Henning Blohm
56
This is the simplest and really just the standard case. If you do not strive for re-use across modules that use Spring, then there is not much to worry about. 
57 5 Henning Blohm
58
As usual, you define an application context in the WEB-INF folder of the Web application and set up a context listener in WEB-INF/web.xml to have the application 
59
context initialized as the Web app is started.
60
61
In order to have the minimal set of dependencies satisfied - i.e. not assuming you want to use the (very cool) AspectJ based Spring configuration, you should _add_ (i.e. augment whatever refs you already have) the following references to *java/z.properties*:
62
63 17 Henning Blohm
<pre><code class="python">
64 5 Henning Blohm
java.privateReferences=\
65
	com.zfabrik.springframework.web,\
66
	org.springframework.foundation,\
67
	org.springframework.web
68
69 11 Henning Blohm
</code></pre>
70 5 Henning Blohm
71
The reference to *com.zfabrik.springframework.web* is not strictly needed but adds the following capabilities:
72
73 7 Henning Blohm
* You implicitly get *com.zfabrik.springframework*, i.e. the integration features described below
74 5 Henning Blohm
75 7 Henning Blohm
* You can use a parent application context to your Web application application context as easily as you would hope (see below).
76
77
78 19 Henning Blohm
h2. Using Spring Context Support
79 7 Henning Blohm
80 19 Henning Blohm
The module *org.springframework.foundation* holds a Java component *org.springframework.foundation/context.support* that is not meant to be referenced but to be _included_.
81
Including a Java component means that it's resources (class files, jars,...) will be copied into the including scope rather than referenced via class loader delegation.
82 7 Henning Blohm
83 19 Henning Blohm
The difference is that in that case, all the includer sees is also be seen by the types in the included component. And that is exactly what context.support is about: It holds adapter classes that effectively have dangling dependencies on other prominent libraries. Say for example we are talking about the Lucene search engine library. If your Java component references the Lucene libs (which are not included with Z2 by default), and say you want to use the Spring adapter types, then include context.support by adding (i.e. customizing correspondingly) the private include:
84
85
<pre><code class="python">
86
java.privateIncludes=\
87
   org.springframework.foundation/context.support
88
</code></pre>
89
90
Typically it makes most sense to only use _private includes_. If you include into the API, which is possible, other modules that reference your API will find the included types
91
of your API with preference of their includes (as part of the parent-first delegation principle). So, they may not be able to repeat the same include pattern described above. 
92
93 49 Henning Blohm
h2. Spring stuff that requires includes
94
95
Several Spring use cases require the use of includes (more below). Among these are:
96
97
|_. Use case|_. What to private-include|_.Why|
98
|Spring context support|org.springframework.foundation/context.support|Dangling imports in spring lib|
99
|Spring AspectJ|org.springframework.foundation/aspects|Class loader bound application context (must be kept on scope - see below)|
100
|Spring Security|org.springframework.security/{config,ldap,...}|Dangling imports in spring lib|
101
102
103 38 Henning Blohm
h2. Using Spring in re-use modules
104 19 Henning Blohm
105 20 Henning Blohm
When going modular, you will leave the pure "Spring in a Web Application" path. That is, you may want to use Spring in modules that expose components and APIs to other modules. For example to implement shared services that are used in more than one Web Application, or for example to implement scheduled job execution.
106
107 22 Henning Blohm
*Define an Application Context in a Java Module*
108 20 Henning Blohm
109
In that case, you will not define an application context in a WEB-INF folder (as there most likely is none) but instead you will define a class path defined application context, or more specifically you will put your application context (most likely) in *java/src.impl/META-INF/applicationContext.xml* of your re-use module.
110
111 22 Henning Blohm
*Starting an Application Context*
112 1 Henning Blohm
113 21 Henning Blohm
Now that you have that application context, you need to make sure it is started. If you went this far, there is good reasons you use Z2 runtime dependencies to start it. Pre-requisite for that is to have the application context declared as a Z2 component. So you create a file *applicationContext.properties* in your module saying
114
115
<pre><code class="python">
116
com.zfabrik.component.type=org.springframework.context
117
118
#
119
# context config location is where the context is 
120
# actually defined. 
121
#
122
context.contextConfigLocation=classpath:META-INF/applicationContext.xml
123 1 Henning Blohm
</code></pre>
124
125 22 Henning Blohm
Once it is defined as a component, you can have it started via a "system state dependency":http://www.z2-environment.eu/v20doc#System%20States%20(core), via a "generic component depencency":http://www.z2-environment.eu/v20doc#CoreComponentProps.
126
127
Another way is to have it started implicitly from a bean component declaration. In that case, before providing the bean instance, the application context will be initialized.
128 19 Henning Blohm
129 38 Henning Blohm
*Exposing a bean from an application context*
130 23 Henning Blohm
131
Now that you have declared an application context component, you can actually expose beans from it as Z2 components that may be looked up from other modules. To do so, create a component like this:
132
133
<pre><code class="python">
134
com.zfabrik.component.type=org.springframework.bean
135
136
#
137
# the context that defines the bean (more than one
138
# bean can be exposed like this)
139
#
140 24 Henning Blohm
bean.context=<module name>/applicationContext
141 23 Henning Blohm
142
#
143
# the bean name
144
#
145 25 Henning Blohm
bean.name=<bean name>
146 23 Henning Blohm
</code></pre>
147
148
Now that a bean has been made available to other modules, the next natural question is how to actually refer to a Z2 component from a Spring application context.
149
150 38 Henning Blohm
*Importing a bean or just any component*
151 1 Henning Blohm
152 25 Henning Blohm
The module *com.zfabrik.springframework* contains a factory bean that just does that. Assuming you want to use component &lt;module&gt;/&lt;name&gt; which is of type (or has super type) my.Class, you would add to your importing application context:
153 1 Henning Blohm
154 25 Henning Blohm
<pre><code class="xml">
155
<bean id="beanId" class="com.zfabrik.springframework.ComponentFactoryBean">
156
  <property name="componentName" value="<module>/<name>" />
157
  <property name="className" value="my.Class" />
158
</bean>
159
</code></pre>
160 23 Henning Blohm
161 26 Henning Blohm
Ok, so far so good. Next subject is how to add more configuration magic to all of this.
162 2 Henning Blohm
163 38 Henning Blohm
h2. Using Spring's AspectJ configuration
164 1 Henning Blohm
165 27 Henning Blohm
By default, Spring's annotation support reaches as far as Spring "can see". That is, objects instantiated outside of Spring's control will not be subject to Spring configuration - simply because Spring had no chance to look at it. 
166 1 Henning Blohm
167 46 Udo Offermann
When using Spring's AspectJ feature, Spring's configuration reach can be extended to virtually anything within the implementation scope. Normally, configuring your build to include the AspectJ compilation can be tricky and tiring. The alternative of using load-time-weaving is rather error-prone as types may not have been loaded before the aspect has been registered - something where you can so easily fool yourself.
168 27 Henning Blohm
169 48 Henning Blohm
Fortunately for you, the Spring integration features of Z2 also provide a compiler extension for Spring with AspectJ. To use it, you need to modify your *java/z.properties* to reflect the following includes and refs and in particular the compiler settings:
170 27 Henning Blohm
171
<pre><code class="python">
172
java.privateReferences=\
173
	com.zfabrik.springframework,\
174
	org.springframework.foundation,\
175
	org.springframework.orm,\
176
	org.springframework.transaction
177
178
java.privateIncludes=\
179
	org.springframework.foundation/aspects
180
181
	
182
java.compile.order=java,spring_aspectj
183
</code></pre>
184
185
The refs to spring transaction and spring ORM look unintuitive. And they are. At the time of this writing the Spring aspect unfortunately still required those.
186
187 41 Henning Blohm
When you have applied the configuration above, you can make any type Spring configurable by annotating it with <code>@Configurable</code>. For example the "ControllerServlet":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.frontend/java/src.impl/com/zfabrik/samples/impl/frontend/ControllerServlet.java in the sample *z2-samples.spring-basic* has the following skeleton:
188 27 Henning Blohm
189
<pre><code class="java">
190 1 Henning Blohm
@Configurable
191 41 Henning Blohm
public class ControllerServlet extends HttpServlet {
192
        @Autowired
193
        private IComputationService computations;
194 27 Henning Blohm
195 41 Henning Blohm
        @Override
196
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
197
            //...
198
        }
199
200 27 Henning Blohm
}
201 41 Henning Blohm
202 27 Henning Blohm
</code></pre>
203 26 Henning Blohm
204 50 Henning Blohm
Now that all complexity of AspectJ compilation is completely out of the way, using Spring AspectJ can realize all its advantages over regular Spring AOP. Most notably, Spring AspectJ does not require proxy objects as Spring AOP does. This has a lot of simplifying implications. For example, annotations like @Transactional now work regardless of who is calling (inside or outside) and what methods are annotated. Similarly, other annotations such as those of Spring security work as naively expected. 
205 1 Henning Blohm
206 50 Henning Blohm
*Simply put: Spring AspectJ does it right where Spring AOP could not due to technical limitations.*
207
208
The whole subject is not completely trivial. For a deeper understanding we suggest to read:
209
210
* "Aspect Oriented Programming with Spring (Springsource)":http://docs.spring.io/spring/docs/2.5.x/reference/aop.html#aop-ataspectj
211
* "A starting point for pro and cons discussion (Stackoverflow)":http://stackoverflow.com/questions/1606559/spring-aop-vs-aspectj
212
* "Pitfalls of Spring proxying (external blog)":http://nurkiewicz.blogspot.de/2011/10/spring-pitfalls-proxying.html
213
214
h3. Making sure to configure for Spring AspectJ correctly
215
216
In order to avoid proxying when using Spring AspectJ, which you should to have one consistent approach, make sure that you apply a @mode="aspectj"@ attribute where possible.
217
218
This includes:
219
220
* the @<tx:annotation-driven/>@ annotation. Make sure it reads @<tx:annotation-driven mode="aspectj"/>@ (and possibly other attributes)
221
* the @<security:global-method-security/>@ annotation. Make sure it reads @<security:global-method-security mode="aspectj"/>@ (and possibly other attributes)
222
223
Use of the Spring aspects require to include the matching aspect libraries. In particular:
224
225
* When using Spring security aspects, add @org.springframework.security/aspects@ to your private includes
226
227
For example, an advanced Spring usage java component configuration may look like this:
228
229
<pre><code class="python">
230
com.zfabrik.component.type=com.zfabrik.java
231
java.privateReferences=\
232 52 Henning Blohm
    org.springframework.foundation,\
233
    org.springframework.orm,\
234
    org.springframework.web,\
235
    org.springframework.transaction,\
236
    org.springframework.security
237 50 Henning Blohm
238
java.privateIncludes=\
239
    org.springframework.security/config,\
240
    org.springframework.security/aspects,\
241
    org.springframework.security/taglibs,\
242
    org.springframework.security/web,\
243
    org.springframework.foundation/aspects,\
244
    org.springframework.foundation/context.support
245
246 51 Henning Blohm
#
247
# enables the processing of @Secured annotations in the implementation
248
#
249
aspectj.privateAspectPathByClass=\
250
	org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect
251
	
252
253 50 Henning Blohm
java.compile.order=java,spring_aspectj
254
</code></pre>
255 51 Henning Blohm
256
See also 
257
* "AspectJCompiler":http://www.z2-environment.net/javadoc/com.zfabrik.springframework!2Fjava/impl/com/zfabrik/impl/springframework/AspectJCompiler.html
258
* [[sample-spring-basic]] that also contains a Spring Security part.
259 50 Henning Blohm
260
261
h3. More important things to know about Spring with AspectJ
262
263 28 Henning Blohm
As always, there is some important pitfalls to watch out for. The Spring AspectJ integration roughly works as follows: 
264
265 1 Henning Blohm
# When an application context is loaded that has &lt;context:spring-configured /&gt; and the Spring aspect classes are on the classpath (i.e. can be found by the class loader of the application context), then the current application context will be set as a static class variable of one Spring aspect implementation class.
266 29 Henning Blohm
# Later, when a configurable object is being instantiated, the woven-in code will look for that static class variable to determine the application context to take configuration from.
267 1 Henning Blohm
268 29 Henning Blohm
This has a few dramatic consequences:
269
270
* If you would have two application contexts seeing the same static class variable they would override each other and hence you essentially lose control over what configuration is effective.
271
* Hence you should not using Spring AspectJ configuration in API types, as anyone referring to your API would not be able to repeat the trick.
272 28 Henning Blohm
273
That's why: *Only use Spring AspectJ in implementations, i.e. under src.impl or src.test*
274
275 38 Henning Blohm
h2. Using a parent application context in a Web application application context
276 7 Henning Blohm
277
Sometimes, later, when you find that your module has a web app but in addition you want to expose services, from the very same module, i.e. when you have spring configured objects in the web app but also a classpath defined application context that should serve as a _parent application context_ to the one of the web app (admittedly an advanced case), then you will find that that is slightly tricky to achieve (see e.g. http://blog.springsource.org/2007/06/11/using-a-shared-parent-application-context-in-a-multi-war-spring-application/). 
278 8 Henning Blohm
279 47 Henning Blohm
The class *com.zfabrik.springframework.web.ComponentParentContextContextLoaderListener* is a drop-in replacement for Spring's ContextLoaderListener implementation that simplifies that use-case as explained in the "javadoc":http://www.z2-environment.net/javadoc/com.zfabrik.springframework.web!2Fjava/api/com/zfabrik/springframework/web/ComponentParentContextContextLoaderListener.html.
280 26 Henning Blohm
281 42 Henning Blohm
h2. Advanced notes
282 1 Henning Blohm
283 42 Henning Blohm
284
As may have leaked through above already, some features of the Spring framework have slightly non-trivial prerequisites. In general these require that Spring provided libraries are used within the context of other Java components - as for context.support above - and that requires some explanation:
285
286
At runtime, Java components in Z2 have two class loader instances. One for the API definitions of the component, the other for the implementation definitions of the component. The latter is not visible to any referencing component, while the former is. Visibility is achieved by class loader delegation. That is, the class loaders of a referencing Java component will first delegate to the API class loader of the referenced component when looking for a type before checking their own resources. 
287
288
The delegation sequence is always strictly along the references. 
289
290
When we use the term shared library or shared Java component, we are referring to a Java component that can be referenced by others to provide some functionality. At runtime, the types of that Java component are loaded exactly once into the VM's memory. As a side-effect, static class members for example will be shared amongst all usages.
291
292
The alternative to sharing a Java component is to “include” a Java component. When a Java component references a component of type *com.zfabrik.files* or *com.zfabrik.java*, libraries and class files of the referenced component will be copied into the referencing component (depending on the reference either into the API or the implementation part). In that case, the types provided by the files component are used in the context of there referencing component and may be loaded several times.
293
294
Considering Spring there are two cases that mandate a non-shared use of libraries.
295
296
h3. Dangling Imports
297
298
Some Spring libraries provide integration of Spring with a variety of third-party libraries. When those libraries were compiled, all those third-party libraries were present on the compilation class path. Java's late linking paradigm allows to use those libraries without the presence of the third-party libraries as long as visibility of those types is not necessary yet.
299
One example of such a library is the context support Spring module. See above for more details.
300
301
h3. Static Members Holding Singletons
302
303
Another reason that mandates in context use is module specific static initialization. In other words there is a class that holds static, class-level data that is specific to the using context.
304
One example of such is the Spring AspectJ context that points to its underlying application context by a class variable. As a consequence, sharing these classes between modules with different application context would lead to confusions about what application context is used during the application of the Spring aspect. That is why the Spring AspectJ library should always be included by a private reference, and the implementation should use only one application context as far as AspectJ configuration is concerned.