Project

General

Profile

How to Spring » History » Version 37

Henning Blohm, 11.09.2012 15:32

1 16 Henning Blohm
h1. How to Use the Spring Framework in Z2
2
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 2 Henning Blohm
h2. Pre-Requisites
8 1 Henning Blohm
9 35 Henning Blohm
In order to have the Spring libraries available you need to add the 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
10 2 Henning Blohm
11 17 Henning Blohm
<pre><code class="python">
12 15 Henning Blohm
com.zfabrik.systemStates.participation=com.zfabrik.boot.main/sysrepo_up
13 3 Henning Blohm
14
# git stored component repository
15
com.zfabrik.component.type=com.zfabrik.gitcr
16
17
# true <=> optional repository. If gitcr.uri is invalid, then this gitcr will be ignore silently  
18
gitcr.optional=true
19
20
# this can also point to a remote repository like 
21
# ssh://myserver/some/git/repo
22
gitcr.uri=http://git.z2-environment.net/z2-addons.spring
23
24
# the git branch to use (e.g. 'master')
25
gitcr.branch=master
26
</code></pre>
27 15 Henning Blohm
28 3 Henning Blohm
For your own system, you may need to adapt the repository URL and the branch selection accordingly.
29
30 32 Henning Blohm
If that sounds like meaningless gibberish to you - sorry! Please consult the documentation at http://www.z2-environment.eu/v20doc and go back to [[First_steps_with_z2]].
31 3 Henning Blohm
32
33 9 Henning Blohm
When you added that repository the following modules are available:
34 4 Henning Blohm
35
* org.springframework.orm
36
* org.springframework.security
37
* org.springframework.foundation   
38
* org.springframework.transaction
39
* org.springframework.jdbc         
40
* org.springframework.web
41
* com.zfabrik.springframework      
42
* com.zfabrik.springframework.web  
43
44 1 Henning Blohm
45
With the exception of those starting with "com.zfabrik", these do, more or less, correspond to the typical Spring modules found out there. 
46
47 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:
48 10 Henning Blohm
49
* z2-samples.jta-spring (LINK)
50
51 4 Henning Blohm
h2. Using Spring in Web Applications
52 2 Henning Blohm
53
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. 
54 5 Henning Blohm
55
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 
56
context initialized as the Web app is started.
57
58
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*:
59
60 17 Henning Blohm
<pre><code class="python">
61 5 Henning Blohm
java.privateReferences=\
62
	com.zfabrik.springframework.web,\
63
	org.springframework.foundation,\
64
	org.springframework.web
65
66 11 Henning Blohm
</code></pre>
67 5 Henning Blohm
68
The reference to *com.zfabrik.springframework.web* is not strictly needed but adds the following capabilities:
69
70 7 Henning Blohm
* You implicitly get *com.zfabrik.springframework*, i.e. the integration features described below
71 5 Henning Blohm
72 7 Henning Blohm
* You can use a parent application context to your Web application application context as easily as you would hope (see below).
73
74
75 19 Henning Blohm
h2. Using Spring Context Support
76 7 Henning Blohm
77 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_.
78
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.
79 7 Henning Blohm
80 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:
81
82
<pre><code class="python">
83
java.privateIncludes=\
84
   org.springframework.foundation/context.support
85
</code></pre>
86
87
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
88
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. 
89
90 2 Henning Blohm
h2. Using Spring in Re-use Modules
91 19 Henning Blohm
92 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.
93
94 22 Henning Blohm
*Define an Application Context in a Java Module*
95 20 Henning Blohm
96
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.
97
98 22 Henning Blohm
*Starting an Application Context*
99 1 Henning Blohm
100 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
101
102
<pre><code class="python">
103
com.zfabrik.component.type=org.springframework.context
104
105
#
106
# context config location is where the context is 
107
# actually defined. 
108
#
109
context.contextConfigLocation=classpath:META-INF/applicationContext.xml
110 1 Henning Blohm
</code></pre>
111
112 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.
113
114
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.
115 19 Henning Blohm
116 23 Henning Blohm
*Exposing a Bean from an Application Context*
117
118
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:
119
120
<pre><code class="python">
121
com.zfabrik.component.type=org.springframework.bean
122
123
#
124
# the context that defines the bean (more than one
125
# bean can be exposed like this)
126
#
127 24 Henning Blohm
bean.context=<module name>/applicationContext
128 23 Henning Blohm
129
#
130
# the bean name
131
#
132 25 Henning Blohm
bean.name=<bean name>
133 23 Henning Blohm
</code></pre>
134
135
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.
136
137
*Importing a Bean Or Just Any Component*
138 1 Henning Blohm
139 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:
140 1 Henning Blohm
141 25 Henning Blohm
<pre><code class="xml">
142
<bean id="beanId" class="com.zfabrik.springframework.ComponentFactoryBean">
143
  <property name="componentName" value="<module>/<name>" />
144
  <property name="className" value="my.Class" />
145
</bean>
146
</code></pre>
147 23 Henning Blohm
148 26 Henning Blohm
Ok, so far so good. Next subject is how to add more configuration magic to all of this.
149 2 Henning Blohm
150 27 Henning Blohm
h2. Using Spring's AspectJ Configuration
151 1 Henning Blohm
152 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. 
153 1 Henning Blohm
154 27 Henning Blohm
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 - soemthing where you can so easily fool yourself.
155
156
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 parcitular the compiler settings:
157
158
<pre><code class="python">
159
java.privateReferences=\
160
	com.zfabrik.springframework,\
161
	org.springframework.foundation,\
162
	org.springframework.orm,\
163
	org.springframework.transaction
164
165
java.privateIncludes=\
166
	org.springframework.foundation/aspects
167
168
	
169
java.compile.order=java,spring_aspectj
170
</code></pre>
171
172
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.
173
174 30 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 <code>ControllerFilter</code> in the sample *z2-samples.jta-spring* has the following skeleton:
175 27 Henning Blohm
176
<pre><code class="java">
177
@Configurable
178
public class ControllerFilter implements Filter {
179
	
180
	/*
181
	 * Use autowired here as the web container will interpret 
182
	 * @Resource and we want Spring to do the injection 
183
	 */
184
	@Autowired
185
	private ThingyRepository thingyRepository;
186
	
187
// ...
188
189
}
190
</code></pre>
191 26 Henning Blohm
192 28 Henning Blohm
*Important Things to Know About Spring with AspectJ*
193
194 31 Henning Blohm
As always, there is some important pitfalls to watch out for. The Spring AspectJ integration roughly works as follows: 
195 28 Henning Blohm
196
# 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.
197
# 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.
198 1 Henning Blohm
199 29 Henning Blohm
This has a few dramatic consequences:
200 1 Henning Blohm
201 29 Henning Blohm
* 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.
202
* 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.
203
204
That's why: *Only use Spring AspectJ in implementations, i.e. under src.impl or src.test*
205 28 Henning Blohm
206
207
208 7 Henning Blohm
h2. Using a Parent Application Context in a Web Application Application Context
209
210
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/). 
211 8 Henning Blohm
212 7 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 http://z2spring.z2-environment.net/javadoc/com.zfabrik.springframework.web!2Fjava/api/com/zfabrik/springframework/web/ComponentParentContextContextLoaderListener.html.
213 26 Henning Blohm
214
h2. References
215
216
* Z2 Spring Integration: http://www.z2-environment.eu/v20doc#Using%20Spring%20Features%20in%20Z2