| | + title | Ref. /chapter[1]/title[1] |
| Original | Traduction | Source Level Metadata Support |
| sect1
| | + title | Ref. /chapter[1]/sect1[1]/title[1] |
| Original | Traduction | Source-level metadata |
|
| + para | Ref. /chapter[1]/sect1[1]/para[1] |
| Original | Traduction | Source-level metadata is the
addition of attributes or annotations
to program elements: usually, classes and/or methods. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[2] |
| Original | Traduction | For example, we might add metadata to a class as follows: |
|
| + programlisting | Ref. /chapter[1]/sect1[1]/para[3]/programlisting[1] |
| Original | Traduction | /**
* Normal comments
* @@org.springframework.transaction.interceptor.DefaultTransactionAttribute()
*/
public class PetStoreImpl implements PetStoreFacade, OrderService { |
|
| + para | Ref. /chapter[1]/sect1[1]/para[4] |
| Original | Traduction | We could add metadata to a method as follows: |
|
| + programlisting | Ref. /chapter[1]/sect1[1]/para[5]/programlisting[1] |
| Original | Traduction | /**
* Normal comments
* @@org.springframework.transaction.interceptor.RuleBasedTransactionAttribute ()
* @@org.springframework.transaction.interceptor.RollbackRuleAttribute (Exception.class)
* @@org.springframework.transaction.interceptor.NoRollbackRuleAttribute ("ServletException")
*/
public void echoException(Exception ex) throws Exception {
....
} |
|
| + para | Ref. /chapter[1]/sect1[1]/para[6] |
| Original | Traduction | Both these examples use Jakarta Commons Attributes syntax. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[7] |
| Original | Traduction | Source-level metadata was introduced to the mainstream with the
release of Microsoft's .NET platform, which uses source-level
attributes to control transactions, pooling and other behaviour. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[8] |
| Original | Traduction | The value in this approach has been recognized in the J2EE
community. For example, it's much less verbose than the traditional
XML deployment descriptors exclusively used by EJB. While it is desirable
to externalize some things from program source code, some important
enterprise settings--notably transaction characteristics--belong in
program source. Contrary to the assumptions of the EJB spec, it seldom
makes sense to modify the transactional characteristics of a method. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[9] |
| Original | Traduction | Although metadata attributes are typically used mainly by framework
infrastructure to describe the services application classes require, it
should also be possible for metadata attributes to be queried at runtime.
This is a key distinction from solutions such as XDoclet, which primarily
view metadata as a way of generating code such as EJB artefacts. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[10] |
| Original | Traduction | There are a number of solutions in this space, including: |
|
| + para | Ref. /chapter[1]/sect1[1]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | JSR-175: the standard Java
metadata implementation, available in Java 1.5. But we need a solution
now and may always want a facade |
|
| + para | Ref. /chapter[1]/sect1[1]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | XDoclet: well-established
solution, primarily intended for code generation |
|
| + para | Ref. /chapter[1]/sect1[1]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | Various open source attribute
implementations, pending the release of JSR-175, of which
Commons Attributes appears to be the most promising. All these require
a special pre- or post-compilation step. |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[2]/title[1] |
| Original | Traduction | Spring's metadata support |
|
| + para | Ref. /chapter[1]/sect1[2]/para[1] |
| Original | Traduction | In keeping with its provision of abstractions over important
concepts, Spring provides a facade to metadata implementations, in the
form of the org.springframework.metadata.Attributes
interface. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[2] |
| Original | Traduction | Such a facade adds value for several reasons: | + para | Ref. /chapter[1]/sect1[2]/para[2]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | There
is currently no standard metadata solution. Java 1.5 will provide one, but
it is still in beta as of Spring 1.0. Furthermore, there will be a need
for metadata support in 1.3 and 1.4 applications for at least two years.
Spring aims to provide working solutions now; waiting
for 1.5 is not an option in such an important area. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[2]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | Current
metadata APIs, such as Commons Attributes (used by Spring 1.0) are hard to
test. Spring provides a simple metadata interface that is much easier to
mock. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[2]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | Even when Java 1.5 provides
metadata support at language level, there will still be value in providing
such an abstraction: |
|
| + para | Ref. /chapter[1]/sect1[2]/para[2]/itemizedlist[1]/listitem[3]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | JSR-175 metadata
is static. It is associated with a class at compile time, and cannot be
changed in a deployed environment. There is a need for hierarchical
metadata, providing the ability to override certain attribute values in
deployment--for example, in an XML file. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[2]/itemizedlist[1]/listitem[3]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | JSR-175
metadata is returned through the Java reflection API. This makes it
impossible to mock during test time. Spring provides a simple interface to
allow this. |
|
|
|
| + para | Ref. /chapter[1]/sect1[2]/para[3] |
| Original | Traduction | Thus Spring will support JSR-175 before Java 1.5 reaches GA, but
will continue to offer an attribute abstraction API. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[4] |
| Original | Traduction | The Spring Attributes interface looks like this: |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/para[5]/programlisting[1] |
| Original | Traduction | public interface Attributes {
Collection getAttributes(Class targetClass);
Collection getAttributes(Class targetClass, Class filter);
Collection getAttributes(Method targetMethod);
Collection getAttributes(Method targetMethod, Class filter);
Collection getAttributes(Field targetField);
Collection getAttributes(Field targetField, Class filter);
} |
|
| + para | Ref. /chapter[1]/sect1[2]/para[6] |
| Original | Traduction | This is a lowest common denominator interface. JSR-175 offers more
capabilities than this, such as attributes on method arguments. As of
Spring 1.0, Spring aims to provide the subset of metadata required to
provide effective declarative enterprise services a la EJB or .NET. Beyond
Spring 1.0, it is likely that Spring will provide further metadata
methods. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[7] |
| Original | Traduction | Note that this interface offers Object
attributes, like .NET. This distinguishes it from attribute systems such
as that of Nanning Aspects and JBoss 4 (as of DR2), which offer only
String attributes. There is a significant advantage in
supporting Object attributes. It enables attributes to
participate in class hierarchies and enables attributes to react
intelligently to their configuration parameters. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[8] |
| Original | Traduction | In most attribute providers, attribute classes will be configured
via constructor arguments or JavaBean properties. Commons Attributes
supports both. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[9] |
| Original | Traduction | As with all Spring abstraction APIs, Attributes
is an interface. This makes it easy to mock attribute implementations for
unit tests. |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[3]/title[1] |
| Original | Traduction | Integration with Jakarta Commons Attributes |
|
| + para | Ref. /chapter[1]/sect1[3]/para[1] |
| Original | Traduction | Presently Spring supports only Jakarta Commons Attributes out of the
box, although it is easy to provide implementations of the
org.springframework.metadata.Attributes interface for
other metadata providers. |
|
| + para | Ref. /chapter[1]/sect1[3]/para[2] |
| Original | Traduction | Commons Attributes 2.1 (http://jakarta.apache.org/commons/attributes/)
is a capable attributes solution. It supports attribute configuration via
constructor arguments and JavaBean properties, which offers better
self-documentation in attribute definitions. (Support for JavaBean
properties was added at the request of the Spring team.) |
|
| + para | Ref. /chapter[1]/sect1[3]/para[3] |
| Original | Traduction | We've already seen two examples of Commons Attributes attributes
definitions. In general, we will need to express: |
|
| + para | Ref. /chapter[1]/sect1[3]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | The name of the attribute class. This can
be an FQN, as shown above. If the relevant attribute class has already
been imported, the FQN isn't required. It's also possible to
specify "attribute packages" in attribute compiler
configuration. |
|
| + para | Ref. /chapter[1]/sect1[3]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | Any necessary parameterization, via
constructor arguments or JavaBean properties |
|
| + para | Ref. /chapter[1]/sect1[3]/para[4] |
| Original | Traduction | Bean properties look as follows: |
|
| + programlisting | Ref. /chapter[1]/sect1[3]/para[5]/programlisting[1] |
| Original | Traduction | /**
* @@MyAttribute(myBooleanJavaBeanProperty=true)
*/ |
|
| + para | Ref. /chapter[1]/sect1[3]/para[6] |
| Original | Traduction | It's possible to combine constructor arguments and JavaBean
properties (as in Spring IoC). |
|
| + para | Ref. /chapter[1]/sect1[3]/para[7] |
| Original | Traduction | Because, unlike Java 1.5 attributes, Commons Attributes is not
integrated with the Java language, it is necessary to run a special
attribute compilation step as part of the build
process. |
|
| + para | Ref. /chapter[1]/sect1[3]/para[8] |
| Original | Traduction | To run Commons Attributes as part of the build process, you will
need to do the following. |
|
| + para | Ref. /chapter[1]/sect1[3]/para[9] |
| Original | Traduction | 1. Copy the necessary library Jars to $ANT_HOME/lib.
Four Jars are required, and all are distributed with Spring: |
|
| + para | Ref. /chapter[1]/sect1[3]/itemizedlist[2]/listitem[1]/para[1] |
| Original | Traduction | The Commons Attributes compiler Jar and API Jar |
|
| + para | Ref. /chapter[1]/sect1[3]/itemizedlist[2]/listitem[2]/para[1] |
| Original | Traduction | xjavadoc.jar, from XDoclet |
|
| + para | Ref. /chapter[1]/sect1[3]/itemizedlist[2]/listitem[3]/para[1] |
| Original | Traduction | commons-collections.jar, from Jakarta Commons |
|
| + para | Ref. /chapter[1]/sect1[3]/para[10] |
| Original | Traduction | 2. Import the Commons Attributes ant tasks into your project build
script, as follows: |
|
| + programlisting | Ref. /chapter[1]/sect1[3]/programlisting[1] |
| Original | Traduction | <taskdef resource="org/apache/commons/attributes/anttasks.properties"/> |
|
| + para | Ref. /chapter[1]/sect1[3]/para[11] |
| Original | Traduction | 3. Next, define an attribute compilation task, which will use the
Commons Attributes attribute-compiler task to "compile" the
attributes in the source. This process results in the generation of
additional sources, to a location specified by the destdir attribute. Here
we show the use of a temporary directory: |
|
| + programlisting | Ref. /chapter[1]/sect1[3]/para[12]/programlisting[1] |
| Original | Traduction | <target name="compileAttributes" >
<attribute-compiler
destdir="${commons.attributes.tempdir}"
>
<fileset dir="${src.dir}" includes="**/*.java"/>
</attribute-compiler>
</target> |
|
| + para | Ref. /chapter[1]/sect1[3]/para[13] |
| Original | Traduction | The compile target that runs Javac over the sources should depend on
this attribute compilation task, and must also compile the generated
sources, which we output to our destination temporary directory. If there
are syntax errors in your attribute definitions, they will normally be
caught by the attribute compiler. However, if the attribute definitions
are syntactically plausible, but specify invalid types or class names, the
compilation of the generated attribute classes may fail. In this case, you
can look at the generated classes to establish the cause of the problem. |
|
| + remark | Ref. /chapter[1]/sect1[3]/remark[1] |
| Original | Traduction | Commons Attributes also provides Maven support. Please refer to
Commons Attributes documentation for further information. |
|
| + para | Ref. /chapter[1]/sect1[3]/para[14] |
| Original | Traduction | While this attribute compilation process may look complex, in fact
it's a one-off cost. Once set up, attribute compilation is
incremental, so it doesn't usually noticeably slow the build process.
And once the compilation process is set up, you may find that use of
attributes as described in this chapter can save you a lot of time in
other areas. |
|
| + para | Ref. /chapter[1]/sect1[3]/para[15] |
| Original | Traduction | If you require attribute indexing support (only currently required
by Spring for attribute-targeted web controllers, discussed below), you
will need an additional step, which must be performed on a Jar file of
your compiled classes. In this, optional, step, Commons Attributes will
create an index of all the attributes defined on your sources, for
efficient lookup at runtime. This step looks as follows: |
|
| + programlisting | Ref. /chapter[1]/sect1[3]/para[16]/programlisting[1] |
| Original | Traduction | <attribute-indexer jarFile="myCompiledSources.jar">
<classpath refid="master-classpath"/>
</attribute-indexer> |
|
| + remark | Ref. /chapter[1]/sect1[3]/remark[2] |
| Original | Traduction | See the /attributes directory of the Spring jPetStore sample
application for an example of this build process. You can take the build
script it contains and modify it for your own projects. |
|
| + para | Ref. /chapter[1]/sect1[3]/para[17] |
| Original | Traduction | If your unit tests depend on attributes, try to express the
dependency on the Spring Attributes abstraction, rather than Commons
Attributes. Not only is this more portable--for example, your tests will
still work if you switch to Java 1.5 attributes in future--it simplifies
testing. Commons Attributes is a static API, while Spring provides a
metadata interface that you can easily mock. |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[4]/title[1] |
| Original | Traduction | Metadata and Spring AOP autoproxying |
|
| + para | Ref. /chapter[1]/sect1[4]/para[1] |
| Original | Traduction | The most important uses of metadata attributes are in conjunction
with Spring AOP. This provides a .NET-like programming model, where
declarative services are automatically provided to application objects
that declare metadata attributes. Such metadata attributes can be
supported out of the box by the framework, as in the case of declarative
transaction management, or can be custom. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[2] |
| Original | Traduction | There is widely held to be a synergy between AOP and metadata
attributes. |
| sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[1]/title[1] |
| Original | Traduction | Fundamentals |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1] |
| Original | Traduction | This builds on the Spring AOP autoproxy functionality.
Configuration might look like this: |
|
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[1]/para[2]/programlisting[1] |
| Original | Traduction | <bean id="autoproxy"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
</bean>
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource"
autowire="constructor">
</bean>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor"
autowire="byType">
</bean>
<bean id="transactionAdvisor"
class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"
autowire="constructor" >
</bean>
<bean id="attributes"
class="org.springframework.metadata.commons.CommonsAttributes"
/> |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[3] |
| Original | Traduction | The basic concepts here should be familiar from the discussion of
autoproxying in the AOP chapter. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[4] |
| Original | Traduction | The most important bean definitions are those named autoproxy and transactionAdvisor.
Note that the actual bean names are not important; what matters is their
class. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[5] |
| Original | Traduction | The autoproxy bean definition of class org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
will automatically advise ("autoproxy") all bean instances in
the current factory based on matching Advisor implementations. This
class knows nothing about attributes, but relies on Advisors'
pointcuts matching. The pointcuts do know about attributes. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[6] |
| Original | Traduction | Thus we simply need an AOP advisor that will provide declarative
transaction management based on attributes. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[7] |
| Original | Traduction | It's possible to add arbitrary custom Advisor implementations
as well, and they will also be evaluated and applied automatically. (You
can use Advisors whose pointcuts match on criteria besides attributes in
the same autoproxy configuration, if necessary.) |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[8] |
| Original | Traduction | Finally, the attributes bean is the Commons
Attributes Attributes implementation. Replace with another
implementation of org.springframework.metadata.Attributes
to source attributes from a different source. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[2]/title[1] |
| Original | Traduction | Declarative transaction management |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[2]/para[1] |
| Original | Traduction | The commonest use of source-level attributes it to provide
declarative transaction management a la .NET. Once the bean definitions
shown above are in place, you can define any number of application
objects requiring declarative transactions. Only those classes or
methods with transaction attributes will be given transaction advice.
You need to do nothing except define the required transaction
attributes. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[2]/para[2] |
| Original | Traduction | Unlike in .NET, you can specify transaction
attributes at either class or method level. Class-level attributes, if
specified, will be "inherited" by all methods. Method attributes
will wholly override any class-level attributes. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[3]/title[1] |
| Original | Traduction | Pooling |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[3]/para[1] |
| Original | Traduction | Again, as with .NET, you can enable pooling behavior via
class-level attributes. Spring can apply this behavior to any POJO. You
simply need to specify a pooling attribute, as follows, in the business
object to be pooled: |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[3]/para[2] |
| Original | Traduction | | + programlisting | Ref. /chapter[1]/sect1[4]/sect2[3]/para[2]/programlisting[1] |
| Original | Traduction | /**
* @@org.springframework.aop.framework.autoproxy.target.PoolingAttribute (10)
*
* @author Rod Johnson
*/
public class MyClass { |
| You'll need the usual autoproxy
infrastructure configuration. You then need to specify a pooling
TargetSourceCreator, as follows. Because pooling
affects the creation of the target, we can't use a regular advice.
Note that pooling will apply even if there are no advisors applicable to
the class, if that class has a pooling attribute. |
|
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[3]/para[3]/programlisting[1] |
| Original | Traduction | <bean id="poolingTargetSourceCreator"
class="org.springframework.aop.framework.autoproxy.metadata.AttributesPoolingTargetSourceCreator"
autowire="constructor" >
</bean> |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[3]/para[4] |
| Original | Traduction | The relevant autoproxy bean definition needs to specify a list of
"custom target source creators", including the Pooling target
source creator. We could modify the example shown above to include this
property as follows: |
|
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[3]/para[5]/programlisting[1] |
| Original | Traduction | <bean id="autoproxy"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
>
<property name="customTargetSourceCreators">
<list>
<ref local="poolingTargetSourceCreator" />
</list>
</property>
</bean> |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[3]/para[6] |
| Original | Traduction | As with the use of metadata in Spring in general, this is a
one-off cost: once setup is out of the way, it's very easy to use
pooling for additional business objects. |
|
| + remark | Ref. /chapter[1]/sect1[4]/sect2[3]/remark[1] |
| Original | Traduction | It's arguable that the need for pooling is rare, so
there's seldom a need to apply pooling to a large number of business
objects. Hence this feature does not appear to be used often. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[3]/para[7] |
| Original | Traduction | Please see the Javadoc for the org.springframework.aop.framework.autoproxy
package for more details. It's possible to use a different pooling
implementation than Commons Pool with minimal custom coding. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[4]/title[1] |
| Original | Traduction | Custom metadata |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[4]/para[1] |
| Original | Traduction | We can even go beyond the capabilities of .NET metadata
attributes, because of the flexibility of the underlying autoproxying
infrastructure. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[4]/para[2] |
| Original | Traduction | We can define custom attributes, to provide any kind of
declarative behavior. To do this, you need to: |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[4]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | Define your custom attribute class |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[4]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | Define a Spring AOP Advisor with a pointcut that fires on the
presence of this custom attribute. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[4]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | Add that Advisor as a bean definition to an application
context with the generic autoproxy infrastructure in place. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[4]/itemizedlist[1]/listitem[4]/para[1] |
| Original | Traduction | Add attributes to your POJOs. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[4]/para[3] |
| Original | Traduction | There are several potential areas you might want to do this, such
as custom declarative security, or possibly caching. |
|
| + remark | Ref. /chapter[1]/sect1[4]/sect2[4]/remark[1] |
| Original | Traduction | This is a powerful mechanism which can significantly reduce
configuration effort in some projects. However, remember that it does
rely on AOP under the covers. The more Advisors you have in play, the
more complex your runtime configuration will be. |
|
| + remark | Ref. /chapter[1]/sect1[4]/sect2[4]/remark[2] |
| Original | Traduction | (If you want to see what advice applies to any object, try
casting a reference to org.springframework.aop.framework.Advised. This
will enable you to examine the Advisors.) |
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[5]/title[1] |
| Original | Traduction | Using attributes to minimize MVC web tier configuration |
|
| + para | Ref. /chapter[1]/sect1[5]/para[1] |
| Original | Traduction | The other main use of Spring metadata as of 1.0 is to provide an
option to simplify Spring MVC web configuration. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[2] |
| Original | Traduction | Spring MVC offers flexible handler mappings:
mappings from incoming request to controller (or other handler) instance.
Normally handler mappings are configured in the xxxx-servlet.xml
file for the relevant Spring DispatcherServlet. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[3] |
| Original | Traduction | Holding these mappings in the DispatcherServlet configuration file
is normally A Good Thing. It provides maximum flexibility. In particular: | + para | Ref. /chapter[1]/sect1[5]/para[3]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | The
controller instance is explicitly managed by Spring IoC, through an XML
bean definition |
|
| + para | Ref. /chapter[1]/sect1[5]/para[3]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | The mapping is external
to the controller, so the same controller instance could be given multiple
mappings in the same DispatcherServlet context or reused in a different
configuration. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[3]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | Spring MVC is able to
support mappings based on any criteria, rather than merely the request
URL-to-controller mappings available in most other frameworks. |
|
|
|
| + para | Ref. /chapter[1]/sect1[5]/para[4] |
| Original | Traduction | However, this does mean that for each controller we typically need
both a handler mapping (normally in a handler mapping XML bean definition)
and an XML mapping for the controller itself. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[5] |
| Original | Traduction | Spring offers a simpler approach based on source-level attributes,
which is an attractive option in simpler scenarios. |
|
| + remark | Ref. /chapter[1]/sect1[5]/remark[1] |
| Original | Traduction | The approach described in this section is best suited to
relatively simple MVC scenarios. It sacrifices some of the power of Spring
MVC, such as the ability to use the same controller with different
mappings, and the ability to base mappings on something other than request
URL. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[6] |
| Original | Traduction | In this approach, controllers are marked with one or more
class-level metadata attributes, each specifying one URL they should be
mapped to. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[7] |
| Original | Traduction | The following examples show the approach. In each case, we have a
controller that depends on a business object of type Cruncher. As usual,
this dependency will be resolved by Dependency Injection. The Cruncher
must be available through a bean definition in the relevant
DispatcherServlet XML file, or a parent context. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[8] |
| Original | Traduction | We attach an attribute to the controller class specifying the URL
that should map to it. We can express the dependency through a JavaBean
property or a constructor argument. This dependency must be resolvable by
autowiring: that is, there must be exactly one business object of type
Cruncher available in the context. |
|
| + programlisting | Ref. /chapter[1]/sect1[5]/para[9]/programlisting[1] |
| Original | Traduction | /**
* Normal comments here
* @author Rod Johnson
* @@org.springframework.web.servlet.handler.metadata.PathMap("/bar.cgi")
*/
public class BarController extends AbstractController {
private Cruncher cruncher;
public void setCruncher(Cruncher cruncher) {
this.cruncher = cruncher;
}
protected ModelAndView handleRequestInternal(
HttpServletRequest arg0, HttpServletResponse arg1)
throws Exception {
System.out.println("Bar Crunching c and d =" +
cruncher.concatenate("c", "d"));
return new ModelAndView("test");
}
} |
|
| + para | Ref. /chapter[1]/sect1[5]/para[10] |
| Original | Traduction | For this auto-mapping to work, we need to add the following to the
relevant xxxx-servlet.xml file, specifying the
attributes handler mapping. This special handler mapping can handle any
number of controllers with attributes as shown above. The bean id
("commonsAttributesHandlerMapping") is not important. The type is
what matters: |
|
| + programlisting | Ref. /chapter[1]/sect1[5]/para[11]/programlisting[1] |
| Original | Traduction | <bean id="commonsAttributesHandlerMapping"
class="org.springframework.web.servlet.handler.metadata.CommonsPathMapHandlerMapping"
/> |
|
| + para | Ref. /chapter[1]/sect1[5]/para[12] |
| Original | Traduction | We do not currently need an Attributes bean
definition, as in the above example, because this class works directly
with the Commons Attributes API, not via the Spring metadata abstraction. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[13] |
| Original | Traduction | We now need no XML configuration for each controller. Controllers
are automatically mapped to the specified URL(s). Controllers benefit from
IoC, using Spring's autowiring capability. For example, the dependency
expressed in the "cruncher" bean property of the simple controller
shown above is automatically resolved in the current web application
context. Both Setter and Constructor Dependency Injection are available,
each with zero configuration. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[14] |
| Original | Traduction | An example of Constructor Injection, also showing multiple URL
paths: |
|
| + programlisting | Ref. /chapter[1]/sect1[5]/para[15]/programlisting[1] |
| Original | Traduction | /**
* Normal comments here
* @author Rod Johnson
*
* @@org.springframework.web.servlet.handler.metadata.PathMap("/foo.cgi")
* @@org.springframework.web.servlet.handler.metadata.PathMap("/baz.cgi")
*/
public class FooController extends AbstractController {
private Cruncher cruncher;
public FooController(Cruncher cruncher) {
this.cruncher = cruncher;
}
protected ModelAndView handleRequestInternal(
HttpServletRequest arg0, HttpServletResponse arg1)
throws Exception {
return new ModelAndView("test");
}
} |
|
| + para | Ref. /chapter[1]/sect1[5]/para[16] |
| Original | Traduction | This approach has the following benefits: |
|
| + para | Ref. /chapter[1]/sect1[5]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | Significantly reduced volume of configuration. Each time we add
a controller we need add no XML configuration. As
with attribute-driven transaction management, once the basic
infrastructure is in place, it is very easy to add more application
classes. |
|
| + para | Ref. /chapter[1]/sect1[5]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | We retain much of the power of Spring IoC to configure
controllers. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[17] |
| Original | Traduction | This approach has the following limitations: |
|
| + para | Ref. /chapter[1]/sect1[5]/itemizedlist[2]/listitem[1]/para[1] |
| Original | Traduction | One-off cost in more complex build process. We need an attribute
compilation step and an attribute indexing step. However, once in
place, this should not be an issue. |
|
| + para | Ref. /chapter[1]/sect1[5]/itemizedlist[2]/listitem[2]/para[1] |
| Original | Traduction | Currently Commons Attributes only, although support for other
attribute providers may be added in future. |
|
| + para | Ref. /chapter[1]/sect1[5]/itemizedlist[2]/listitem[3]/para[1] |
| Original | Traduction | Only "autowiring by type" dependency injection is
supported for such controllers. However, this still leaves them far in
advance of Struts Actions (with no IoC support from the framework)
and, arguably, WebWork Actions (with only rudimentary IoC support)
where IoC is concerned. |
|
| + para | Ref. /chapter[1]/sect1[5]/itemizedlist[2]/listitem[4]/para[1] |
| Original | Traduction | Reliance on automagical IoC resolution may be confusing. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[18] |
| Original | Traduction | Because autowiring by type means there must be exactly one
dependency of the specified type, we need to be careful if we use AOP. In
the common case using TransactionProxyFactoryBean, for example, we end up
with two implementations of a business interface such
as Cruncher: the original POJO definition, and the transactional AOP
proxy. This won't work, as the owning application context can't
resolve the type dependency unambiguously. The solution is to use AOP
autoproxying, setting up the autoproxy infrastructure so that there is
only one implementation of Cruncher defined, and that implementation is
automatically advised. Thus this approach works well with
attribute-targeted declarative services as described above. As the
attributes compilation process must be in place to handle the web
controller targeting, this is easy to set up. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[19] |
| Original | Traduction | Unlike other metadata functionality, there is currently only a
Commons Attributes implementation available:
org.springframework.web.servlet.handler.metadata.CommonsPathMapHandlerMapping.
This limitation is due to the fact that not only do we need attribute
compilation, we need attribute indexing: the ability
to ask the attributes API for all classes with the PathMap attribute.
Indexing is not currently offered on the org.springframework.metadata.Attributes
abstraction interface, although it may be in future. (If you want to add
support for another attributes implementation--which must support
indexing--you can easily extend the AbstractPathMapHandlerMapping
superclass of CommonsPathMapHandlerMapping,
implementing the two protected abstract methods to use your preferred
attributes API.) |
|
| + para | Ref. /chapter[1]/sect1[5]/para[20] |
| Original | Traduction | Thus we need two additional steps in the build process: attribute
compilation and attribute indexing. Use of the attribute indexer task was
shown above. Note that Commons Attributes presently requires a Jar file as
input to indexing. |
|
| + remark | Ref. /chapter[1]/sect1[5]/remark[2] |
| Original | Traduction | If you begin with a handler metadata mapping approach, it is
possible to switch at any point to a classic Spring XML mapping approach.
So you don't close off this option. For this reason, I find that I
often start a web application using metadata mapping. |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[6]/title[1] |
| Original | Traduction | Other uses of metadata attributes |
|
| + para | Ref. /chapter[1]/sect1[6]/para[1] |
| Original | Traduction | Other uses of metadata attributes appear to be growing in
popularity. As of March 2004, an attribute-based validation package for
Spring is in development. The one-off setup cost of attribute parsing
looks more attractive, when the potential for multiple uses is considered. |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[7]/title[1] |
| Original | Traduction | Adding support for additional metadata APIs |
|
| + para | Ref. /chapter[1]/sect1[7]/para[1] |
| Original | Traduction | Should you wish to provide support for another metadata API it is
easy to do so. |
|
| + para | Ref. /chapter[1]/sect1[7]/para[2] |
| Original | Traduction | Simply implement the org.springframework.metadata.Attributes
interface as a facade for your metadata API. You can then include this
object in your bean definitions as shown above. |
|
| + para | Ref. /chapter[1]/sect1[7]/para[3] |
| Original | Traduction | All framework services that use metadata, such as AOP
metadata-driven autoproxying, will then automatically be able to use your
new metadata provider. |
|
| + remark | Ref. /chapter[1]/sect1[7]/remark[1] |
| Original | Traduction | We expect to add support for Java 1.5 attributes--probably as an
add-on to the Spring core--in Q2 2004. |
|
| |
|