Sample-spring-basic » History » Version 20
Henning Blohm, 10.11.2013 13:02
| 1 | 8 | Henning Blohm | h1. A basic Spring with Z2 modularity sample |
|---|---|---|---|
| 2 | 2 | Henning Blohm | |
| 3 | The sample contained in the repository "z2-samples.spring-basic":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic is a clean room example on how to use the Spring integration features described in [[how_to_spring]]. |
||
| 4 | |||
| 5 | 10 | Henning Blohm | There is no further pre-requisite to running this sample, and you may proceed as described in [[How to run a sample]]. Here's the really fast version: |
| 6 | |||
| 7 | 11 | Henning Blohm | <pre><code class="ruby"> |
| 8 | 10 | Henning Blohm | mkdir install |
| 9 | cd install |
||
| 10 | git clone -b master http://git.z2-environment.net/z2-base.core |
||
| 11 | git clone -b master http://git.z2-environment.net/z2-samples.spring-basic |
||
| 12 | |||
| 13 | 11 | Henning Blohm | # on Linux / Mac OS: |
| 14 | 10 | Henning Blohm | cd z2-base.core/run/bin |
| 15 | ./gui.sh |
||
| 16 | |||
| 17 | # on Windows: |
||
| 18 | 12 | Henning Blohm | cd z2-base.core\run\bin |
| 19 | 10 | Henning Blohm | gui.bat |
| 20 | </code></pre> |
||
| 21 | |||
| 22 | 15 | Henning Blohm | If you want to inspect the code using Eclipse, please create a workspace in install (i.e. *install/workspace*) and import the Git repositories and projects (see also [[Step_3_-_First_steps_with_Z2_on_Git|First steps]]). |
| 23 | 2 | Henning Blohm | |
| 24 | 16 | Henning Blohm | There are three modules contained in this sample. For the moment only consider the following two: |
| 25 | 2 | Henning Blohm | |
| 26 | h2. com.zfabrik.samples.spring-basic.services |
||
| 27 | |||
| 28 | 6 | Henning Blohm | This module has a classpath defined "applicationContext":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.services/java/src.impl/META-INF/applicationContext.xml and exposes an annotation defined bean "ComputationServiceImpl":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.services/java/src.impl/com/zfabrik/samples/impl/services/ComputationServiceImpl.java bean from it as a service to be consumed from another module: The *computations* bean. |
| 29 | 2 | Henning Blohm | |
| 30 | 17 | Henning Blohm | The application context enables discovery of Spring beans that are marked by annotations such as @Service, @Component, @Repository: |
| 31 | |||
| 32 | <pre><code class="xml"> |
||
| 33 | <beans ...> |
||
| 34 | <!-- Turn on annotation based config --> |
||
| 35 | <context:annotation-config/> |
||
| 36 | <!-- Turn on auto discovery --> |
||
| 37 | <context:component-scan base-package="com.zfabrik.samples.impl"/> |
||
| 38 | </beans> |
||
| 39 | </code></pre> |
||
| 40 | |||
| 41 | The *computations" bean implementation implements the interface "IComputationService":https://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.services/java/src.api/com/zfabrik/samples/services/IComputationService.java and is itself not visible to consumers. It's structure is roughly like this: |
||
| 42 | |||
| 43 | <pre><code class="java"> |
||
| 44 | @Service("computations") |
||
| 45 | public class ComputationServiceImpl implements IComputationService { |
||
| 46 | |||
| 47 | ... |
||
| 48 | |||
| 49 | } |
||
| 50 | </code></pre> |
||
| 51 | |||
| 52 | The *computations* bean is exposed via the Z2 component "com.zfabrik.samples.spring-basic.services/computations":https://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.services/computations.properties: |
||
| 53 | |||
| 54 | <pre><code class="ruby"> |
||
| 55 | com.zfabrik.component.type=org.springframework.bean |
||
| 56 | |||
| 57 | # |
||
| 58 | # the context that defines the bean (more than one |
||
| 59 | # bean can be exposed like this) |
||
| 60 | # |
||
| 61 | bean.context=com.zfabrik.samples.spring-basic.services/applicationContext |
||
| 62 | |||
| 63 | # |
||
| 64 | # the bean name |
||
| 65 | # |
||
| 66 | bean.name=computations |
||
| 67 | </code></pre> |
||
| 68 | |||
| 69 | Note that the Z2 Bean component names its application context. At runtime this means that an attempt to retrieve the bean will make sure the application context is loaded - and not any earlier. |
||
| 70 | |||
| 71 | 4 | Henning Blohm | h2. com.zfabrik.samples.spring-basic.frontend |
| 72 | 1 | Henning Blohm | |
| 73 | 17 | Henning Blohm | This module has a Web application with an application context defined in "WEB-INF/applicationContext":https://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.frontend/web/WebContent/WEB-INF/applicationContext.xml. It uses Spring AspectJ based annotation driven configuration to inject dependencies into instances of "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. |
| 74 | 1 | Henning Blohm | |
| 75 | 17 | Henning Blohm | Note the Java component descriptor that, apart from referencing the service module, holds the minimum declaration to make sure of Spring with AspectJ supported, compile-time-woven annotation based configuration: |
| 76 | |||
| 77 | <pre><code class="ruby"> |
||
| 78 | com.zfabrik.component.type=com.zfabrik.java |
||
| 79 | |||
| 80 | java.privateReferences=\ |
||
| 81 | com.zfabrik.servletjsp,\ |
||
| 82 | org.springframework.transaction,\ |
||
| 83 | org.springframework.orm,\ |
||
| 84 | org.springframework.web,\ |
||
| 85 | com.zfabrik.springframework,\ |
||
| 86 | com.zfabrik.samples.spring-basic.services |
||
| 87 | |||
| 88 | java.privateIncludes=\ |
||
| 89 | org.springframework.foundation/aspects |
||
| 90 | |||
| 91 | java.compile.order=java,spring_aspectj |
||
| 92 | </code></pre> |
||
| 93 | |||
| 94 | |||
| 95 | It's "application context":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.frontend/web/WebContent/WEB-INF/applicationContext.xml imports the *computations* service from the other module above and enables the use of Spring configuration (note: Unlike above it does not enable discovery of Spring beans): |
||
| 96 | |||
| 97 | <pre><code class="xml"> |
||
| 98 | <beans ... > |
||
| 99 | <!-- turn on @Configurable support --> |
||
| 100 | <context:spring-configured/> |
||
| 101 | <!-- Turn on annotation based config --> |
||
| 102 | <context:annotation-config/> |
||
| 103 | <!-- application config: Bind the bean at samples.spring.simplemodules.services/computations --> |
||
| 104 | <bean id="computations" class="com.zfabrik.springframework.ComponentFactoryBean"> |
||
| 105 | <property name="componentName" value="com.zfabrik.samples.spring-basic.services/computations"/> |
||
| 106 | <property name="className" value="com.zfabrik.samples.services.IComputationService"/> |
||
| 107 | </bean> |
||
| 108 | </beans> |
||
| 109 | </code></pre> |
||
| 110 | 7 | Henning Blohm | |
| 111 | 9 | Henning Blohm | h2. Finally |
| 112 | |||
| 113 | 19 | Henning Blohm | Open a browser and navigate to http://localhost:8080/spring-basic to verify you get this: |
| 114 | 9 | Henning Blohm | |
| 115 | 1 | Henning Blohm | !frontend.png! |
| 116 | 16 | Henning Blohm | |
| 117 | h1. An extended Spring with Z2 modularity and some Spring Security sample |
||
| 118 | |||
| 119 | The third module *com.zfabrik.samples.spring-basic.secured* contained in the sample repository implements a very similar basic frontend to the one above but illustrating in addition: |
||
| 120 | |||
| 121 | * How to use Spring Security to secure the access to a Web application |
||
| 122 | * How to use Spring Security to secure methods of a bean |
||
| 123 | * How to use Spring Security with Spring AspectJ weaving |
||
| 124 | |||
| 125 | 18 | Henning Blohm | More specifically, the contained Web application knows of two users *"user"* (password "user") and *"admin"* (password "admin") that have roles @ROLE_USER@ or @ROLE_USER@ and @ROLE_ADMIN@ respectively. |
| 126 | |||
| 127 | The controller servlet delegates operations to a _session facade_ implemented by the class "SomeFacadeImpl":https://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.secured/java/src.impl/com/zfabrik/samples/impl/facades/SomeFacadeImpl.java that offers two methods, one requiring @ROLE_USER@, one requiring @ROLE_ADMIN@. |
||
| 128 | |||
| 129 | But let's rather have a step-by-step overview: The Java component declaration "com.zfabrik.samples.spring-basic.secured/java":https://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.secured/java/z.properties, as compared to the one of the other frontend module has some noteworthy additions: |
||
| 130 | |||
| 131 | <pre><code class="ruby"> |
||
| 132 | com.zfabrik.component.type=com.zfabrik.java |
||
| 133 | |||
| 134 | java.privateReferences=\ |
||
| 135 | com.zfabrik.servletjsp,\ |
||
| 136 | org.springframework.transaction,\ |
||
| 137 | org.springframework.security,\ |
||
| 138 | org.springframework.orm,\ |
||
| 139 | org.springframework.web,\ |
||
| 140 | com.zfabrik.springframework,\ |
||
| 141 | com.zfabrik.samples.spring-basic.services |
||
| 142 | |||
| 143 | java.privateIncludes=\ |
||
| 144 | org.springframework.foundation/aspects,\ |
||
| 145 | org.springframework.security/web,\ |
||
| 146 | org.springframework.security/config,\ |
||
| 147 | org.springframework.security/aspects |
||
| 148 | |||
| 149 | # |
||
| 150 | # this enables the processing of @Secured annotations |
||
| 151 | # |
||
| 152 | aspectj.privateAspectPathByClass=\ |
||
| 153 | org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect |
||
| 154 | |||
| 155 | java.compile.order=java,spring_aspectj |
||
| 156 | </code></pre> |
||
| 157 | |||
| 158 | One the one it references the Spring Security module and it includes some Spring Security elements (that unfortunately must be included). Notably the support for Web apps, the *config* support, and finally the *aspect*, which is the pre-requisite for AspectJ support with Spring Security. |
||
| 159 | |||
| 160 | We prefer AspectJ compile-time weaving over Spring AOP as it is much more consistent (non-proxy-based AOP, see also [[how_to_spring]] and elsewhere) and, as the compilation part is automatic with Z2, no extra burden to configure. |
||
| 161 | |||
| 162 | However, to let the Spring AspectJ compiler, supported by Z2 know about the handling of Spring Security annotations used in the implementation, the corresponding _Aspect Implementation_ must be indicated. Hence the additional property "aspectj.privateAspectPathByClass". See also "AspectJCompiler":http://www.z2-environment.net/javadoc/com.zfabrik.springframework!2Fjava/impl/com/zfabrik/impl/springframework/AspectJCompiler.html for more details. |
||
| 163 | |||
| 164 | Fortunately this was the hardest part of our configuration tour. |
||
| 165 | |||
| 166 | The Web apps "application context":https://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.secured/web/WebContent/WEB-INF/applicationContext.xml has a lot of similarities to the one of the other frontend but adds some Spring Security related configuration: |
||
| 167 | |||
| 168 | |||
| 169 | <pre><code class="xml"> |
||
| 170 | ... |
||
| 171 | |||
| 172 | <!-- web security config: require basic authentication, hard-coded users "user" and "admin" --> |
||
| 173 | <security:http auto-config='true' disable-url-rewriting="true"> |
||
| 174 | <security:intercept-url pattern="/**" access="ROLE_ADMIN,ROLE_USER" /> |
||
| 175 | <security:http-basic /> |
||
| 176 | </security:http> |
||
| 177 | |||
| 178 | <security:authentication-manager> |
||
| 179 | <security:authentication-provider> |
||
| 180 | <security:user-service> |
||
| 181 | <security:user name="admin" password="admin" authorities="ROLE_ADMIN,ROLE_USER" /> |
||
| 182 | <security:user name="user" password="user" authorities="ROLE_USER" /> |
||
| 183 | </security:user-service> |
||
| 184 | </security:authentication-provider> |
||
| 185 | </security:authentication-manager> |
||
| 186 | |||
| 187 | <!-- method security config (in this case, only Secured annotations enabled)--> |
||
| 188 | <security:global-method-security |
||
| 189 | secured-annotations="enabled" |
||
| 190 | mode="aspectj" |
||
| 191 | /> |
||
| 192 | |||
| 193 | ... |
||
| 194 | </code></pre> |
||
| 195 | |||
| 196 | Having users and passwords declared in the application context is is a sacrifice due to the sample nature. Other than that these declarations say that |
||
| 197 | |||
| 198 | # the Web app uses Basic Authentication (being simpler than a form-based login for the sample), |
||
| 199 | # that all requests require either @ROLE_USER@ or @ROLE_ADMIN@, and |
||
| 200 | # that it makes use of _Method Security_, expecting the support of @Secured annotations with AspectJ weaving. |
||
| 201 | |||
| 202 | The controller servlet ("ControllerServlet":https://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.secured/java/src.impl/com/zfabrik/samples/impl/frontend/ControllerServlet.java) delegates all calls to the facade implementation "SomeFacadeImpl":https://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-spring-basic/revisions/master/entry/com.zfabrik.samples.spring-basic.secured/java/src.impl/com/zfabrik/samples/impl/facades/SomeFacadeImpl.java that has secured methods: |
||
| 203 | |||
| 204 | <pre><code class="java"> |
||
| 205 | @Component |
||
| 206 | public class SomeFacadeImpl { |
||
| 207 | private final static Logger LOG = Logger.getLogger(SomeFacadeImpl.class.getName()); |
||
| 208 | |||
| 209 | public SomeFacadeImpl() { |
||
| 210 | LOG.info("Init of "+this); |
||
| 211 | } |
||
| 212 | |||
| 213 | @Autowired |
||
| 214 | private IComputationService computations; |
||
| 215 | |||
| 216 | @Secured("ROLE_USER") |
||
| 217 | public String doSomethingWithAString(String in) { |
||
| 218 | return computations.doSomethingWithAString(in); |
||
| 219 | } |
||
| 220 | |||
| 221 | @Secured("ROLE_ADMIN") |
||
| 222 | public String doSomethingThatRequiresAdmin() { |
||
| 223 | return "Yes, you can!"; |
||
| 224 | } |
||
| 225 | } |
||
| 226 | </code></pre> |
||
| 227 | |||
| 228 | It does use the re-use service *computations* from the other module and gets it injected as above. |
||
| 229 | |||
| 230 | 20 | Henning Blohm | Now, if you open a Web browser at http://localhost:8080/spring-basic-secured you will first be asked to log in (best try "user" with password "user" first) and next offered the following options: |
| 231 | 18 | Henning Blohm | |
| 232 | !secured.png! |
||
| 233 | |||
| 234 | Depending on what user you chose, the admin user function will be refused or not. |
