From 278488d11edb034c5b0a4e3d9e25e0321f14696d Mon Sep 17 00:00:00 2001 From: Mark Pollack Date: Tue, 9 Jun 2009 21:29:53 +0000 Subject: [PATCH] Documentation cleanup. Move classic aop-api chapter to appendix Move JMS 1.0.2 related documentation to appendix Remove references to Commons Annotations and source level metadata abstraction Fix program highlighting issue in beans.xml --- spring-framework-reference/src/beans.xml | 2 +- .../src/classic-aop-spring.xml | 1955 +++++++++++++++++ .../src/classic-spring.xml | 98 + spring-framework-reference/src/jms.xml | 1852 ++++++++-------- spring-framework-reference/src/metadata.xml | 631 ++---- .../src/spring-framework-reference.xml | 1 + 6 files changed, 3199 insertions(+), 1340 deletions(-) create mode 100644 spring-framework-reference/src/classic-aop-spring.xml diff --git a/spring-framework-reference/src/beans.xml b/spring-framework-reference/src/beans.xml index f2f62ea5334..699bb587110 100644 --- a/spring-framework-reference/src/beans.xml +++ b/spring-framework-reference/src/beans.xml @@ -2525,7 +2525,7 @@ public class ReplacementComputeValue implements MethodReplacer { The bean definition to deploy the original class and specify the method override would look like this: - <bean id="myValueCalculator class="x.y.z.MyValueCalculator"> + <bean id="myValueCalculator" class="x.y.z.MyValueCalculator"> <!-- arbitrary method replacement --> <replaced-method name="computeValue" replacer="replacementComputeValue"> diff --git a/spring-framework-reference/src/classic-aop-spring.xml b/spring-framework-reference/src/classic-aop-spring.xml new file mode 100644 index 00000000000..e20cf2e9116 --- /dev/null +++ b/spring-framework-reference/src/classic-aop-spring.xml @@ -0,0 +1,1955 @@ + + + + Classic Spring AOP Usage +
+ In this chapter we discuss + the lower-level Spring AOP APIs and the AOP support used in Spring 1.2 applications. + For new applications, we recommend the use of the Spring 2.0 AOP support + described in the AOP chapter, but when working with existing applications, + or when reading books and articles, you may come across Spring 1.2 style examples. + Spring 2.0 is fully backwards compatible with Spring 1.2 and everything described + in this chapter is fully supported in Spring 2.0. + + +
+ +
+ Pointcut API in Spring + + Let's look at how Spring handles the crucial pointcut concept. + +
+ Concepts + + Spring's pointcut model enables pointcut reuse independent of + advice types. It's possible to target different advice using the same + pointcut. + + The org.springframework.aop.Pointcut interface + is the central interface, used to target advices to particular classes + and methods. The complete interface is shown below: + + + + Splitting the Pointcut interface into two parts + allows reuse of class and method matching parts, and fine-grained + composition operations (such as performing a "union" with another method + matcher). + + The ClassFilter interface is used to restrict + the pointcut to a given set of target classes. If the + matches() method always returns true, all target + classes will be matched: + + + + The MethodMatcher interface is normally more + important. The complete interface is shown below: + + + + The matches(Method, Class) method is used to + test whether this pointcut will ever match a given method on a target + class. This evaluation can be performed when an AOP proxy is created, to + avoid the need for a test on every method invocation. If the 2-argument + matches method returns true for a given method, and the + isRuntime() method for the MethodMatcher returns + true, the 3-argument matches method will be invoked on every method + invocation. This enables a pointcut to look at the arguments passed to + the method invocation immediately before the target advice is to + execute. + + Most MethodMatchers are static, meaning that their + isRuntime() method returns false. In this case, the + 3-argument matches method will never be invoked. + + + If possible, try to make pointcuts static, allowing the AOP + framework to cache the results of pointcut evaluation when an AOP proxy + is created. + +
+ +
+ Operations on pointcuts + + Spring supports operations on pointcuts: notably, + union and intersection. + + + + Union means the methods that either pointcut matches. + + + Intersection means the methods that both pointcuts match. + + + Union is usually more useful. + + + Pointcuts can be composed using the static methods in the + org.springframework.aop.support.Pointcuts class, or + using the ComposablePointcut class in the same + package. However, using AspectJ pointcut expressions is usually a + simpler approach. + + + +
+ +
+ AspectJ expression pointcuts + + Since 2.0, the most important type of pointcut used by Spring is + org.springframework.aop.aspectj.AspectJExpressionPointcut. + This is a pointcut that uses an AspectJ supplied library to parse an AspectJ + pointcut expression string. + + See the previous chapter for a discussion of supported AspectJ pointcut + primitives. + +
+ +
+ Convenience pointcut implementations + + Spring provides several convenient pointcut implementations. Some + can be used out of the box; others are intended to be subclassed in + application-specific pointcuts. + +
+ Static pointcuts + + Static pointcuts are based on method and target class, and + cannot take into account the method's arguments. Static pointcuts are + sufficient - and best - for most usages. It's possible for Spring to + evaluate a static pointcut only once, when a method is first invoked: + after that, there is no need to evaluate the pointcut again with each + method invocation. + + Let's consider some static pointcut implementations included + with Spring. + +
+ Regular expression pointcuts + + One obvious way to specify static pointcuts is regular + expressions. Several AOP frameworks besides Spring make this + possible. + org.springframework.aop.support.Perl5RegexpMethodPointcut + is a generic regular expression pointcut, using Perl 5 regular + expression syntax. The Perl5RegexpMethodPointcut + class depends on Jakarta ORO for regular expression matching. Spring + also provides the JdkRegexpMethodPointcut class + that uses the regular expression support in JDK 1.4+. + + Using the Perl5RegexpMethodPointcut class, + you can provide a list of pattern Strings. If any of these is a + match, the pointcut will evaluate to true. (So the result is + effectively the union of these pointcuts.) + + The usage is shown below: + + <bean id="settersAndAbsquatulatePointcut" + class="org.springframework.aop.support.Perl5RegexpMethodPointcut"> + <property name="patterns"> + <list> + <value>.*set.*</value> + <value>.*absquatulate</value> + </list> + </property> +</bean> + + Spring provides a convenience class, + RegexpMethodPointcutAdvisor, that allows us to + also reference an Advice (remember that an Advice can be an + interceptor, before advice, throws advice etc.). Behind the scenes, + Spring will use a JdkRegexpMethodPointcut. Using + RegexpMethodPointcutAdvisor simplifies wiring, + as the one bean encapsulates both pointcut and advice, as shown + below: + + <bean id="settersAndAbsquatulateAdvisor" + class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> + <property name="advice"> + <ref local="beanNameOfAopAllianceInterceptor"/> + </property> + <property name="patterns"> + <list> + <value>.*set.*</value> + <value>.*absquatulate</value> + </list> + </property> +</bean> + + RegexpMethodPointcutAdvisor can be used + with any Advice type. +
+ +
+ Attribute-driven pointcuts + + An important type of static pointcut is a + metadata-driven pointcut. This uses the values + of metadata attributes: typically, source-level metadata. +
+
+ +
+ Dynamic pointcuts + + Dynamic pointcuts are costlier to evaluate than static + pointcuts. They take into account method + arguments, as well as static information. This + means that they must be evaluated with every method invocation; the + result cannot be cached, as arguments will vary. + + The main example is the control flow + pointcut. + +
+ Control flow pointcuts + + Spring control flow pointcuts are conceptually similar to + AspectJ cflow pointcuts, although less + powerful. (There is currently no way to specify that a pointcut + executes below a join point matched by another pointcut.) + A control flow pointcut matches + the current call stack. For example, it might fire if the join point + was invoked by a method in the com.mycompany.web + package, or by the SomeCaller class. Control flow + pointcuts are specified using the + org.springframework.aop.support.ControlFlowPointcut + class. + Control flow pointcuts are significantly more expensive to + evaluate at runtime than even other dynamic pointcuts. In Java 1.4, + the cost is about 5 times that of other dynamic pointcuts. + +
+
+
+ +
+ Pointcut superclasses + + Spring provides useful pointcut superclasses to help you to + implement your own pointcuts. + + Because static pointcuts are most useful, you'll probably subclass + StaticMethodMatcherPointcut, as shown below. This requires implementing + just one abstract method (although it's possible to override other + methods to customize behavior): + + class TestStaticPointcut extends StaticMethodMatcherPointcut { + + public boolean matches(Method m, Class targetClass) { + // return true if custom criteria match + } +}There are also superclasses for dynamic pointcuts. + + You can use custom pointcuts with any advice type in Spring 1.0 + RC2 and above. +
+ +
+ Custom pointcuts + + Because pointcuts in Spring AOP are Java classes, rather than + language features (as in AspectJ) it's possible to declare custom + pointcuts, whether static or dynamic. Custom pointcuts in Spring can be + arbitrarily complex. However, using the AspectJ pointcut expression + language is recommended if possible. + + + Later versions of Spring may offer support for "semantic + pointcuts" as offered by JAC: for example, "all methods that change + instance variables in the target object." + +
+
+ +
+ Advice API in Spring + + Let's now look at how Spring AOP handles advice. + +
+ Advice lifecycles + + Each advice is a Spring bean. An advice instance can be shared across all + advised objects, or unique + to each advised object. This corresponds to + per-class or per-instance + advice. + + Per-class advice is used most often. It is appropriate for generic + advice such as transaction advisors. These do not depend on the state of + the proxied object or add new state; they merely act on the method and + arguments. + + Per-instance advice is appropriate for introductions, to support + mixins. In this case, the advice adds state to the proxied + object. + + It's possible to use a mix of shared and per-instance advice in + the same AOP proxy. +
+ +
+ Advice types in Spring + + Spring provides several advice types out of the box, and is + extensible to support arbitrary advice types. Let us look at the basic + concepts and standard advice types. + +
+ Interception around advice + + The most fundamental advice type in Spring is + interception around advice. + + Spring is compliant with the AOP Alliance interface for around + advice using method interception. MethodInterceptors implementing + around advice should implement the following interface: + + public interface MethodInterceptor extends Interceptor { + + Object invoke(MethodInvocation invocation) throws Throwable; +} + + The MethodInvocation argument to the + invoke() method exposes the method being invoked; + the target join point; the AOP proxy; and the arguments to the method. + The invoke() method should return the + invocation's result: the return value of the join point. + + A simple MethodInterceptor implementation + looks as follows: + + public class DebugInterceptor implements MethodInterceptor { + + public Object invoke(MethodInvocation invocation) throws Throwable { + System.out.println("Before: invocation=[" + invocation + "]"); + Object rval = invocation.proceed(); + System.out.println("Invocation returned"); + return rval; + } +} + + Note the call to the MethodInvocation's + proceed() method. This proceeds down the + interceptor chain towards the join point. Most interceptors will invoke + this method, and return its return value. However, a + MethodInterceptor, like any around advice, can return a different + value or throw an exception rather than invoke the proceed method. + However, you don't want to do this without good reason! + + MethodInterceptors offer interoperability with other AOP + Alliance-compliant AOP implementations. The other advice types + discussed in the remainder of this section implement common AOP + concepts, but in a Spring-specific way. While there is an advantage in + using the most specific advice type, stick with MethodInterceptor + around advice if you are likely to want to run the aspect in another + AOP framework. Note that pointcuts are not currently interoperable + between frameworks, and the AOP Alliance does not currently define + pointcut interfaces. +
+ +
+ Before advice + + A simpler advice type is a before + advice. This does not need a + MethodInvocation object, since it will only be + called before entering the method. + + The main advantage of a before advice is that there is no need + to invoke the proceed() method, and therefore no + possibility of inadvertently failing to proceed down the interceptor + chain. + + The MethodBeforeAdvice interface is shown + below. (Spring's API design would allow for field before advice, + although the usual objects apply to field interception and it's + unlikely that Spring will ever implement it). + + public interface MethodBeforeAdvice extends BeforeAdvice { + + void before(Method m, Object[] args, Object target) throws Throwable; +} + + Note the return type is void. Before + advice can insert custom behavior before the join point executes, but + cannot change the return value. If a before advice throws an + exception, this will abort further execution of the interceptor chain. + The exception will propagate back up the interceptor chain. If it is + unchecked, or on the signature of the invoked method, it will be + passed directly to the client; otherwise it will be wrapped in an + unchecked exception by the AOP proxy. + + An example of a before advice in Spring, which counts all method + invocations: + + public class CountingBeforeAdvice implements MethodBeforeAdvice { + + private int count; + + public void before(Method m, Object[] args, Object target) throws Throwable { + ++count; + } + + public int getCount() { + return count; + } +} + + Before advice can be used with any pointcut. +
+ +
+ Throws advice + + Throws advice is invoked after + the return of the join point if the join point threw an exception. + Spring offers typed throws advice. Note that this means that the + org.springframework.aop.ThrowsAdvice interface does + not contain any methods: It is a tag interface identifying that the + given object implements one or more typed throws advice methods. These + should be in the form of: + + afterThrowing([Method, args, target], subclassOfThrowable) + + Only the last argument is required. The method signatures may + have either one or four arguments, depending on whether the advice + method is interested in the method and arguments. The following + classes are examples of throws advice. + + The advice below is invoked if a RemoteException + is thrown (including subclasses): + + // Do something with remote exception + + The following advice is invoked if a + ServletException is thrown. Unlike the above + advice, it declares 4 arguments, so that it has access to the invoked + method, method arguments and target object: + + // Do something with all arguments + + The final example illustrates how these two methods could be + used in a single class, which handles both + RemoteException and + ServletException. Any number of throws advice + methods can be combined in a single class. + + public static class CombinedThrowsAdvice implements ThrowsAdvice { + + public void afterThrowing(RemoteException ex) throws Throwable { + // Do something with remote exception + } + + public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) { + // Do something with all arguments + } +} + + Note: If a throws-advice method throws an exception itself, + it will override the original exception (i.e. change the exception thrown to the user). + The overriding exception will typically be a RuntimeException; this is compatible with + any method signature. However, if a throws-advice method throws a checked exception, + it will have to match the declared exceptions of the target method and is hence to some + degree coupled to specific target method signatures. Do not throw an undeclared + checked exception that is incompatible with the target method's signature! + + Throws advice can be used with any pointcut. +
+ +
+ After Returning advice + + An after returning advice in Spring must implement the + org.springframework.aop.AfterReturningAdvice + interface, shown below: + + public interface AfterReturningAdvice extends Advice { + + void afterReturning(Object returnValue, Method m, Object[] args, Object target) + throws Throwable; +} + + An after returning advice has access to the return value (which + it cannot modify), invoked method, methods arguments and + target. + + The following after returning advice counts all successful + method invocations that have not thrown exceptions: + + public class CountingAfterReturningAdvice implements AfterReturningAdvice { + + private int count; + + public void afterReturning(Object returnValue, Method m, Object[] args, Object target) + throws Throwable { + ++count; + } + + public int getCount() { + return count; + } +} + + This advice doesn't change the execution path. If it throws an + exception, this will be thrown up the interceptor chain instead of the + return value. + + After returning advice can be used with any pointcut. +
+ +
+ Introduction advice + Spring treats introduction advice as a special kind of + interception advice. + Introduction requires an IntroductionAdvisor, + and an IntroductionInterceptor, implementing the + following interface: + + public interface IntroductionInterceptor extends MethodInterceptor { + + boolean implementsInterface(Class intf); +} + + The invoke() method inherited from the AOP + Alliance MethodInterceptor interface must implement + the introduction: that is, if the invoked method is on an introduced + interface, the introduction interceptor is responsible for handling + the method call - it cannot invoke proceed(). + + + + Introduction advice cannot be used with any pointcut, as it + applies only at class, rather than method, level. You can only use + introduction advice with the IntroductionAdvisor, + which has the following methods: + + + + public interface IntroductionAdvisor extends Advisor, IntroductionInfo { + + ClassFilter getClassFilter(); + + void validateInterfaces() throws IllegalArgumentException; +} + +public interface IntroductionInfo { + + Class[] getInterfaces(); +} + + + + There is no MethodMatcher, and hence no + Pointcut, associated with introduction advice. Only + class filtering is logical. + + + + The getInterfaces() method returns the + interfaces introduced by this advisor. + + The + + validateInterfaces() + + method is used internally to see whether or not the introduced interfaces can be implemented by the configured + + IntroductionInterceptor + + . + + Let's look at a simple example from the Spring test suite. Let's + suppose we want to introduce the following interface to one or more + objects: + + + + + public interface Lockable { + void lock(); + void unlock(); + boolean locked(); +} + + + + + This illustrates a mixin. We + want to be able to cast advised objects to Lockable, whatever their + type, and call lock and unlock methods. If we call the lock() method, + we want all setter methods to throw a + LockedException. Thus we can add an aspect that + provides the ability to make objects immutable, without them having + any knowledge of it: a good example of AOP. + + + + Firstly, we'll need an + IntroductionInterceptor that does the heavy + lifting. In this case, we extend the + org.springframework.aop.support.DelegatingIntroductionInterceptor + convenience class. We could implement IntroductionInterceptor + directly, but using + DelegatingIntroductionInterceptor is best for most + cases. + + + + The DelegatingIntroductionInterceptor is + designed to delegate an introduction to an actual implementation of + the introduced interface(s), concealing the use of interception to do + so. The delegate can be set to any object using a constructor + argument; the default delegate (when the no-arg constructor is used) + is this. Thus in the example below, the delegate is the + LockMixin subclass of + DelegatingIntroductionInterceptor. Given a delegate + (by default itself), a + DelegatingIntroductionInterceptor instance looks + for all interfaces implemented by the delegate (other than + IntroductionInterceptor), and will support introductions against any + of them. It's possible for subclasses such as + LockMixin to call the + suppressInterface(Class intf) method to suppress + interfaces that should not be exposed. However, no matter how many + interfaces an IntroductionInterceptor is prepared + to support, the IntroductionAdvisor used will + control which interfaces are actually exposed. An introduced interface + will conceal any implementation of the same interface by the + target. + + + + Thus LockMixin subclasses + DelegatingIntroductionInterceptor and implements + Lockable itself. The superclass automatically picks up that Lockable + can be supported for introduction, so we don't need to specify that. + We could introduce any number of interfaces in this way. + + + + Note the use of the locked instance variable. + This effectively adds additional state to that held in the target + object. + + + + + public class LockMixin extends DelegatingIntroductionInterceptor + implements Lockable { + + private boolean locked; + + public void lock() { + this.locked = true; + } + + public void unlock() { + this.locked = false; + } + + public boolean locked() { + return this.locked; + } + + public Object invoke(MethodInvocation invocation) throws Throwable { + if (locked() && invocation.getMethod().getName().indexOf("set") == 0) + throw new LockedException(); + return super.invoke(invocation); + } + +} + + + + + Often it isn't necessary to override the invoke() + method: the + DelegatingIntroductionInterceptor + implementation - which calls the delegate method if the method is + introduced, otherwise proceeds towards the join point - is usually + sufficient. In the present case, we need to add a check: no setter + method can be invoked if in locked mode. + + + + The introduction advisor required is simple. All it needs to do + is hold a distinct LockMixin instance, and specify + the introduced interfaces - in this case, just + Lockable. A more complex example might take a + reference to the introduction interceptor (which would be defined as a + prototype): in this case, there's no configuration relevant for a + LockMixin, so we simply create it using + new. + + + + + public class LockMixinAdvisor extends DefaultIntroductionAdvisor { + + public LockMixinAdvisor() { + super(new LockMixin(), Lockable.class); + } +} + + + + + We can apply this advisor very simply: it requires no + configuration. (However, it is necessary: It's + impossible to use an IntroductionInterceptor + without an IntroductionAdvisor.) As usual with + introductions, the advisor must be per-instance, as it is stateful. We + need a different instance of LockMixinAdvisor, and + hence LockMixin, for each advised object. The + advisor comprises part of the advised object's state. + + + + We can apply this advisor programmatically, using the + Advised.addAdvisor() method, or (the recommended + way) in XML configuration, like any other advisor. All proxy creation + choices discussed below, including "auto proxy creators," correctly + handle introductions and stateful mixins. + + +
+
+
+ +
+ Advisor API in Spring + + In Spring, an Advisor is an aspect that contains just a single advice + object associated with a pointcut expression. + + Apart from the special case of introductions, any advisor can be + used with any advice. + org.springframework.aop.support.DefaultPointcutAdvisor + is the most commonly used advisor class. For example, it can be used with + a MethodInterceptor, BeforeAdvice or + ThrowsAdvice. + + It is possible to mix advisor and advice types in Spring in the same + AOP proxy. For example, you could use a interception around advice, throws + advice and before advice in one proxy configuration: Spring will + automatically create the necessary interceptor chain. +
+ +
+ Using the ProxyFactoryBean to create AOP proxies + + If you're using the Spring IoC container (an ApplicationContext or + BeanFactory) for your business objects - and you should be! - you will want + to use one of Spring's AOP FactoryBeans. (Remember that a factory bean + introduces a layer of indirection, enabling it to create objects of a + different type.) + + + The Spring 2.0 AOP support also uses factory beans under the covers. + + + The basic way to create an AOP proxy in Spring is to use the + org.springframework.aop.framework.ProxyFactoryBean. + This gives complete control over the pointcuts and advice that will apply, + and their ordering. However, there are simpler options that are preferable + if you don't need such control. + +
+ Basics + + The ProxyFactoryBean, like other Spring + FactoryBean implementations, introduces a level of + indirection. If you define a ProxyFactoryBean with + name foo, what objects referencing + foo see is not the + ProxyFactoryBean instance itself, but an object + created by the ProxyFactoryBean's implementation of + the getObject() method. This method will create an + AOP proxy wrapping a target object. + + One of the most important benefits of using a + ProxyFactoryBean or another IoC-aware class to create + AOP proxies, is that it means that advices and pointcuts can also be + managed by IoC. This is a powerful feature, enabling certain approaches + that are hard to achieve with other AOP frameworks. For example, an + advice may itself reference application objects (besides the target, + which should be available in any AOP framework), benefiting from all the + pluggability provided by Dependency Injection. +
+ +
+ JavaBean properties + + In common with most FactoryBean implementations + provided with Spring, the ProxyFactoryBean class is + itself a JavaBean. Its properties are used to: + + + + Specify the target you want to proxy. + + + Specify whether to use CGLIB (see below and also the section entitled + ). + + + + Some key properties are inherited from + org.springframework.aop.framework.ProxyConfig (the + superclass for all AOP proxy factories in Spring). These key properties include: + + + + + proxyTargetClass: true if the + target class is to be proxied, rather than the target class' interfaces. + If this property value is set to true, then CGLIB proxies + will be created (but see also below the section entitled + ). + + + + + optimize: controls whether or not aggressive + optimizations are applied to proxies created via CGLIB. + One should not blithely use this setting unless one fully understands + how the relevant AOP proxy handles optimization. This is currently used only + for CGLIB proxies; it has no effect with JDK dynamic proxies. + + + + frozen: if a proxy configuration is frozen, + then changes to the configuration are no longer allowed. This is useful both as + a slight optimization and for those cases when you don't want callers to be able + to manipulate the proxy (via the Advised interface) + after the proxy has been created. The default value of this property is + false, so changes such as adding additional advice are allowed. + + + + exposeProxy: determines whether or not the current + proxy should be exposed in a ThreadLocal so that + it can be accessed by the target. If a target needs to obtain + the proxy and the exposeProxy property is set to + true, the target can use the + AopContext.currentProxy() method. + + + + + aopProxyFactory: the implementation of + AopProxyFactory to use. Offers a way of + customizing whether to use dynamic proxies, CGLIB or any other proxy + strategy. The default implementation will choose dynamic proxies or + CGLIB appropriately. There should be no need to use this property; + it is intended to allow the addition of new proxy types in Spring 1.1. + + + + + Other properties specific to ProxyFactoryBean include: + + + + + proxyInterfaces: array of String interface + names. If this isn't supplied, a CGLIB proxy for the target class + will be used (but see also below the section entitled + ). + + + + + interceptorNames: String array of + Advisor, interceptor or other advice + names to apply. Ordering is significant, on a first come-first served + basis. That is to say that the first interceptor in the list + will be the first to be able to intercept the invocation. + + + The names are bean names in the current factory, including + bean names from ancestor factories. You can't mention bean + references here since doing so would result in the + ProxyFactoryBean ignoring the singleton + setting of the advice. + + + You can append an interceptor name with an asterisk + (*). This will result in the application of all + advisor beans with names starting with the part before the asterisk + to be applied. An example of using this feature can be found in + . + + + + + singleton: whether or not the factory should return a single + object, no matter how often the getObject() + method is called. Several FactoryBean + implementations offer such a method. The default value is + true. If you want to use stateful advice - + for example, for stateful mixins - use prototype advices along + with a singleton value of false. + + + +
+ +
+ JDK- and CGLIB-based proxies + + This section serves as the definitive documentation on how the + ProxyFactoryBean chooses to create one of + either a JDK- and CGLIB-based proxy for a particular target object + (that is to be proxied). + + + + The behavior of the ProxyFactoryBean with regard + to creating JDK- or CGLIB-based proxies changed between versions 1.2.x and + 2.0 of Spring. The ProxyFactoryBean now + exhibits similar semantics with regard to auto-detecting interfaces + as those of the TransactionProxyFactoryBean class. + + + + If the class of a target object that is to be proxied (hereafter simply + referred to as the target class) doesn't implement any interfaces, then + a CGLIB-based proxy will be created. This is the easiest scenario, because + JDK proxies are interface based, and no interfaces means JDK proxying + isn't even possible. One simply plugs in the target bean, and specifies the + list of interceptors via the interceptorNames property. + Note that a CGLIB-based proxy will be created even if the + proxyTargetClass property of the + ProxyFactoryBean has been set to false. + (Obviously this makes no sense, and is best removed from the bean + definition because it is at best redundant, and at worst confusing.) + + + If the target class implements one (or more) interfaces, then the type of + proxy that is created depends on the configuration of the + ProxyFactoryBean. + + + If the proxyTargetClass property of the + ProxyFactoryBean has been set to true, + then a CGLIB-based proxy will be created. This makes sense, and is in + keeping with the principle of least surprise. Even if the + proxyInterfaces property of the + ProxyFactoryBean has been set to one or more + fully qualified interface names, the fact that the + proxyTargetClass property is set to + true will cause + CGLIB-based proxying to be in effect. + + + If the proxyInterfaces property of the + ProxyFactoryBean has been set to one or more + fully qualified interface names, then a JDK-based proxy will be created. + The created proxy will implement all of the interfaces that were specified + in the proxyInterfaces property; if the target class + happens to implement a whole lot more interfaces than those specified in + the proxyInterfaces property, that is all well and + good but those additional interfaces will not be implemented by the + returned proxy. + + + If the proxyInterfaces property of the + ProxyFactoryBean has not been + set, but the target class does implement one (or more) + interfaces, then the ProxyFactoryBean will auto-detect + the fact that the target class does actually implement at least one interface, + and a JDK-based proxy will be created. The interfaces that are actually + proxied will be all of the interfaces that the target + class implements; in effect, this is the same as simply supplying a list + of each and every interface that the target class implements to the + proxyInterfaces property. However, it is significantly less + work, and less prone to typos. + + +
+ +
+ Proxying interfaces + + + Let's look at a simple example of ProxyFactoryBean + in action. This example involves: + + + + + A target bean that will be proxied. This + is the "personTarget" bean definition in the example below. + + + + An Advisor and an Interceptor used to provide advice. + + + + An AOP proxy bean definition specifying the target object (the + personTarget bean) and the interfaces to proxy, along with the + advices to apply. + + + + <bean id="personTarget" class="com.mycompany.PersonImpl"> + <property name="name"><value>Tony</value></property> + <property name="age"><value>51</value></property> +</bean> + +<bean id="myAdvisor" class="com.mycompany.MyAdvisor"> + <property name="someProperty"><value>Custom string property value</value></property> +</bean> + +<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"> +</bean> + +<bean id="person" + class="org.springframework.aop.framework.ProxyFactoryBean"> + <property name="proxyInterfaces"><value>com.mycompany.Person</value></property> + + <property name="target"><ref local="personTarget"/></property> + <property name="interceptorNames"> + <list> + <value>myAdvisor</value> + <value>debugInterceptor</value> + </list> + </property> +</bean> + + Note that the interceptorNames property takes a + list of String: the bean names of the interceptor or advisors in the + current factory. Advisors, interceptors, before, after returning and + throws advice objects can be used. The ordering of advisors is + significant. + + + You might be wondering why the list doesn't hold bean + references. The reason for this is that if the ProxyFactoryBean's + singleton property is set to false, it must be able to return + independent proxy instances. If any of the advisors is itself a + prototype, an independent instance would need to be returned, so it's + necessary to be able to obtain an instance of the prototype from the + factory; holding a reference isn't sufficient. + + + The "person" bean definition above can be used in place of a + Person implementation, as follows: + + Person person = (Person) factory.getBean("person"); + + Other beans in the same IoC context can express a strongly typed + dependency on it, as with an ordinary Java object: + + <bean id="personUser" class="com.mycompany.PersonUser"> + <property name="person"><ref local="person" /></property> +</bean> + + The PersonUser class in this example would + expose a property of type Person. As far as it's concerned, the AOP + proxy can be used transparently in place of a "real" person + implementation. However, its class would be a dynamic proxy class. It + would be possible to cast it to the Advised interface + (discussed below). + + It's possible to conceal the distinction between target and proxy + using an anonymous inner bean, as follows. Only the + ProxyFactoryBean definition is different; the advice + is included only for completeness: + + <bean id="myAdvisor" class="com.mycompany.MyAdvisor"> + <property name="someProperty"><value>Custom string property value</value></property> +</bean> + +<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/> + +<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean"> + <property name="proxyInterfaces"><value>com.mycompany.Person</value></property> + <!-- Use inner bean, not local reference to target --> + <property name="target"> + <bean class="com.mycompany.PersonImpl"> + <property name="name"><value>Tony</value></property> + <property name="age"><value>51</value></property> + </bean> + </property> + <property name="interceptorNames"> + <list> + <value>myAdvisor</value> + <value>debugInterceptor</value> + </list> + </property> +</bean> + + This has the advantage that there's only one object of type + Person: useful if we want to prevent users of the + application context from obtaining a reference to the un-advised object, or + need to avoid any ambiguity with Spring IoC + autowiring. There's also arguably an advantage in + that the ProxyFactoryBean definition is self-contained. However, there + are times when being able to obtain the un-advised target from the + factory might actually be an advantage: for + example, in certain test scenarios. +
+ +
+ Proxying classes + + What if you need to proxy a class, rather than one or more + interfaces? + + Imagine that in our example above, there was no + Person interface: we needed to advise a class called + Person that didn't implement any business interface. + In this case, you can configure Spring to use CGLIB proxying, rather + than dynamic proxies. Simply set the proxyTargetClass + property on the ProxyFactoryBean above to true. While it's best to + program to interfaces, rather than classes, the ability to advise + classes that don't implement interfaces can be useful when working with + legacy code. (In general, Spring isn't prescriptive. While it makes it + easy to apply good practices, it avoids forcing a particular + approach.) + + If you want to, you can force the use of CGLIB in any case, even if + you do have interfaces. + + CGLIB proxying works by generating a subclass of the target class + at runtime. Spring configures this generated subclass to delegate method + calls to the original target: the subclass is used to implement the + Decorator pattern, weaving in the advice. + + CGLIB proxying should generally be transparent to users. However, + there are some issues to consider: + + + + Final methods can't be advised, as they + can't be overridden. + + + + You'll need the CGLIB 2 binaries on your classpath; dynamic + proxies are available with the JDK. + + + + There's little performance difference between CGLIB proxying and + dynamic proxies. As of Spring 1.0, dynamic proxies are slightly faster. + However, this may change in the future. Performance should not be a + decisive consideration in this case. +
+ +
+ Using 'global' advisors + + By appending an asterisk to an interceptor name, all advisors with + bean names matching the part before the asterisk, will be added to the + advisor chain. This can come in handy if you need to add a standard set + of 'global' advisors: +<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> + <property name="target" ref="service"/> + <property name="interceptorNames"> + <list> + <value>global*</value> + </list> + </property> +</bean> + +<bean id="global_debug" class="org.springframework.aop.interceptor.DebugInterceptor"/> +<bean id="global_performance" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/> + +
+
+ +
+ Concise proxy definitions + + Especially when defining transactional proxies, you may end up with + many similar proxy definitions. The use of parent and child bean + definitions, along with inner bean definitions, can result in much cleaner + and more concise proxy definitions. + + First a parent, template, bean definition is + created for the proxy: + + <bean id="txProxyTemplate" abstract="true" + class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> + <property name="transactionManager" ref="transactionManager"/> + <property name="transactionAttributes"> + <props> + <prop key="*">PROPAGATION_REQUIRED</prop> + </props> + </property> +</bean> + + This will never be instantiated itself, so may actually be + incomplete. Then each proxy which needs to be created is just a child bean + definition, which wraps the target of the proxy as an inner bean + definition, since the target will never be used on its own + anyway.<bean id="myService" parent="txProxyTemplate"> + <property name="target"> + <bean class="org.springframework.samples.MyServiceImpl"> + </bean> + </property> +</bean> + + It is of course possible to override properties from the parent + template, such as in this case, the transaction propagation + settings:<bean id="mySpecialService" parent="txProxyTemplate"> + <property name="target"> + <bean class="org.springframework.samples.MySpecialServiceImpl"> + </bean> + </property> + <property name="transactionAttributes"> + <props> + <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> + <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> + <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop> + <prop key="store*">PROPAGATION_REQUIRED</prop> + </props> + </property> +</bean> + + Note that in the example above, we have explicitly marked the parent + bean definition as abstract by using the + abstract attribute, as described previously, so that it may + not actually ever be instantiated. Application contexts (but not simple + bean factories) will by default pre-instantiate all singletons. It is therefore + important (at least for singleton beans) that if you have a (parent) + bean definition which you intend to use only as a template, and this + definition specifies a class, you must make sure to set the + abstract attribute to true, + otherwise the application context will actually try to pre-instantiate + it. +
+ +
+ Creating AOP proxies programmatically with the ProxyFactory + + It's easy to create AOP proxies programmatically using Spring. This + enables you to use Spring AOP without dependency on Spring IoC. + + The following listing shows creation of a proxy for a target object, + with one interceptor and one advisor. The interfaces implemented by the + target object will automatically be proxied: + + ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl); +factory.addInterceptor(myMethodInterceptor); +factory.addAdvisor(myAdvisor); +MyBusinessInterface tb = (MyBusinessInterface) factory.getProxy(); + + The first step is to construct an object of type + org.springframework.aop.framework.ProxyFactory. You can + create this with a target object, as in the above example, or specify the + interfaces to be proxied in an alternate constructor. + + You can add interceptors or advisors, and manipulate them for the + life of the ProxyFactory. If you add an + IntroductionInterceptionAroundAdvisor you can cause the proxy to implement + additional interfaces. + + There are also convenience methods on ProxyFactory (inherited from + AdvisedSupport) which allow you to add other advice types + such as before and throws advice. AdvisedSupport is the superclass of both + ProxyFactory and ProxyFactoryBean. + + + Integrating AOP proxy creation with the IoC framework is best + practice in most applications. We recommend that you externalize + configuration from Java code with AOP, as in general. + +
+ +
+ Manipulating advised objects + + However you create AOP proxies, you can manipulate them using the + org.springframework.aop.framework.Advised interface. + Any AOP proxy can be cast to this interface, whichever other interfaces it + implements. This interface includes the following methods: + + Advisor[] getAdvisors(); + +void addAdvice(Advice advice) throws AopConfigException; + +void addAdvice(int pos, Advice advice) + throws AopConfigException; + +void addAdvisor(Advisor advisor) throws AopConfigException; + +void addAdvisor(int pos, Advisor advisor) throws AopConfigException; + +int indexOf(Advisor advisor); + +boolean removeAdvisor(Advisor advisor) throws AopConfigException; + +void removeAdvisor(int index) throws AopConfigException; + +boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException; + +boolean isFrozen(); + + The getAdvisors() method will return an Advisor + for every advisor, interceptor or other advice type that has been added to + the factory. If you added an Advisor, the returned advisor at this index + will be the object that you added. If you added an interceptor or other + advice type, Spring will have wrapped this in an advisor with a pointcut + that always returns true. Thus if you added a + MethodInterceptor, the advisor returned for this index + will be an DefaultPointcutAdvisor returning your + MethodInterceptor and a pointcut that matches all + classes and methods. + + The addAdvisor() methods can be used to add any + Advisor. Usually the advisor holding pointcut and advice will be the + generic DefaultPointcutAdvisor, which can be used with + any advice or pointcut (but not for introductions). + + By default, it's possible to add or remove advisors or interceptors + even once a proxy has been created. The only restriction is that it's + impossible to add or remove an introduction advisor, as existing proxies + from the factory will not show the interface change. (You can obtain a new + proxy from the factory to avoid this problem.) + + A simple example of casting an AOP proxy to the + Advised interface and examining and manipulating its + advice: + + Advised advised = (Advised) myObject; +Advisor[] advisors = advised.getAdvisors(); +int oldAdvisorCount = advisors.length; +System.out.println(oldAdvisorCount + " advisors"); + +// Add an advice like an interceptor without a pointcut +// Will match all proxied methods +// Can use for interceptors, before, after returning or throws advice +advised.addAdvice(new DebugInterceptor()); + +// Add selective advice using a pointcut +advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice)); + +assertEquals("Added two advisors", + oldAdvisorCount + 2, advised.getAdvisors().length); + + + It's questionable whether it's advisable (no pun intended) to + modify advice on a business object in production, although there are no + doubt legitimate usage cases. However, it can be very useful in + development: for example, in tests. I have sometimes found it very useful + to be able to add test code in the form of an interceptor or other advice, + getting inside a method invocation I want to test. (For example, the + advice can get inside a transaction created for that method: for example, + to run SQL to check that a database was correctly updated, before marking + the transaction for roll back.) + + + Depending on how you created the proxy, you can usually set a + frozen flag, in which case the + Advised isFrozen() method will + return true, and any attempts to modify advice through addition or removal + will result in an AopConfigException. The ability to + freeze the state of an advised object is useful in some cases, for + example, to prevent calling code removing a security interceptor. It may + also be used in Spring 1.1 to allow aggressive optimization if runtime + advice modification is known not to be required. +
+ +
+ Using the "autoproxy" facility + + So far we've considered explicit creation of AOP proxies using a + ProxyFactoryBean or similar factory bean. + + Spring also allows us to use "autoproxy" bean definitions, which can + automatically proxy selected bean definitions. This is built on Spring + "bean post processor" infrastructure, which enables modification of any + bean definition as the container loads. + + In this model, you set up some special bean definitions in your XML + bean definition file to configure the auto proxy infrastructure. This + allows you just to declare the targets eligible for autoproxying: you + don't need to use ProxyFactoryBean. + + There are two ways to do this: + + + + Using an autoproxy creator that refers to specific beans in the + current context. + + + + A special case of autoproxy creation that deserves to be + considered separately; autoproxy creation driven by source-level + metadata attributes. + + + +
+ Autoproxy bean definitions + + The org.springframework.aop.framework.autoproxy + package provides the following standard autoproxy creators. + +
+ BeanNameAutoProxyCreator + + The BeanNameAutoProxyCreator class is a + BeanPostProcessor that automatically creates AOP proxies + for beans with names matching literal values or wildcards. + + <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> + <property name="beanNames"><value>jdk*,onlyJdk</value></property> + <property name="interceptorNames"> + <list> + <value>myInterceptor</value> + </list> + </property> +</bean> + + As with ProxyFactoryBean, there is an + interceptorNames property rather than a list of interceptors, to allow + correct behavior for prototype advisors. Named "interceptors" can be + advisors or any advice type. + + As with auto proxying in general, the main point of using + BeanNameAutoProxyCreator is to apply the same + configuration consistently to multiple objects, with minimal + volume of configuration. It is a popular choice for applying + declarative transactions to multiple objects. + + Bean definitions whose names match, such as "jdkMyBean" and + "onlyJdk" in the above example, are plain old bean definitions with + the target class. An AOP proxy will be created automatically by the + BeanNameAutoProxyCreator. The same advice will be + applied to all matching beans. Note that if advisors are used (rather + than the interceptor in the above example), the pointcuts may apply + differently to different beans. +
+ +
+ DefaultAdvisorAutoProxyCreator + + A more general and extremely powerful auto proxy creator is + DefaultAdvisorAutoProxyCreator. This will + automagically apply eligible advisors in the current context, without + the need to include specific bean names in the autoproxy advisor's + bean definition. It offers the same merit of consistent configuration + and avoidance of duplication as + BeanNameAutoProxyCreator. + + Using this mechanism involves: + + + + Specifying a + DefaultAdvisorAutoProxyCreator bean + definition. + + + + Specifying any number of Advisors in the same or related + contexts. Note that these must be Advisors, + not just interceptors or other advices. This is necessary because + there must be a pointcut to evaluate, to check the eligibility of + each advice to candidate bean definitions. + + + + The DefaultAdvisorAutoProxyCreator will + automatically evaluate the pointcut contained in each advisor, to see + what (if any) advice it should apply to each business object (such as + "businessObject1" and "businessObject2" in the example). + + This means that any number of advisors can be applied + automatically to each business object. If no pointcut in any of the + advisors matches any method in a business object, the object will not + be proxied. As bean definitions are added for new business objects, + they will automatically be proxied if necessary. + + Autoproxying in general has the advantage of making it + impossible for callers or dependencies to obtain an un-advised object. + Calling getBean("businessObject1") on this ApplicationContext will + return an AOP proxy, not the target business object. (The "inner bean" + idiom shown earlier also offers this benefit.) + + <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> + +<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> + <property name="transactionInterceptor" ref="transactionInterceptor"/> +</bean> + +<bean id="customAdvisor" class="com.mycompany.MyAdvisor"/> + +<bean id="businessObject1" class="com.mycompany.BusinessObject1"> + <!-- Properties omitted --> +</bean> + +<bean id="businessObject2" class="com.mycompany.BusinessObject2"/> + + + The DefaultAdvisorAutoProxyCreator is very + useful if you want to apply the same advice consistently to many + business objects. Once the infrastructure definitions are in place, + you can simply add new business objects without including specific + proxy configuration. You can also drop in additional aspects very + easily - for example, tracing or performance monitoring aspects - with + minimal change to configuration. + + The DefaultAdvisorAutoProxyCreator offers support for filtering + (using a naming convention so that only certain advisors are + evaluated, allowing use of multiple, differently configured, + AdvisorAutoProxyCreators in the same factory) and ordering. Advisors + can implement the org.springframework.core.Ordered + interface to ensure correct ordering if this is an issue. The + TransactionAttributeSourceAdvisor used in the above example has a + configurable order value; the default setting is unordered. +
+ +
+ AbstractAdvisorAutoProxyCreator + + This is the superclass of DefaultAdvisorAutoProxyCreator. You + can create your own autoproxy creators by subclassing this class, in + the unlikely event that advisor definitions offer insufficient + customization to the behavior of the framework + DefaultAdvisorAutoProxyCreator. +
+
+ +
+ Using metadata-driven auto-proxying + + A particularly important type of autoproxying is driven by + metadata. This produces a similar programming model to .NET + ServicedComponents. Instead of using XML deployment + descriptors as in EJB, configuration for transaction management and + other enterprise services is held in source-level attributes. + + In this case, you use the + DefaultAdvisorAutoProxyCreator, in combination with + Advisors that understand metadata attributes. The metadata specifics are + held in the pointcut part of the candidate advisors, rather than in the + autoproxy creation class itself. + + This is really a special case of the + DefaultAdvisorAutoProxyCreator, but deserves + consideration on its own. (The metadata-aware code is in the pointcuts + contained in the advisors, not the AOP framework itself.) + + The /attributes directory of the JPetStore + sample application shows the use of attribute-driven autoproxying. In + this case, there's no need to use the + TransactionProxyFactoryBean. Simply defining + transactional attributes on business objects is sufficient, because of + the use of metadata-aware pointcuts. The bean definitions include the + following code, in /WEB-INF/declarativeServices.xml. + Note that this is generic, and can be used outside the JPetStore: + + <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> + +<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> + <property name="transactionInterceptor" ref="transactionInterceptor"/> +</bean> + +<bean id="transactionInterceptor" + class="org.springframework.transaction.interceptor.TransactionInterceptor"> + <property name="transactionManager" ref="transactionManager"/> + <property name="transactionAttributeSource"> + <bean class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource"> + <property name="attributes" ref="attributes"/> + </bean> + </property> +</bean> + +<bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/> + + The DefaultAdvisorAutoProxyCreator bean + definition (the name is not significant, hence it can even be omitted) + will pick up all eligible pointcuts in the current application context. + In this case, the "transactionAdvisor" bean definition, of type + TransactionAttributeSourceAdvisor, will apply to + classes or methods carrying a transaction attribute. The + TransactionAttributeSourceAdvisor depends on a TransactionInterceptor, + via constructor dependency. The example resolves this via autowiring. + The AttributesTransactionAttributeSource depends on + an implementation of the + org.springframework.metadata.Attributes interface. In + this fragment, the "attributes" bean satisfies this, using the Jakarta + Commons Attributes API to obtain attribute information. (The application + code must have been compiled using the Commons Attributes compilation + task.) + + The /annotation directory of the JPetStore + sample application contains an analogous example for auto-proxying + driven by JDK 1.5+ annotations. The following configuration enables + automatic detection of Spring's Transactional + annotation, leading to implicit proxies for beans containing that + annotation: + + <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> + +<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> + <property name="transactionInterceptor" ref="transactionInterceptor"/> +</bean> + +<bean id="transactionInterceptor" + class="org.springframework.transaction.interceptor.TransactionInterceptor"> + <property name="transactionManager" ref="transactionManager"/> + <property name="transactionAttributeSource"> + <bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/> + </property> +</bean> + + The TransactionInterceptor defined here depends + on a PlatformTransactionManager definition, which is + not included in this generic file (although it could be) because it will + be specific to the application's transaction requirements (typically + JTA, as in this example, or Hibernate, JDO or JDBC): + + <bean id="transactionManager" + class="org.springframework.transaction.jta.JtaTransactionManager"/> + + + If you require only declarative transaction management, using + these generic XML definitions will result in Spring automatically + proxying all classes or methods with transaction attributes. You won't + need to work directly with AOP, and the programming model is similar to + that of .NET ServicedComponents. + + + This mechanism is extensible. It's possible to do autoproxying + based on custom attributes. You need to: + + + + Define your custom attribute. + + + + Specify an Advisor with the necessary advice, including a + pointcut that is triggered by the presence of the custom attribute + on a class or method. You may be able to use an existing advice, + merely implementing a static pointcut that picks up the custom + attribute. + + + + It's possible for such advisors to be unique to each advised class + (for example, mixins): they simply need to be defined as prototype, + rather than singleton, bean definitions. For example, the + LockMixin introduction interceptor from the Spring + test suite, shown above, could be used in conjunction with an + attribute-driven pointcut to target a mixin, as shown here. We use the + generic DefaultPointcutAdvisor, configured using + JavaBean properties: + + <bean id="lockMixin" class="org.springframework.aop.LockMixin" + scope="prototype"/> + +<bean id="lockableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" + scope="prototype"> + <property name="pointcut" ref="myAttributeAwarePointcut"/> + <property name="advice" ref="lockMixin"/> +</bean> + +<bean id="anyBean" class="anyclass" ... + + If the attribute aware pointcut matches any methods in the + anyBean or other bean definitions, the mixin will be + applied. Note that both lockMixin and + lockableAdvisor definitions are prototypes. The + myAttributeAwarePointcut pointcut can be a singleton + definition, as it doesn't hold state for individual advised + objects. +
+
+ +
+ Using TargetSources + + Spring offers the concept of a TargetSource, + expressed in the org.springframework.aop.TargetSource + interface. This interface is responsible for returning the "target object" + implementing the join point. The TargetSource + implementation is asked for a target instance each time the AOP proxy + handles a method invocation. + + Developers using Spring AOP don't normally need to work directly + with TargetSources, but this provides a powerful means of supporting + pooling, hot swappable and other sophisticated targets. For example, a + pooling TargetSource can return a different target instance for each + invocation, using a pool to manage instances. + + If you do not specify a TargetSource, a default implementation is + used that wraps a local object. The same target is returned for each + invocation (as you would expect). + + Let's look at the standard target sources provided with Spring, and + how you can use them. + + + When using a custom target source, your target will usually need + to be a prototype rather than a singleton bean definition. This allows + Spring to create a new target instance when required. + + +
+ Hot swappable target sources + + The + org.springframework.aop.target.HotSwappableTargetSource + exists to allow the target of an AOP proxy to be switched while allowing + callers to keep their references to it. + + Changing the target source's target takes effect immediately. The + HotSwappableTargetSource is threadsafe. + + You can change the target via the swap() method + on HotSwappableTargetSource as follows: + + HotSwappableTargetSource swapper = + (HotSwappableTargetSource) beanFactory.getBean("swapper"); +Object oldTarget = swapper.swap(newTarget); + + The XML definitions required look as follows: + + <bean id="initialTarget" class="mycompany.OldTarget"/> + +<bean id="swapper" class="org.springframework.aop.target.HotSwappableTargetSource"> + <constructor-arg ref="initialTarget"/> +</bean> + +<bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean"> + <property name="targetSource" ref="swapper"/> +</bean> + + The above swap() call changes the target of the + swappable bean. Clients who hold a reference to that bean will be + unaware of the change, but will immediately start hitting the new + target. + + Although this example doesn't add any advice - and it's not + necessary to add advice to use a TargetSource - of + course any TargetSource can be used in conjunction + with arbitrary advice. +
+ +
+ Pooling target sources + + Using a pooling target source provides a similar programming model + to stateless session EJBs, in which a pool of identical instances is + maintained, with method invocations going to free objects in the + pool. + + A crucial difference between Spring pooling and SLSB pooling is + that Spring pooling can be applied to any POJO. As with Spring in + general, this service can be applied in a non-invasive way. + + Spring provides out-of-the-box support for Jakarta Commons Pool + 1.3, which provides a fairly efficient pooling implementation. You'll + need the commons-pool Jar on your application's classpath to use this + feature. It's also possible to subclass + org.springframework.aop.target.AbstractPoolingTargetSource + to support any other pooling API. + + Sample configuration is shown below: + + <bean id="businessObjectTarget" class="com.mycompany.MyBusinessObject" + scope="prototype"> + ... properties omitted +</bean> + +<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource"> + <property name="targetBeanName" value="businessObjectTarget"/> + <property name="maxSize" value="25"/> +</bean> + +<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean"> + <property name="targetSource" ref="poolTargetSource"/> + <property name="interceptorNames" value="myInterceptor"/> +</bean> + + Note that the target object - "businessObjectTarget" in the + example - must be a prototype. This allows the + PoolingTargetSource implementation to create new + instances of the target to grow the pool as necessary. See the havadoc + for AbstractPoolingTargetSource and the concrete + subclass you wish to use for information about its properties: "maxSize" + is the most basic, and always guaranteed to be present. + + In this case, "myInterceptor" is the name of an interceptor that + would need to be defined in the same IoC context. However, it isn't + necessary to specify interceptors to use pooling. If you want only + pooling, and no other advice, don't set the interceptorNames property at + all. + + It's possible to configure Spring so as to be able to cast any + pooled object to the + org.springframework.aop.target.PoolingConfig + interface, which exposes information about the configuration and current + size of the pool through an introduction. You'll need to define an + advisor like this: + + <bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> + <property name="targetObject" ref="poolTargetSource"/> + <property name="targetMethod" value="getPoolingConfigMixin"/> +</bean> + + This advisor is obtained by calling a convenience method on the + AbstractPoolingTargetSource class, hence the use of + MethodInvokingFactoryBean. This advisor's name ("poolConfigAdvisor" + here) must be in the list of interceptors names in the ProxyFactoryBean + exposing the pooled object. + + The cast will look as follows: + + + + + Pooling stateless service objects is not usually necessary. We + don't believe it should be the default choice, as most stateless objects + are naturally thread safe, and instance pooling is problematic if + resources are cached. + + + Simpler pooling is available using autoproxying. It's possible to + set the TargetSources used by any autoproxy creator. +
+ +
+ Prototype target sources + + Setting up a "prototype" target source is similar to a pooling + TargetSource. In this case, a new instance of the target will be created + on every method invocation. Although the cost of creating a new object + isn't high in a modern JVM, the cost of wiring up the new object + (satisfying its IoC dependencies) may be more expensive. Thus you + shouldn't use this approach without very good reason. + + To do this, you could modify the + poolTargetSource definition shown above as follows. + (I've also changed the name, for clarity.) + + + +]]> + + There's only one property: the name of the target bean. + Inheritance is used in the TargetSource implementations to ensure + consistent naming. As with the pooling target source, the target bean + must be a prototype bean definition. +
+ +
+ <classname>ThreadLocal</classname> target sources + + ThreadLocal target sources are useful if you need an object to be + created for each incoming request (per thread that is). The concept of a + ThreadLocal provide a JDK-wide facility to + transparently store resource alongside a thread. Setting up a + ThreadLocalTargetSource is pretty much the same as was explained for the + other types of target source: + + + +]]> + + + ThreadLocals come with serious issues (potentially + resulting in memory leaks) when incorrectly using them in a + multi-threaded and multi-classloader environments. One should always + consider wrapping a threadlocal in some other class and never directly + use the ThreadLocal itself (except of course in the wrapper class). + Also, one should always remember to correctly set and unset (where the + latter simply involved a call to ThreadLocal.set(null)) the resource + local to the thread. Unsetting should be done in any case since not + unsetting it might result in problematic behavior. Spring's ThreadLocal + support does this for you and should always be considered in favor + of using ThreadLocals without other proper handling + code. + +
+
+ +
+ Defining new <interfacename>Advice</interfacename> types + + Spring AOP is designed to be extensible. While the interception + implementation strategy is presently used internally, it is possible to + support arbitrary advice types in addition to the out-of-the-box interception around advice, + before, throws advice and after returning advice. + + The org.springframework.aop.framework.adapter + package is an SPI package allowing support for new custom advice types to + be added without changing the core framework. The only constraint on a + custom Advice type is that it must implement the + org.aopalliance.aop.Advice tag interface. + + Please refer to the + org.springframework.aop.framework.adapter package's + Javadocs for further information. +
+ +
+ Further resources + + Please refer to the Spring sample applications for further examples + of Spring AOP: + + + + The JPetStore's default configuration illustrates the use of the + TransactionProxyFactoryBean for declarative transaction + management. + + + + The /attributes directory of the JPetStore + illustrates the use of attribute-driven declarative transaction management. + + + +
+ +
diff --git a/spring-framework-reference/src/classic-spring.xml b/spring-framework-reference/src/classic-spring.xml index 53a879f0e18..82a121cad22 100644 --- a/spring-framework-reference/src/classic-spring.xml +++ b/spring-framework-reference/src/classic-spring.xml @@ -352,4 +352,102 @@ ... + +
+ JMS Usage + + One of the benefits of Spring's JMS support is to shield the user + from differences between the JMS 1.0.2 and 1.1 APIs. (For a description of + the differences between the two APIs see sidebar on Domain Unification). + Since it is now common to encounter only the JMS 1.1 API the use of + classes that are based on the JMS 1.0.2 API has been deprecated in Spring + 3.0. This section describes Spring JMS support for the JMS 1.0.2 + deprecated classes. + + + Domain Unification + + There are two major releases of the JMS specification, 1.0.2 and + 1.1. + + JMS 1.0.2 defined two types of messaging domains, point-to-point + (Queues) and publish/subscribe (Topics). The 1.0.2 API reflected these + two messaging domains by providing a parallel class hierarchy for each + domain. As a result, a client application became domain specific in its + use of the JMS API. JMS 1.1 introduced the concept of domain unification + that minimized both the functional differences and client API + differences between the two domains. As an example of a functional + difference that was removed, if you use a JMS 1.1 provider you can + transactionally consume a message from one domain and produce a message + on the other using the same + Session. + + + The JMS 1.1 specification was released in April 2002 and + incorporated as part of J2EE 1.4 in November 2003. As a result, common + J2EE 1.3 application servers which are still in widespread use (such + as BEA WebLogic 8.1 and IBM WebSphere 5.1) are based on JMS + 1.0.2. + + + +
+ JmsTemplate + + Located in the package + org.springframework.jms.core the class + JmsTemplate102 provides all of the features of + the JmsTemplate described the JMS chapter, but is + based on the JMS 1.0.2 API instead of the JMS 1.1 API. As a consequence, + if you are using JmsTemplate102 you need to set the boolean property + pubSubDomain to configure the + JmsTemplate with knowledge of what JMS domain is + being used. By default the value of this property is false, indicating + that the point-to-point domain, Queues, will be used. +
+ +
+ Asynchronous Message Reception + + MessageListenerAdapter's + are used in conjunction with Spring's message + listener containers to support asynchronous message reception by + exposing almost any class as a Message-driven POJO. If you are using the + JMS 1.0.2 API, you will want to use the 1.0.2 specific classes such as + MessageListenerAdapter102, + SimpleMessageListenerContainer102, and + DefaultMessageListenerContainer102. These classes + provide the same functionality as the JMS 1.1 based counterparts but + rely only on the JMS 1.0.2 API. +
+ +
+ Connections + + The ConnectionFactory interface is part of + the JMS specification and serves as the entry point for working with + JMS. Spring provides an implementation of the + ConnectionFactory interface, + SingleConnectionFactory102, based on the JMS + 1.0.2 API that will return the same Connection on + all createConnection calls and ignore calls to + close. You will need to set the boolean + property pubSubDomain to indicate which messaging + domain is used as SingleConnectionFactory102 will + always explicitly differentiate between a + javax.jms.QueueConnection and a + javax.jmsTopicConnection. +
+ +
+ Transaction Management + + In a JMS 1.0.2 environment the class + JmsTransactionManager102 provides support for + managing JMS transactions for a single Connection Factory. Please refer + to the reference documentation on JMS Transaction + Management for more information on this functionality. +
+
diff --git a/spring-framework-reference/src/jms.xml b/spring-framework-reference/src/jms.xml index 4698d73e036..8e05ce3c4d8 100644 --- a/spring-framework-reference/src/jms.xml +++ b/spring-framework-reference/src/jms.xml @@ -1,7 +1,6 @@ - +"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> JMS (Java Message Service) @@ -9,37 +8,16 @@ Introduction Spring provides a JMS integration framework that simplifies the use - of the JMS API and shields the user from differences between the JMS 1.0.2 - and 1.1 APIs. - JMS can be roughly divided into two areas of functionality, namely the - production and consumption of messages. The JmsTemplate - class is used for message production and synchronous message reception. For - asynchronous reception similar to J2EE's message-driven bean style, Spring - provides a number of message listener containers that are used to create - Message-Driven POJOs (MDPs). + of the JMS API much like Spring's integration does for the JDBC + API. - - Domain Unification - There are two major releases of the JMS specification, 1.0.2 and - 1.1. - JMS 1.0.2 defined two types of messaging domains, point-to-point - (Queues) and publish/subscribe (Topics). The 1.0.2 API reflected these two - messaging domains by providing a parallel class hierarchy for each domain. - As a result, a client application became domain specific in its use of - the JMS API. JMS 1.1 introduced the concept of domain unification that - minimized both the functional differences and client API differences - between the two domains. As an example of a functional difference that was - removed, if you use a JMS 1.1 provider you can transactionally consume a - message from one domain and produce a message on the other using the same - Session. - - - The JMS 1.1 specification was released in April 2002 and - incorporated as part of J2EE 1.4 in November 2003. As a result, common - J2EE 1.3 application servers which are still in widespread use (such as - BEA WebLogic 8.1 and IBM WebSphere 5.1) are based on JMS 1.0.2. - - + JMS can be roughly divided into two areas of functionality, namely + the production and consumption of messages. The + JmsTemplate class is used for message production + and synchronous message reception. For asynchronous reception similar to + J2EE's message-driven bean style, Spring provides a number of message + listener containers that are used to create Message-Driven POJOs + (MDPs). The package org.springframework.jms.core provides the core functionality for using JMS. It contains JMS template classes @@ -54,16 +32,20 @@ to the user. The package org.springframework.jms.support - provides JMSException translation functionality. The translation converts - the checked JMSException hierarchy to a mirrored - hierarchy of unchecked exceptions. If there are any provider specific - subclasses of the checked javax.jms.JMSException, - this exception is wrapped in the unchecked - UncategorizedJmsException. - The package org.springframework.jms.support.converter provides a - MessageConverter abstraction to convert between Java objects - and JMS messages. - The package org.springframework.jms.support.destination provides + provides JMSException translation functionality. + The translation converts the checked JMSException + hierarchy to a mirrored hierarchy of unchecked exceptions. If there are + any provider specific subclasses of the checked + javax.jms.JMSException, this exception is wrapped + in the unchecked UncategorizedJmsException. + + The package + org.springframework.jms.support.converter provides a + MessageConverter abstraction to convert + between Java objects and JMS messages. + + The package + org.springframework.jms.support.destination provides various strategies for managing JMS destinations, such as providing a service locator for destinations stored in JNDI. @@ -71,281 +53,325 @@ org.springframework.jms.connection provides an implementation of the ConnectionFactory suitable for use in standalone applications. It also contains an implementation of - Spring's PlatformTransactionManager for - JMS (the cunningly named JmsTransactionManager). - This allows for seamless integration of JMS as a transactional resource into + Spring's PlatformTransactionManager for JMS + (the cunningly named JmsTransactionManager). This + allows for seamless integration of JMS as a transactional resource into Spring's transaction management mechanisms. - +
- Using Spring JMS + Using Spring JMS -
- <classname>JmsTemplate</classname> +
+ <classname>JmsTemplate</classname> - There are two variants of the functionality offered by the - JmsTemplate: the JmsTemplate - uses the JMS 1.1 API, and the subclass JmsTemplate102 - uses the JMS 1.0.2 API. + The JmsTemplate class is the central class + in the JMS core package. It simplifies the use of JMS since it handles + the creation and release of resources when sending or synchronously + recieving messages. - Code that uses the JmsTemplate only needs to - implement callback interfaces giving them a clearly defined contract. The - MessageCreator callback interface creates a message - given a Session provided by the calling code - in JmsTemplate. In order to allow for more complex - usage of the JMS API, the callback SessionCallback - provides the user with the JMS session and the callback - ProducerCallback exposes a - Session and - MessageProducer pair. + Code that uses the JmsTemplate only needs + to implement callback interfaces giving them a clearly defined high + level contract. The MessageCreator callback + interface creates a message given a + Session provided by the calling code in + JmsTemplate. In order to allow for more complex + usage of the JMS API, the callback + SessionCallback provides the user with the JMS + session and the callback ProducerCallback exposes + a Session and + MessageProducer pair. - The JMS API exposes two types of send methods, one that takes - delivery mode, priority, and time-to-live as Quality of Service (QOS) - parameters and one that takes no QOS parameters which uses default values. - Since there are many send methods in JmsTemplate, - the setting of the QOS parameters have been exposed as bean properties to - avoid duplication in the number of send methods. Similarly, the timeout - value for synchronous receive calls is set using the property - setReceiveTimeout. + The JMS API exposes two types of send methods, one that takes + delivery mode, priority, and time-to-live as Quality of Service (QOS) + parameters and one that takes no QOS parameters which uses default + values. Since there are many send methods in + JmsTemplate, the setting of the QOS parameters + have been exposed as bean properties to avoid duplication in the number + of send methods. Similarly, the timeout value for synchronous receive + calls is set using the property + setReceiveTimeout. - Some JMS providers allow the setting of default QOS values - administratively through the configuration of the ConnectionFactory. This - has the effect that a call to MessageProducer's - send method send(Destination destination, Message - message) will use different QOS default values than those - specified in the JMS specification. In order to provide consistent - management of QOS values, the JmsTemplate must - therefore be specifically enabled to use its own QOS values by setting - the boolean property isExplicitQosEnabled - to true. + Some JMS providers allow the setting of default QOS values + administratively through the configuration of the ConnectionFactory. + This has the effect that a call to + MessageProducer's send method + send(Destination destination, Message message) + will use different QOS default values than those specified in the JMS + specification. In order to provide consistent management of QOS values, + the JmsTemplate must therefore be specifically + enabled to use its own QOS values by setting the boolean property + isExplicitQosEnabled to + true. - - Instances of the JmsTemplate class are - thread-safe once configured. This is important because - it means that you can configure a single instance of a - JmsTemplate and then safely inject this - shared reference into multiple collaborators. To be - clear, the JmsTemplate is stateful, in that it - maintains a reference to a ConnectionFactory, - but this state is not conversational state. - -
+ + Instances of the JmsTemplate class are + thread-safe once configured. This is important + because it means that you can configure a single instance of a + JmsTemplate and then safely inject this + shared reference into multiple collaborators. To + be clear, the JmsTemplate is stateful, in that + it maintains a reference to a + ConnectionFactory, but this state is + not conversational state. + +
-
- Connections - - The JmsTemplate requires a reference to a - ConnectionFactory. The - ConnectionFactory is part of the JMS - specification and serves as the entry point for working with JMS. It is - used by the client application as a factory to create connections with - the JMS provider and encapsulates various configuration parameters, many - of which are vendor specific such as SSL configuration options. +
+ Connections - When using JMS inside an EJB, the vendor provides implementations - of the JMS interfaces so that they can participate in declarative - transaction management and perform pooling of connections and session. - In order to use this implementation, J2EE containers typically require - that you declare a JMS connection factory as a - resource-ref inside the EJB or servlet deployment - descriptors. To ensure the use of these features with the - JmsTemplate inside an EJB, the client application - should ensure that it references the managed implementation of the - ConnectionFactory. + The JmsTemplate requires a reference to a + ConnectionFactory. The + ConnectionFactory is part of the JMS + specification and serves as the entry point for working with JMS. It is + used by the client application as a factory to create connections with + the JMS provider and encapsulates various configuration parameters, many + of which are vendor specific such as SSL configuration options. - Spring provides an implementation of the - ConnectionFactory interface, - SingleConnectionFactory, that will return the - same Connection on all - createConnection calls and ignore calls to - close. This is useful for testing and - standalone environments so that the same connection can be used for - multiple JmsTemplate calls that may span any - number of transactions. SingleConnectionFactory - takes a reference to a standard ConnectionFactory - that would typically come from JNDI. -
- -
- Destination Management - - Destinations, like ConnectionFactories, are JMS administered - objects that can be stored and retrieved in JNDI. When configuring a - Spring application context you can use the JNDI factory class - JndiObjectFactoryBean to perform dependency - injection on your object's references to JMS destinations. However, - often this strategy is cumbersome if there are a large number of - destinations in the application or if there are advanced destination - management features unique to the JMS provider. Examples of such - advanced destination management would be the creation of dynamic - destinations or support for a hierarchical namespace of destinations. - The JmsTemplate delegates the resolution of a - destination name to a JMS destination object to an implementation of the - interface DestinationResolver. - DynamicDestinationResolver is the default - implementation used by JmsTemplate and - accommodates resolving dynamic destinations. A - JndiDestinationResolver is also provided that - acts as a service locator for destinations contained in JNDI and - optionally falls back to the behavior contained in - DynamicDestinationResolver. + When using JMS inside an EJB, the vendor provides implementations + of the JMS interfaces so that they can participate in declarative + transaction management and perform pooling of connections and session. + In order to use this implementation, J2EE containers typically require + that you declare a JMS connection factory as a + resource-ref inside the EJB or servlet deployment + descriptors. To ensure the use of these features with the + JmsTemplate inside an EJB, the client application + should ensure that it references the managed implementation of the + ConnectionFactory. - Quite often the destinations used in a JMS application are only - known at runtime and therefore cannot be administratively created when - the application is deployed. This is often because there is shared - application logic between interacting system components that create - destinations at runtime according to a well-known naming convention. - Even though the creation of dynamic destinations are not part of the JMS - specification, most vendors have provided this functionality. Dynamic - destinations are created with a name defined by the user which - differentiates them from temporary destinations and are often not - registered in JNDI. The API used to create dynamic destinations varies - from provider to provider since the properties associated with the - destination are vendor specific. However, a simple implementation choice - that is sometimes made by vendors is to disregard the warnings in the - JMS specification and to use the TopicSession - method createTopic(String topicName) or the - QueueSession method - createQueue(String queueName) to create a new - destination with default destination properties. Depending on the vendor - implementation, DynamicDestinationResolver may - then also create a physical destination instead of only resolving - one. +
+ Caching Messaging Resources - The boolean property pubSubDomain is used to - configure the JmsTemplate with knowledge of what - JMS domain is being used. By default the value of this property is - false, indicating that the point-to-point domain, Queues, will be used. - In the 1.0.2 implementation the value of this property determines if the - JmsTemplate's send operations will send a message - to a Queue or to a Topic. - This flag has no effect on send operations for - the 1.1 implementation. However, in both implementations, this property - determines the behavior of dynamic destination resolution via - implementations of the DestinationResolver interface. + The standard API involves creating many intermediate objects. To + send a message the following 'API' walk is performed - You can also configure the JmsTemplate with - a default destination via the property - defaultDestination. The default destination will be - used with send and receive operations that do not refer to a specific - destination. -
- -
- Message Listener Containers + ConnectionFactory->Connection->Session->MessageProducer->send - One of the most common uses of JMS messages in the EJB world is to - drive message-driven beans (MDBs). Spring offers a solution to create - message-driven POJOs (MDPs) in a way that does not tie a user to an EJB - container. (See the section entitled - for detailed coverage of Spring's MDP support.) + Between the ConnectionFactory and the Send operation there are + three intermediate objects that are created and destroyed. To optimise + the resource usage and increase performance two implementations of + IConnectionFactory are provided. +
- A message listener container is used to receive messages - from a JMS message queue and drive the MessageListener that is - injected into it. The listener container is responsible for all - threading of message reception and dispatches into the listener - for processing. A message listener container is the intermediary between an - MDP and a messaging provider, and takes care of registering to receive messages, - participating in transactions, resource acquisition and release, exception - conversion and suchlike. This allows you as an application developer to write - the (possibly complex) business logic associated with receiving a message - (and possibly responding to it), and delegates boilerplate JMS - infrastructure concerns to the framework. +
+ SingleConnectionFactory - There are three standard JMS message listener containers packaged - with Spring, each with its specialised feature set. + Spring provides an implementation of the + ConnectionFactory interface, + SingleConnectionFactory, that will return the + same Connection on all + createConnection calls and ignore calls to + close. This is useful for testing and + standalone environments so that the same connection can be used for + multiple JmsTemplate calls that may span any + number of transactions. SingleConnectionFactory + takes a reference to a standard + ConnectionFactory that would typically come + from JNDI. +
-
- SimpleMessageListenerContainer +
+ CachingConnectionFactory - This message listener container is the simplest of the three - standard flavors. It simply creates a fixed number of JMS sessions - at startup and uses them throughout the lifespan of the container. - This container doesn't allow for dynamic adaption to runtime demands - or participate in externally managed transactions. However, - it does have the fewest requirements on the JMS provider: This - listener container only requires simple JMS API compliance. -
+ The CachingConnectionFactory extends the + functionality of SingleConnectionFactory and + adds the caching of Sessions, MessageProducers, and MessageConsumers. + The initial cache size is set to 1, use the property + SessionCacheSize to increase the number of cached + sessions. Note that the number of actual cached sessions will be more + than that number as sessions are cached based on their acknowledgment + mode, so there can be up to 4 cached session instances when + SessionCacheSize is set to one, one for each + AcknowledgementMode. MessageProducers and MessageConsumers are cached + within their owning session and also take into account the unique + properties of the producers and consumers when caching. + MessageProducers are cached based on their destination. + MessageConsumers are cached based on a key composed of the + destination, selector, noLocal delivery flag, and the durable + subscription name (if creating durable consumers). +
+
-
- DefaultMessageListenerContainer +
+ Destination Management - This message listener container is the one used in most cases. - In contrast to SimpleMessageListenerContainer, - this container variant does allow for dynamic adaption to runtime - demands and is able to participate in externally managed transactions. - Each received message is registered with an XA transaction - (when configured with a JtaTransactionManager); - processing can take advantage of XA transation semantics. - This listener container strikes a good balance between low - requirements on the JMS provider and good functionality including - transaction participation. -
+ Destinations, like ConnectionFactories, are JMS administered + objects that can be stored and retrieved in JNDI. When configuring a + Spring application context you can use the JNDI factory class + JndiObjectFactoryBean to perform dependency + injection on your object's references to JMS destinations. However, + often this strategy is cumbersome if there are a large number of + destinations in the application or if there are advanced destination + management features unique to the JMS provider. Examples of such + advanced destination management would be the creation of dynamic + destinations or support for a hierarchical namespace of destinations. + The JmsTemplate delegates the resolution of a + destination name to a JMS destination object to an implementation of the + interface DestinationResolver. + DynamicDestinationResolver is the default + implementation used by JmsTemplate and + accommodates resolving dynamic destinations. A + JndiDestinationResolver is also provided that + acts as a service locator for destinations contained in JNDI and + optionally falls back to the behavior contained in + DynamicDestinationResolver. -
- ServerSessionMessageListenerContainer + Quite often the destinations used in a JMS application are only + known at runtime and therefore cannot be administratively created when + the application is deployed. This is often because there is shared + application logic between interacting system components that create + destinations at runtime according to a well-known naming convention. + Even though the creation of dynamic destinations are not part of the JMS + specification, most vendors have provided this functionality. Dynamic + destinations are created with a name defined by the user which + differentiates them from temporary destinations and are often not + registered in JNDI. The API used to create dynamic destinations varies + from provider to provider since the properties associated with the + destination are vendor specific. However, a simple implementation choice + that is sometimes made by vendors is to disregard the warnings in the + JMS specification and to use the TopicSession + method createTopic(String topicName) or the + QueueSession method + createQueue(String queueName) to create a new + destination with default destination properties. Depending on the vendor + implementation, DynamicDestinationResolver may + then also create a physical destination instead of only resolving + one. - This listener container leverages the JMS ServerSessionPool SPI - to allow for dynamic management of JMS sessions. The use of this variety - of message listener container enables the provider to perform dynamic - runtime tuning but, at the expense of requiring the JMS provider to support - the ServerSessionPool SPI. If there is no need for provider-driven runtime - tuning, look at the DefaultMessageListenerContainer - or the SimpleMessageListenerContainer instead. -
-
+ The boolean property pubSubDomain is used to + configure the JmsTemplate with knowledge of what + JMS domain is being used. By default the value of this property is + false, indicating that the point-to-point domain, Queues, will be used. + This property is used by JmsTemplate determines + the behavior of dynamic destination resolution via implementations of + the DestinationResolver interface. -
- Transaction management + You can also configure the JmsTemplate with + a default destination via the property + defaultDestination. The default destination will be + used with send and receive operations that do not refer to a specific + destination. +
- Spring provides a JmsTransactionManager - that manages transactions for a single JMS - ConnectionFactory. This allows JMS applications - to leverage the managed transaction features of Spring as described in - . The JmsTransactionManager - performs local resource transactions, binding a JMS Connection/Session - pair from the specified ConnectionFactory to the - thread. JmsTemplate automatically detects such - transactional resources and operates on them accordingly. +
+ Message Listener Containers - In a J2EE environment, the ConnectionFactory - will pool Connections and Sessions, so those resources are efficiently - reused across transactions. In a standalone environment, using Spring's - SingleConnectionFactory will result in a shared - JMS Connection, with each transaction having its - own independent Session. Alternatively, consider - the use of a provider-specific pooling adapter such as ActiveMQ's - PooledConnectionFactory class. + One of the most common uses of JMS messages in the EJB world is to + drive message-driven beans (MDBs). Spring offers a solution to create + message-driven POJOs (MDPs) in a way that does not tie a user to an EJB + container. (See the section entitled for detailed coverage of + Spring's MDP support.) - JmsTemplate can also be used with the - JtaTransactionManager and an XA-capable JMS - ConnectionFactory for performing distributed - transactions. Note that this requires the use of a JTA transaction - manager as well as a properly XA-configured ConnectionFactory! - (Check your J2EE server's / JMS provider's documentation.) + A message listener container is used to receive messages from a + JMS message queue and drive the MessageListener that is injected into + it. The listener container is responsible for all threading of message + reception and dispatches into the listener for processing. A message + listener container is the intermediary between an MDP and a messaging + provider, and takes care of registering to receive messages, + participating in transactions, resource acquisition and release, + exception conversion and suchlike. This allows you as an application + developer to write the (possibly complex) business logic associated with + receiving a message (and possibly responding to it), and delegates + boilerplate JMS infrastructure concerns to the framework. - Reusing code across a managed and unmanaged transactional - environment can be confusing when using the JMS API to create a - Session from a Connection. - This is because the JMS API has only one factory method to create a - Session and it requires values for the - transaction and acknowledgement modes. In a managed environment, setting - these values is the responsibility of the environment's transactional - infrastructure, so these values are ignored by the vendor's wrapper to - the JMS Connection. When using the JmsTemplate in - an unmanaged environment you can specify these values through the use of - the properties sessionTransacted and - sessionAcknowledgeMode. When using a - PlatformTransactionManager with - JmsTemplate, the template will always be given a - transactional JMS Session. -
+ There are three standard JMS message listener containers packaged + with Spring, each with its specialised feature set. + +
+ SimpleMessageListenerContainer + + This message listener container is the simplest of the three + standard flavors. It simply creates a fixed number of JMS sessions at + startup and uses them throughout the lifespan of the container. This + container doesn't allow for dynamic adaption to runtime demands or + participate in externally managed transactions. However, it does have + the fewest requirements on the JMS provider: This listener container + only requires simple JMS API compliance. +
+ +
+ DefaultMessageListenerContainer + + This message listener container is the one used in most cases. + In contrast to SimpleMessageListenerContainer, + this container variant does allow for dynamic adaption to runtime + demands and is able to participate in externally managed transactions. + Each received message is registered with an XA transaction (when + configured with a JtaTransactionManager); + processing can take advantage of XA transation semantics. This + listener container strikes a good balance between low requirements on + the JMS provider and good functionality including transaction + participation. +
+ +
+ ServerSessionMessageListenerContainer + + This listener container leverages the JMS ServerSessionPool SPI + to allow for dynamic management of JMS sessions. The use of this + variety of message listener container enables the provider to perform + dynamic runtime tuning but, at the expense of requiring the JMS + provider to support the ServerSessionPool SPI. If there is no need for + provider-driven runtime tuning, look at the + DefaultMessageListenerContainer or the + SimpleMessageListenerContainer instead. +
+
+ +
+ Transaction management + + Spring provides a JmsTransactionManager + that manages transactions for a single JMS + ConnectionFactory. This allows JMS applications + to leverage the managed transaction features of Spring as described in + . The + JmsTransactionManager performs local resource + transactions, binding a JMS Connection/Session pair from the specified + ConnectionFactory to the thread. + JmsTemplate automatically detects such + transactional resources and operates on them accordingly. + + In a J2EE environment, the + ConnectionFactory will pool Connections and + Sessions, so those resources are efficiently reused across transactions. + In a standalone environment, using Spring's + SingleConnectionFactory will result in a shared + JMS Connection, with each transaction having its + own independent Session. Alternatively, consider + the use of a provider-specific pooling adapter such as ActiveMQ's + PooledConnectionFactory class. + + JmsTemplate can also be used with the + JtaTransactionManager and an XA-capable JMS + ConnectionFactory for performing distributed + transactions. Note that this requires the use of a JTA transaction + manager as well as a properly XA-configured ConnectionFactory! (Check + your J2EE server's / JMS provider's documentation.) + + Reusing code across a managed and unmanaged transactional + environment can be confusing when using the JMS API to create a + Session from a Connection. + This is because the JMS API has only one factory method to create a + Session and it requires values for the + transaction and acknowledgement modes. In a managed environment, setting + these values is the responsibility of the environment's transactional + infrastructure, so these values are ignored by the vendor's wrapper to + the JMS Connection. When using the JmsTemplate in + an unmanaged environment you can specify these values through the use of + the properties sessionTransacted and + sessionAcknowledgeMode. When using a + PlatformTransactionManager with + JmsTemplate, the template will always be given a + transactional JMS Session. +
- Sending a <interfacename>Message</interfacename> - - The JmsTemplate contains many convenience + Sending a <interfacename>Message</interfacename> + + The JmsTemplate contains many convenience methods to send a message. There are send methods that specify the destination using a javax.jms.Destination object and those that specify the destination using a string for use in a JNDI @@ -353,7 +379,7 @@ default destination. Here is an example that sends a message to a queue using the 1.0.2 implementation. - import javax.jms.ConnectionFactory; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.Queue; @@ -361,7 +387,6 @@ import javax.jms.Session; import org.springframework.jms.core.MessageCreator; import org.springframework.jms.core.JmsTemplate; -import org.springframework.jms.core.JmsTemplate102; public class JmsQueueSender { @@ -369,7 +394,7 @@ public class JmsQueueSender { private Queue queue; public void setConnectionFactory(ConnectionFactory cf) { - this.jmsTemplate = new JmsTemplate102(cf, false); + this.jmsTemplate = new JmsTemplate(cf, false); } public void setQueue(Queue queue) { @@ -383,41 +408,34 @@ public class JmsQueueSender { } }); } -}]]> +} - This example uses the MessageCreator - callback to create a text message from the supplied - Session object and the - JmsTemplate is constructed by passing a reference - to a ConnectionFactory and a boolean specifying - the messaging domain. A zero argument constructor and + This example uses the MessageCreator callback + to create a text message from the supplied Session + object and the JmsTemplate is constructed by + passing a reference to a ConnectionFactory and a + boolean specifying the messaging domain. A zero argument constructor and connectionFactory / queue bean properties are provided and can be used for constructing the instance - (using a BeanFactory or plain Java code). Alternatively, consider - deriving from Spring's JmsGatewaySupport - convenience base class, which provides pre-built bean properties for JMS + (using a BeanFactory or plain Java code). Alternatively, consider deriving + from Spring's JmsGatewaySupport convenience base + class, which provides pre-built bean properties for JMS configuration. - When configuring the JMS 1.0.2 support in an application context, - it is important to remember setting the value of the boolean property - pubSubDomain property in order to indicate if you - want to send to Queues or Topics. - The method send(String destinationName, MessageCreator - creator) lets you send to a message using the string name - of the destination. If these names are registered in JNDI, you should - set the destinationResolver property of the - template to an instance of - JndiDestinationResolver. + creator) lets you send to a message using the string name of + the destination. If these names are registered in JNDI, you should set the + destinationResolver property of the template to an + instance of JndiDestinationResolver. - If you created the JmsTemplate and - specified a default destination, the send(MessageCreator c) + If you created the JmsTemplate and specified + a default destination, the send(MessageCreator c) sends a message to that destination. - -
- Using Message Converters - - In order to facilitate the sending of domain model objects, the + +
+ Using Message Converters + + In order to facilitate the sending of domain model objects, the JmsTemplate has various send methods that take a Java object as an argument for a message's data content. The overloaded methods convertAndSend and @@ -442,16 +460,18 @@ public class JmsQueueSender { Other popular implementations choices you might implement yourself are Converters that use an existing XML marshalling package, such as JAXB, Castor, XMLBeans, or XStream, to create a - TextMessage representing the object. + TextMessage representing the + object. To accommodate the setting of a message's properties, headers, and body that can not be generically encapsulated inside a converter class, - the MessagePostProcessor interface gives you access - to the message after it has been converted, but before it is sent. The - example below demonstrates how to modify a message header and a property after - a java.util.Map is converted to a message. + the MessagePostProcessor interface gives + you access to the message after it has been converted, but before it is + sent. The example below demonstrates how to modify a message header and + a property after a java.util.Map is + converted to a message. - public void sendWithConversion() { Map map = new HashMap(); map.put("Name", "Mark"); map.put("Age", new Integer(47)); @@ -462,9 +482,11 @@ public class JmsQueueSender { return message; } }); -}]]> +} + This results in a message of the form: - MapMessage={ Header={ ... standard headers ... CorrelationID={123-00001} @@ -476,32 +498,35 @@ public class JmsQueueSender { Name={String:Mark} Age={Integer:47} } -}]]> -
+} +
-
- <interfacename>SessionCallback</interfacename> and <interfacename>ProducerCallback</interfacename> - While the send operations cover many common usage scenarios, there +
+ <interfacename>SessionCallback</interfacename> and + <interfacename>ProducerCallback</interfacename> + + While the send operations cover many common usage scenarios, there are cases when you want to perform multiple operations on a JMS Session or MessageProducer. The SessionCallback and ProducerCallback expose the JMS Session and - Session / MessageProducer - pair respectfully. The execute() methods on + Session / + MessageProducer pair respectfully. The + execute() methods on JmsTemplate execute these callback methods. -
+
- Receiving a message + Receiving a message -
- Synchronous Reception +
+ Synchronous Reception - While JMS is typically associated with asynchronous processing, it + While JMS is typically associated with asynchronous processing, it is possible to consume messages synchronously. The overloaded receive(..) methods provide this functionality. During a synchronous receive, the calling thread blocks until a message @@ -509,21 +534,24 @@ public class JmsQueueSender { thread can potentially be blocked indefinitely. The property receiveTimeout specifies how long the receiver should wait before giving up waiting for a message. -
+
-
- Asynchronous Reception - Message-Driven POJOs - - In a fashion similar to a Message-Driven Bean (MDB) in the EJB world, - the Message-Driven POJO (MDP) acts as a receiver for JMS messages. The one - restriction (but see also below for the discussion of the - MessageListenerAdapter class) on an MDP is that it - must implement the javax.jms.MessageListener - interface. Please also be aware that in the case where your POJO will be - receiving messages on multiple threads, it is important to ensure that your - implementation is thread-safe. - Below is a simple implementation of an MDP: - + Asynchronous Reception - Message-Driven POJOs + + In a fashion similar to a Message-Driven Bean (MDB) in the EJB + world, the Message-Driven POJO (MDP) acts as a receiver for JMS + messages. The one restriction (but see also below for the discussion of + the MessageListenerAdapter class) on an MDP is + that it must implement the + javax.jms.MessageListener interface. + Please also be aware that in the case where your POJO will be receiving + messages on multiple threads, it is important to ensure that your + implementation is thread-safe. + + Below is a simple implementation of an MDP: + + import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; @@ -543,76 +571,94 @@ public class ExampleListener implements MessageListener { throw new IllegalArgumentException("Message must be of type TextMessage"); } } -}]]> - Once you've implemented your MessageListener, - it's time to create a message listener container. - Find below an example of how to define and configure one of the message listener - containers that ships with Spring (in this case the - DefaultMessageListenerContainer). - <!-- this is the Message Driven POJO (MDP) --> - +} -]]><!-- and this is the message listener container --> - - - ]]>]]>]]> - Please refer to the Spring Javadoc of the various message - listener containers for a full description of the features supported by each implementation. -
- -
- The <interfacename>SessionAwareMessageListener</interfacename> interface - The SessionAwareMessageListener interface - is a Spring-specific interface that provides a similar contract the JMS - MessageListener interface, but also provides - the message handling method with access to the JMS Session - from which the Message was received. - Once you've implemented your + MessageListener, it's time to create a + message listener container. + + Find below an example of how to define and configure one of the + message listener containers that ships with Spring (in this case the + DefaultMessageListenerContainer). + + <!-- this is the Message Driven POJO (MDP) --> +<bean id="messageListener" class="jmsexample.ExampleListener" /> + +<!-- and this is the message listener container --> +<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> + <property name="connectionFactory" ref="connectionFactory"/> + <property name="destination" ref="destination"/> + <property name="messageListener" ref="messageListener" /> +</bean> + + Please refer to the Spring Javadoc of the various message listener + containers for a full description of the features supported by each + implementation. +
+ +
+ The <interfacename>SessionAwareMessageListener</interfacename> + interface + + The SessionAwareMessageListener + interface is a Spring-specific interface that provides a similar + contract the JMS MessageListener + interface, but also provides the message handling method with access to + the JMS Session from which the + Message was received. + + package org.springframework.jms.listener; public interface SessionAwareMessageListener { - void onMessage(Message message, Session session) ]]> - You can choose to have your MDPs implement this interface (in preference to the - standard JMS MessageListener interface) if you - want your MDPs to be able to respond to any received messages (using the - Session supplied in the - onMessage(Message, Session) method). All of the message listener - container implementations that ship wth Spring have support for MDPs that implement either - the MessageListener or - SessionAwareMessageListener interface. Classes - that implement the SessionAwareMessageListener come - with the caveat that they are then tied to Spring through the interface. The choice of whether - or not to use it is left entirely up to you as an application developer or architect. - Please note that the 'onMessage(..)' method of the - SessionAwareMessageListener interface throws - JMSException. In contrast to the standard JMS - MessageListener interface, when using the - SessionAwareMessageListener interface, it is the responsibility - of the client code to handle any exceptions thrown. -
- -
- The <classname>MessageListenerAdapter</classname> - The MessageListenerAdapter class is the final component in - Spring's asynchronous messaging support: in a nutshell, it allows you to - expose almost any class as a MDP (there are of course some constraints). - - If you are using the JMS 1.0.2 API, you will want to use the - MessageListenerAdapter102 class which provides the exact - same functionality and value add as the MessageListenerAdapter - class, but for the JMS 1.0.2 API. - - Consider the following interface definition. Notice that although the interface extends - neither the MessageListener nor - SessionAwareMessageListener interfaces, it can still - be used as a MDP via the use of the MessageListenerAdapter class. - Notice also how the various message handling methods are strongly typed according to - the contents of the various Message - types that they can receive and handle. - throws JMSException; +} + + You can choose to have your MDPs implement this interface (in + preference to the standard JMS + MessageListener interface) if you want + your MDPs to be able to respond to any received messages (using the + Session supplied in the + onMessage(Message, Session) method). All of the + message listener container implementations that ship wth Spring have + support for MDPs that implement either the + MessageListener or + SessionAwareMessageListener interface. + Classes that implement the + SessionAwareMessageListener come with the + caveat that they are then tied to Spring through the interface. The + choice of whether or not to use it is left entirely up to you as an + application developer or architect. + + Please note that the 'onMessage(..)' method of + the SessionAwareMessageListener interface + throws JMSException. In contrast to the standard + JMS MessageListener interface, when using + the SessionAwareMessageListener + interface, it is the responsibility of the client code to handle any + exceptions thrown. +
+ +
+ The <classname>MessageListenerAdapter</classname> + + The MessageListenerAdapter class is the + final component in Spring's asynchronous messaging support: in a + nutshell, it allows you to expose almost any class + as a MDP (there are of course some constraints). + + Consider the following interface definition. Notice that although + the interface extends neither the + MessageListener nor + SessionAwareMessageListener interfaces, + it can still be used as a MDP via the use of the + MessageListenerAdapter class. Notice also how the + various message handling methods are strongly typed according to the + contents of the various + Message types that they can receive and + handle. + + public interface MessageDelegate { void handleMessage(String message); @@ -621,600 +667,676 @@ public interface SessionAwareMessageListener { void handleMessage(byte[] message); void handleMessage(Serializable message); -}]]> - // implementation elided for clarity... - In particular, note how the above implementation of the MessageDelegate - interface (the above DefaultMessageDelegate class) has - no JMS dependencies at all. It truly is a POJO that we will - make into an MDP via the following configuration. - <!-- this is the Message Driven POJO (MDP) --> - - - - -]]> +} -<!-- and this is the message listener container... --> - - - ]]>]]>]]> - Below is an example of another MDP that can only handle the receiving of - JMS TextMessage messages. Notice how the message handling - method is actually called 'receive' (the name of the message handling - method in a MessageListenerAdapter defaults to - 'handleMessage'), but it is configurable (as you will see below). - Notice also how the 'receive(..)' method is strongly typed to - receive and respond only to JMS TextMessage messages. - public class DefaultMessageDelegate implements MessageDelegate { + // implementation elided for clarity... +} + + In particular, note how the above implementation of the + MessageDelegate interface (the above + DefaultMessageDelegate class) has + no JMS dependencies at all. It truly is a POJO that + we will make into an MDP via the following configuration. + + <!-- this is the Message Driven POJO (MDP) --> +<bean id="messageListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter"> + <constructor-arg> + <bean class="jmsexample.DefaultMessageDelegate"/> + </constructor-arg> +</bean> + +<!-- and this is the message listener container... --> +<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> + <property name="connectionFactory" ref="connectionFactory"/> + <property name="destination" ref="destination"/> + <property name="messageListener" ref="messageListener" /> +</bean> + + Below is an example of another MDP that can only handle the + receiving of JMS TextMessage messages. + Notice how the message handling method is actually called + 'receive' (the name of the message handling method in + a MessageListenerAdapter defaults to + 'handleMessage'), but it is configurable (as you will + see below). Notice also how the 'receive(..)' method + is strongly typed to receive and respond only to JMS + TextMessage messages. + + public interface TextMessageDelegate { void receive(TextMessage message); -}]]> - // implementation elided for clarity... - The configuration of the attendant MessageListenerAdapter would - look like this: - - - - - - ]]><!-- we don't want automatic message context extraction --> - - -]]> - Please note that if the above 'messageListener' receives a - JMS Message of a type other than - TextMessage, an IllegalStateException - will be thrown (and subsequently swallowed). - Another of the capabilities of the MessageListenerAdapter - class is the ability to automatically send back a response Message - if a handler method returns a non-void value. - Consider the interface and class: - - ]]>// notice the return type...public class DefaultTextMessageDelegate implements TextMessageDelegate { + // implementation elided for clarity... +} + + The configuration of the attendant + MessageListenerAdapter would look like + this: + + <bean id="messageListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter"> + <constructor-arg> + <bean class="jmsexample.DefaultTextMessageDelegate"/> + </constructor-arg> + <property name="defaultListenerMethod" value="receive"/> + <!-- we don't want automatic message context extraction --> + <property name="messageConverter"> + <null/> + </property> +</bean> + + Please note that if the above 'messageListener' + receives a JMS Message of a type other + than TextMessage, an + IllegalStateException will be thrown (and + subsequently swallowed). Another of the capabilities of the + MessageListenerAdapter class is the ability to + automatically send back a response + Message if a handler method returns a + non-void value. Consider the interface and class: + + public interface ResponsiveTextMessageDelegate { + + // notice the return type... String receive(TextMessage message); -}]]> - // implementation elided for clarity... - If the above DefaultResponsiveTextMessageDelegate is used in - conjunction with a MessageListenerAdapter then any non-null - value that is returned from the execution of the 'receive(..)' - method will (in the default configuration) be converted into a - TextMessage. The resulting TextMessage - will then be sent to the Destination (if one exists) - defined in the JMS Reply-To property of the original Message, or the - default Destination set on the - MessageListenerAdapter (if one has been configured); if no - Destination is found then an - InvalidDestinationException will be thrown (and please note - that this exception will not be swallowed and - will propagate up the call stack). -
- -
- Processing messages within transactions +} - Invoking a message listener within a transaction only requires - reconfiguration of the listener container. + public class DefaultResponsiveTextMessageDelegate implements ResponsiveTextMessageDelegate { + // implementation elided for clarity... +} - Local resource transactions can simply be activated through the - sessionTransacted flag on the listener container - definition. Each message listener invocation will then operate within - an active JMS transaction, with message reception rolled back in case - of listener execution failure. Sending a response message - (via SessionAwareMessageListener) - will be part of the same local transaction, but any other resource - operations (such as database access) will operate independently. - This usually requires duplicate message detection in the listener - implementation, covering the case where database processing has - committed but message processing failed to commit. + If the above + DefaultResponsiveTextMessageDelegate is used in + conjunction with a MessageListenerAdapter then + any non-null value that is returned from the execution of the + 'receive(..)' method will (in the default + configuration) be converted into a + TextMessage. The resulting + TextMessage will then be sent to the + Destination (if one exists) defined in + the JMS Reply-To property of the original + Message, or the default + Destination set on the + MessageListenerAdapter (if one has been + configured); if no Destination is found + then an InvalidDestinationException will be + thrown (and please note that this exception will + not be swallowed and will propagate up + the call stack). +
- - - - - ]]>]]>]]> +
+ Processing messages within transactions - For participating in an externally managed transaction, - you will need to configure a transaction manager and use a listener - container which supports externally managed transactions: typically - DefaultMessageListenerContainer. + Invoking a message listener within a transaction only requires + reconfiguration of the listener container. - To configure a message listener container for XA transaction - participation, you'll want to configure a JtaTransactionManager - (which, by default, delegates to the J2EE server's transaction subsystem). - Note that the underlying JMS ConnectionFactory needs to be XA-capable - and properly registered with your JTA transaction coordinator! - (Check your J2EE server's configuration of JNDI resources.) - This allows message recepton as well as e.g. database access to be - part of the same transaction (with unified commit semantics, - at the expense of XA transaction log overhead). + Local resource transactions can simply be activated through the + sessionTransacted flag on the listener container + definition. Each message listener invocation will then operate within an + active JMS transaction, with message reception rolled back in case of + listener execution failure. Sending a response message (via + SessionAwareMessageListener) will be part + of the same local transaction, but any other resource operations (such + as database access) will operate independently. This usually requires + duplicate message detection in the listener implementation, covering the + case where database processing has committed but message processing + failed to commit. - -]]> + <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> + <property name="connectionFactory" ref="connectionFactory"/> + <property name="destination" ref="destination"/> + <property name="messageListener" ref="messageListener"/> + <property name="sessionTransacted" value="true"/> +</bean> - Then you just need to add it to our earlier container configuration. The - container will take care of the rest. + For participating in an externally managed transaction, you will + need to configure a transaction manager and use a listener container + which supports externally managed transactions: typically + DefaultMessageListenerContainer. - - - - - ]]>]]>]]> -
+ To configure a message listener container for XA transaction + participation, you'll want to configure a + JtaTransactionManager (which, by default, + delegates to the J2EE server's transaction subsystem). Note that the + underlying JMS ConnectionFactory needs to be XA-capable and properly + registered with your JTA transaction coordinator! (Check your J2EE + server's configuration of JNDI resources.) This allows message recepton + as well as e.g. database access to be part of the same transaction (with + unified commit semantics, at the expense of XA transaction log + overhead). + + <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> + + + Then you just need to add it to our earlier container + configuration. The container will take care of the rest. + + <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> + <property name="connectionFactory" ref="connectionFactory"/> + <property name="destination" ref="destination"/> + <property name="messageListener" ref="messageListener"/> + <property name="transactionManager" ref="transactionManager"/> +</bean> +
Support for JCA Message Endpoints - Beginning with version 2.5, Spring also provides support for a JCA-based - MessageListener container. The - JmsMessageEndpointManager will attempt to automatically - determine the ActivationSpec class name from the - provider's ResourceAdapter class name. Therefore, - it is typically possible to just provide Spring's generic - JmsActivationSpecConfig as shown in the following example. - + Beginning with version 2.5, Spring also provides support for a + JCA-based MessageListener container. The + JmsMessageEndpointManager will attempt to + automatically determine the ActivationSpec + class name from the provider's + ResourceAdapter class name. Therefore, it + is typically possible to just provide Spring's generic + JmsActivationSpecConfig as shown in the following + example. - - - - - - - - -]]> + <bean class="org.springframework.jms.listener.endpoint.JmsMessageEndpointManager"> + <property name="resourceAdapter" ref="resourceAdapter"/> + <property name="activationSpecConfig"> + <bean class="org.springframework.jms.listener.endpoint.JmsActivationSpecConfig"> + <property name="destinationName" value="myQueue"/> + </bean> + </property> + <property name="messageListener" ref="myMessageListener"/> +</bean> - Alternatively, you may set up a JmsMessageEndpointManager - with a given ActivationSpec object. The - ActivationSpec object may also come - from a JNDI lookup (using <jee:jndi-lookup>). + Alternatively, you may set up a + JmsMessageEndpointManager with a given + ActivationSpec object. The + ActivationSpec object may also come from a + JNDI lookup (using <jee:jndi-lookup>). - - - - - - - - - -]]> + <bean class="org.springframework.jms.listener.endpoint.JmsMessageEndpointManager"> + <property name="resourceAdapter" ref="resourceAdapter"/> + <property name="activationSpec"> + <bean class="org.apache.activemq.ra.ActiveMQActivationSpec"> + <property name="destination" value="myQueue"/> + <property name="destinationType" value="javax.jms.Queue"/> + </bean> + </property> + <property name="messageListener" ref="myMessageListener"/> +</bean> Using Spring's ResourceAdapterFactoryBean, the target ResourceAdapter may be configured locally as depicted in the following example. - - - - - - - - - -]]> + <bean id="resourceAdapter" class="org.springframework.jca.support.ResourceAdapterFactoryBean"> + <property name="resourceAdapter"> + <bean class="org.apache.activemq.ra.ActiveMQResourceAdapter"> + <property name="serverUrl" value="tcp://localhost:61616"/> + </bean> + </property> + <property name="workManager"> + <bean class="org.springframework.jca.work.SimpleTaskWorkManager"/> + </property> +</bean> - The specified WorkManager - may also point to an environment-specific thread pool - typically - through SimpleTaskWorkManager's - "asyncTaskExecutor" property. Consider defining a shared thread - pool for all your ResourceAdapter - instances if you happen to use multiple adapters. + The specified WorkManager may also + point to an environment-specific thread pool - typically through + SimpleTaskWorkManager's "asyncTaskExecutor" + property. Consider defining a shared thread pool for all your + ResourceAdapter instances if you happen to + use multiple adapters. In some environments (e.g. WebLogic 9 or above), the entire - ResourceAdapter object may be obtained - from JNDI instead (using <jee:jndi-lookup>). - The Spring-based message listeners can then interact with the server-hosted + ResourceAdapter object may be obtained from + JNDI instead (using <jee:jndi-lookup>). The + Spring-based message listeners can then interact with the server-hosted ResourceAdapter, also using the server's built-in WorkManager. - Please consult the JavaDoc for JmsMessageEndpointManager, + Please consult the JavaDoc for + JmsMessageEndpointManager, JmsActivationSpecConfig, and ResourceAdapterFactoryBean for more details. - Spring also provides a generic JCA message endpoint manager which is not tied to JMS: + Spring also provides a generic JCA message endpoint manager which is + not tied to JMS: org.springframework.jca.endpoint.GenericMessageEndpointManager. - This component allows for using any message listener type (e.g. a CCI MessageListener) - and any provided-specific ActivationSpec object. Check out your JCA provider's - documentation to find out about the actual capabilities of your connector, - and consult GenericMessageEndpointManager's JavaDoc - for the Spring-specific configuration details. + This component allows for using any message listener type (e.g. a CCI + MessageListener) and any provided-specific ActivationSpec object. Check + out your JCA provider's documentation to find out about the actual + capabilities of your connector, and consult + GenericMessageEndpointManager's JavaDoc for the + Spring-specific configuration details. JCA-based message endpoint management is very analogous to EJB 2.1 - Message-Driven Beans; it uses the same underlying resource provider contract. - Like with EJB 2.1 MDBs, any message listener interface supported by your JCA - provider can be used in the Spring context as well. Spring nevertheless provides - explicit 'convenience' support for JMS, simply because JMS is the most common - endpoint API used with the JCA endpoint management contract. + Message-Driven Beans; it uses the same underlying resource provider + contract. Like with EJB 2.1 MDBs, any message listener interface + supported by your JCA provider can be used in the Spring context as + well. Spring nevertheless provides explicit 'convenience' support for + JMS, simply because JMS is the most common endpoint API used with the + JCA endpoint management contract.
JMS Namespace Support - - Spring 2.5 introduces an XML namespace for simplifying JMS configuration. To use the - JMS namespace elements you will need to reference the JMS schema: - -Spring 2.5 introduces an XML namespace for simplifying JMS + configuration. To use the JMS namespace elements you will need to + reference the JMS schema: + + <?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - ]]>xmlns:jms="http://www.springframework.org/schema/jms"xmlns:jms="http://www.springframework.org/schema/jms" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd -]]>http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-2.5.xsd" +http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-2.5.xsd"> -]]><!-- <bean/> definitions here --><!-- <bean/> definitions here --> -]]> +</beans> - The namespace consists of two top-level elements: <listener-container/> - and <jca-listener-container/> both of which may contain one or more - <listener/> child elements. Here is an example of a basic configuration - for two listeners. + The namespace consists of two top-level elements: + <listener-container/> and + <jca-listener-container/> both of which may + contain one or more <listener/> child elements. + Here is an example of a basic configuration for two listeners. - + <jms:listener-container> - + <jms:listener destination="queue.orders" ref="orderService" method="placeOrder"/> - + <jms:listener destination="queue.confirmations" ref="confirmationLogger" method="log"/> -]]> +</jms:listener-container> + + The example above is equivalent to creating two distinct listener + container bean definitions and two distinct + MessageListenerAdapter bean definitions as + demonstrated in the section entitled . In addition to + the attributes shown above, the listener element may + contain several optional ones. The following table describes all available + attributes: - The example above is equivalent to creating two distinct listener container bean - definitions and two distinct MessageListenerAdapter bean - definitions as demonstrated in the section entitled - . In addition to the - attributes shown above, the listener element may contain several - optional ones. The following table describes all available attributes: - - Attributes of the JMS <literal><listener></literal> element + Attributes of the JMS <literal><listener></literal> + element + - - + + + + Attribute + Description + id - - A bean name for the hosting listener container. If not - specified, a bean name will be automatically generated. - + + A bean name for the hosting listener container. If + not specified, a bean name will be automatically + generated. + - destination (required) - - The destination name for this listener, resolved through the - DestinationResolver strategy. - + destination (required) + + The destination name for this listener, resolved + through the DestinationResolver + strategy. + ref (required) - - The bean name of the handler object. - + + The bean name of the handler object. + method - - The name of the handler method to invoke. If the - ref points to a - MessageListener or Spring - SessionAwareMessageListener, - this attribute may be omitted. - + + The name of the handler method to invoke. If the + ref points to a + MessageListener or Spring + SessionAwareMessageListener, this + attribute may be omitted. + response-destination - - The name of the default response destination to send - response messages to. This will be applied in case of a - request message that does not carry a "JMSReplyTo" field. - The type of this destination will be determined by the - listener-container's "destination-type" attribute. Note: - This only applies to a listener method with a return - value, for which each result object will be converted - into a response message. - + + The name of the default response destination to send + response messages to. This will be applied in case of a request + message that does not carry a "JMSReplyTo" field. The type of this + destination will be determined by the listener-container's + "destination-type" attribute. Note: This only applies to a + listener method with a return value, for which each result object + will be converted into a response message. + subscription - - The name of the durable subscription, if any. - + + The name of the durable subscription, if + any. + selector - - An optional message selector for this listener. - + + An optional message selector for this + listener.
- The <listener-container/> element also accepts several optional - attributes. This allows for customization of the various strategies (for example, - taskExecutor and destinationResolver) as well as - basic JMS settings and resource references. Using these attributes, it is possible to define - highly-customized listener containers while still benefiting from the convenience of the - namespace. + The <listener-container/> element also + accepts several optional attributes. This allows for customization of the + various strategies (for example, taskExecutor and + destinationResolver) as well as basic JMS settings + and resource references. Using these attributes, it is possible to define + highly-customized listener containers while still benefiting from the + convenience of the namespace. - <jms:listener-container connection-factory="myConnectionFactory" task-executor="myTaskExecutor" destination-resolver="myDestinationResolver" transaction-manager="myTransactionManager" - concurrency="10"> + concurrency="10"> - + <jms:listener destination="queue.orders" ref="orderService" method="placeOrder"/> - + <jms:listener destination="queue.confirmations" ref="confirmationLogger" method="log"/> -]]> +</jms:listener-container> + + The following table describes all available attributes. Consult the + class-level Javadoc of the + AbstractMessageListenerContainer and its concrete + subclasses for more detail on the individual properties. The Javadoc also + provides a discussion of transaction choices and message redelivery + scenarios. - The following table describes all available attributes. Consult the class-level - Javadoc of the AbstractMessageListenerContainer and its - concrete subclasses for more detail on the individual properties. The Javadoc also - provides a discussion of transaction choices and message redelivery scenarios. - - Attributes of the JMS <literal><listener-container></literal> element + Attributes of the JMS + <literal><listener-container></literal> element + - - + + + + Attribute + Description + container-type - - The type of this listener container. Available options are: - default, simple, - default102, or simple102 - (the default value is 'default'). - + + The type of this listener container. Available + options are: default, + simple, default102, or + simple102 (the default value is + 'default'). + connection-factory - - A reference to the JMS - ConnectionFactory bean (the default bean - name is 'connectionFactory'). - + + A reference to the JMS + ConnectionFactory bean (the default + bean name is + 'connectionFactory'). + task-executor - - A reference to the Spring TaskExecutor - for the JMS listener invokers. - + + A reference to the Spring + TaskExecutor for the JMS listener + invokers. + destination-resolver - - A reference to the DestinationResolver - strategy for resolving JMS Destinations. - + + A reference to the + DestinationResolver strategy for + resolving JMS + Destinations. + message-converter - - A reference to the MessageConverter - strategy for converting JMS Messages to listener method arguments. Default - is a SimpleMessageConverter. - + + A reference to the + MessageConverter strategy for + converting JMS Messages to listener method arguments. Default is a + SimpleMessageConverter. + destination-type - - The JMS destination type for this listener: queue, - topic or durableTopic. - The default is queue. - + + The JMS destination type for this listener: + queue, topic or + durableTopic. The default is + queue. + client-id - - The JMS client id for this listener container. - Needs to be specified when using durable subscriptions. - + + The JMS client id for this listener container. Needs + to be specified when using durable subscriptions. + cache - - The cache level for JMS resources: none, - connection, session, - consumer or auto. - By default (auto), the cache level will - effectively be "consumer", unless an external transaction manager - has been specified - in which case the effective default will be - none (assuming J2EE-style transaction management - where the given ConnectionFactory is an XA-aware pool). - + + The cache level for JMS resources: + none, connection, + session, consumer or + auto. By default (auto), the + cache level will effectively be "consumer", unless an external + transaction manager has been specified - in which case the + effective default will be none (assuming + J2EE-style transaction management where the given + ConnectionFactory is an XA-aware pool). + acknowledge - - The native JMS acknowledge mode: auto, - client, dups-ok or - transacted. A value of transacted - activates a locally transacted Session. - As an alternative, specify the transaction-manager - attribute described below. Default is auto. - + + The native JMS acknowledge mode: + auto, client, + dups-ok or transacted. A + value of transacted activates a locally + transacted Session. As an + alternative, specify the transaction-manager + attribute described below. Default is + auto. + transaction-manager - - A reference to an external - PlatformTransactionManager - (typically an XA-based transaction coordinator, e.g. Spring's - JtaTransactionManager). If not specified, - native acknowledging will be used (see "acknowledge" attribute). - + + A reference to an external + PlatformTransactionManager + (typically an XA-based transaction coordinator, e.g. Spring's + JtaTransactionManager). If not specified, + native acknowledging will be used (see "acknowledge" + attribute). + concurrency - - The number of concurrent sessions/consumers to start for each - listener. Can either be a simple number indicating the maximum number (e.g. "5") - or a range indicating the lower as well as the upper limit (e.g. "3-5"). - Note that a specified minimum is just a hint and might be ignored at runtime. - Default is 1; keep concurrency limited to 1 in case of a topic listener - or if queue ordering is important; consider raising it for general queues. - + + The number of concurrent sessions/consumers to start + for each listener. Can either be a simple number indicating the + maximum number (e.g. "5") or a range indicating the lower as well + as the upper limit (e.g. "3-5"). Note that a specified minimum is + just a hint and might be ignored at runtime. Default is 1; keep + concurrency limited to 1 in case of a topic listener or if queue + ordering is important; consider raising it for general + queues. + prefetch - - The maximum number of messages to load into a single session. - Note that raising this number might lead to starvation of concurrent - consumers! - - - - -
- - Configuring a JCA-based listener container with the "jms" schema support is very similar. - - - - -]]> - - The available configuration options for the JCA variant are described in the following table: - - - Attributes of the JMS <literal><jca-listener-container/></literal> element - - - - - - Attribute - Description - - - - - resource-adapter - - A reference to the JCA - ResourceAdapter bean (the default bean - name is 'resourceAdapter'). - - - - activation-spec-factory - - A reference to the JmsActivationSpecFactory. - The default is to autodetect the JMS provider and its - ActivationSpec class - (see DefaultJmsActivationSpecFactory) - - - - destination-resolver - - A reference to the DestinationResolver - strategy for resolving JMS Destinations. - - - - - message-converter - - A reference to the MessageConverter - strategy for converting JMS Messages to listener method arguments. - Default is a SimpleMessageConverter. - - - - destination-type - - The JMS destination type for this listener: queue, - topic or durableTopic. - The default is queue. - - - - client-id - - The JMS client id for this listener container. - Needs to be specified when using durable subscriptions. - - - - acknowledge - - The native JMS acknowledge mode: auto, - client, dups-ok or - transacted. A value of transacted - activates a locally transacted Session. - As an alternative, specify the transaction-manager - attribute described below. Default is auto. - - - - transaction-manager - - A reference to a Spring JtaTransactionManager - or a javax.transaction.TransactionManager - for kicking off an XA transaction for each incoming message. - If not specified, native acknowledging will be used (see - the "acknowledge" attribute). - - - - concurrency - - The number of concurrent sessions/consumers to start for each - listener. Can either be a simple number indicating the maximum number (e.g. "5") - or a range indicating the lower as well as the upper limit (e.g. "3-5"). - Note that a specified minimum is just a hint and will typically be ignored - at runtime when using a JCA listener container. Default is 1. - - - - prefetch - - The maximum number of messages to load into a single session. - Note that raising this number might lead to starvation of concurrent - consumers! - + The maximum number of messages to load into a single + session. Note that raising this number might lead to starvation of + concurrent consumers!
- -
-
\ No newline at end of file + Configuring a JCA-based listener container with the "jms" schema + support is very similar. + + <jms:jca-listener-container resource-adapter="myResourceAdapter" + destination-resolver="myDestinationResolver" + transaction-manager="myTransactionManager" + concurrency="10"> + + <jms:listener destination="queue.orders" ref="myMessageListener"/> + +</jms:jca-listener-container> + + The available configuration options for the JCA variant are + described in the following table: + + + Attributes of the JMS + <literal><jca-listener-container/></literal> element + + + + + + + + + Attribute + + Description + + + + + + resource-adapter + + A reference to the JCA + ResourceAdapter bean (the default + bean name is 'resourceAdapter'). + + + + activation-spec-factory + + A reference to the + JmsActivationSpecFactory. The + default is to autodetect the JMS provider and its + ActivationSpec class (see + DefaultJmsActivationSpecFactory) + + + + destination-resolver + + A reference to the + DestinationResolver strategy for + resolving JMS Destinations. + + + + + message-converter + + A reference to the + MessageConverter strategy for + converting JMS Messages to listener method arguments. Default is a + SimpleMessageConverter. + + + + destination-type + + The JMS destination type for this listener: + queue, topic or + durableTopic. The default is + queue. + + + + client-id + + The JMS client id for this listener container. Needs + to be specified when using durable subscriptions. + + + + acknowledge + + The native JMS acknowledge mode: + auto, client, + dups-ok or transacted. A + value of transacted activates a locally + transacted Session. As an + alternative, specify the transaction-manager + attribute described below. Default is + auto. + + + + transaction-manager + + A reference to a Spring + JtaTransactionManager or a + javax.transaction.TransactionManager + for kicking off an XA transaction for each incoming message. If + not specified, native acknowledging will be used (see the + "acknowledge" attribute). + + + + concurrency + + The number of concurrent sessions/consumers to start + for each listener. Can either be a simple number indicating the + maximum number (e.g. "5") or a range indicating the lower as well + as the upper limit (e.g. "3-5"). Note that a specified minimum is + just a hint and will typically be ignored at runtime when using a + JCA listener container. Default is 1. + + + + prefetch + + The maximum number of messages to load into a single + session. Note that raising this number might lead to starvation of + concurrent consumers! + + + +
+ + diff --git a/spring-framework-reference/src/metadata.xml b/spring-framework-reference/src/metadata.xml index abc5001a6c2..131e95d9f39 100644 --- a/spring-framework-reference/src/metadata.xml +++ b/spring-framework-reference/src/metadata.xml @@ -1,247 +1,148 @@ - +"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> - Annotations and Source Level Metadata Support -
- Introduction - Source-level metadata is the addition of attributes or - annotations to program elements - usually, classes - and/or methods. - For example, we might add metadata to a class as follows: - - We could add metadata to a method as follows: - - Both of these examples use Jakarta Commons Attributes syntax. - - Source-level metadata was introduced to the mainstream by XDoclet - (in the Java world) and by the release of Microsoft's .NET platform, which - uses source-level attributes to control transactions, pooling and other - behavior. - - - 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 used exclusively by EJB. While it is desirable to - externalize some things from program source code, some important - enterprise settings - notably transaction characteristics - arguably belong - in program source. Contrary to the assumptions of the EJB spec, it seldom - makes sense to modify the transactional characteristics of a method - (although parameters like transaction timeouts might change!). - - - 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 - view metadata primarily as a way of generating code such as EJB artefacts. - - - There are a number of solutions in this space, including: - - - - Standard Java Annotations: the - standard Java metadata implementation (developed as JSR-175 and available - in Java 5). Spring has specific Java 5 annotations for transactional - demarcation, JMX, and aspects (to be precise they are AspectJ annotations). - However, since Spring supports Java 1.4 as well, a solution for said - JVM versions is needed too. Spring metadata support provides such a - solution. - - - XDoclet: well-established - solution, primarily intended for code generation. - - - Various open source attribute - implementations, for Java 1.4, of which Commons - Attributes is the most complete implementation. All these require - a special pre- or post-compilation step. - - -
-
- Spring's metadata support - 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. Such a facade adds value for several reasons: - - - Even though Java 5 provides metadata support at language level, there will - still be value in providing such an abstraction: - - - - Java 5 metadata is static. It is associated with a class - at compile time, and cannot be changed in a deployed - environment (annotation state can actually be changed - at runtime using reflection, but doing so would really be - a bad practice). There is a need for hierarchical metadata, - providing the ability to override certain attribute values in - deployment - for example, in an XML file. - - - Java 5 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. - - - 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; forcing the use of - Java 5 is not an option in such an important area. - - - - - Current metadata APIs, such as Commons Attributes (used by - Spring 1.0-1.2) are hard to test. Spring provides a simple metadata - interface that is much easier to mock. - - - The Spring Attributes interface looks like this: - Annotations and Source Level Metadata Support - Collection getAttributes(Class targetClass); +
+ Introduction - Collection getAttributes(Class targetClass, Class filter); + Java 5 introduced source-level metadata called annotations to + program elements, usually, classes and/or methods - Collection getAttributes(Method targetMethod); + For example we might add metadata at the class level using the + Spring's @Transactional annotation that is used to support Spring's + declarative transaction management features. - Collection getAttributes(Method targetMethod, Class filter); + @Transactional +public class PetStoreImpl implements PetStoreFacade, OrderService { - Collection getAttributes(Field targetField); + We could also add metadata to a method as follows: - Collection getAttributes(Field targetField, Class filter); -}]]> - - This is a lowest common denominator interface. JSR-175 offers more - capabilities than this, such as attributes on method arguments. - - - Note that this interface offers Object - attributes, like .NET. This distinguishes it from attribute systems such - as that of Nanning Aspects, which offer only String - attributes. There is a significant advantage in supporting - Object attributes, namely that it enables - attributes to participate in class hierarchies and allows such - attributes to react intelligently to their configuration parameters. - - - With most attribute providers, attribute classes are configured - via constructor arguments or JavaBean properties. Commons Attributes - supports both. - - As with all Spring abstraction APIs, Attributes - is an interface. This makes it easy to mock attribute implementations for unit tests. -
-
- Annotations - - The Spring Framework ships with a number of custom Java 5+ annotations. - -
- <interfacename>@Required</interfacename> - The @Required annotation in the - org.springframework.beans.factory.annotation - package can be used to mark a property as - being 'required-to-be-set' (i.e. an - annotated (setter) method of a class must be configured to be - dependency injected with a value), else an - Exception will be thrown by the container - at runtime. - The best way to illustrate the usage of this annotation is to - show an example: - public class PetStoreImpl implements PetStoreFacade, OrderService { - ]]>// the SimpleMovieLister has a dependency on the MovieFinder + + The value of using annoations has been broadly embrassed by the JEE + community. For example, it's much less verbose than the traditional XML + deployment descriptors. While it is desirable to externalize some things + from program source code, some important enterprise settings - notably + transaction characteristics - arguably belong in program source. + + Spring uses custom Java 5 annotations thoughout the framework across + a wide range of features such as DI, MVC, and AOP and supports JEE + standard annotations such as @PreDestroy and @PostConstruct defined by + JSR-250. This chapter describes the @Required attribute and provides links + to other parts the documentation where the various attributes are + described in more detail. +
+ +
+ Annotations + + The Spring Framework ships with a number of custom Java 5+ + annotations. + +
+ <interfacename>@Required</interfacename> + + The @Required annotation in the + org.springframework.beans.factory.annotation package + can be used to mark a property as being + 'required-to-be-set' (i.e. an annotated (setter) + method of a class must be configured to be dependency injected with a + value), else an Exception will be thrown by the + container at runtime. + + The best way to illustrate the usage of this annotation is to show + an example: + + public class SimpleMovieLister { + + // the SimpleMovieLister has a dependency on the MovieFinder private MovieFinder movieFinder; - ]]>// a setter method so that the Spring container can 'inject' a MovieFinder// a setter method so that the Spring container can 'inject' a MovieFinder @Required public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } - ]]>// business logic that actually 'uses' the injected MovieFinder is omitted... - - Hopefully the above class definition reads easy on the eye. - Any and all BeanDefinitions for the - SimpleMovieLister class must be provided - with a value. - - - Let's look at an example of some XML configuration that will - not pass validation. - - - ]]><!-- whoops, no MovieFinder is set (and this property is @Required) -->]]> - - At runtime the following message will be generated by the Spring container - (the rest of the stack trace has been truncated). - - - - There is one last little (small, tiny) piece of Spring configuration - that is required to actually 'switch on' this - behavior. Simply annotating the 'setter' properties - of your classes is not enough to get this behavior. You need - to enable a component that is aware of the @Required - annotation and that can process it appropriately. - - - This component is the RequiredAnnotationBeanPostProcessor class. - This is a special BeanPostProcessor - implementation that is @Required-aware - and actually provides the 'blow up if this required property - has not been set' logic. It is very easy - to configure; simply drop the following bean definition into your Spring - XML configuration. - - ]]> - - Finally, one can configure an instance of the - RequiredAnnotationBeanPostProcessor class to look - for another Annotation type. - This is great if you already have your own - @Required-style annotation. Simply plug it into - the definition of a RequiredAnnotationBeanPostProcessor and - you are good to go. - - - By way of an example, let's suppose you (or your organization / team) have - defined an attribute called @ Mandatory. - You can make a RequiredAnnotationBeanPostProcessor - instance @Mandatory-aware like so: - - - -]]> - - Here is the source code for the @Mandatory - annotation. You will need to ensure that your custom annotation type - is itself annotated with appropriate annotations for its target - and runtime retention policy. - - // business logic that actually 'uses' the injected MovieFinder is omitted... +} + + Hopefully the above class definition reads easy on the eye. Any + and all BeanDefinitions for the + SimpleMovieLister class must be provided with a + value. + + Let's look at an example of some XML configuration that will + not pass validation. + + <bean id="movieLister" class="x.y.SimpleMovieLister"> + <!-- whoops, no MovieFinder is set (and this property is @Required) --> +</bean> + + At runtime the following message will be generated by the Spring + container (the rest of the stack trace has been truncated). + + Exception in thread "main" java.lang.IllegalArgumentException: + Property 'movieFinder' is required for bean 'movieLister'. + + There is one last little (small, tiny) piece of Spring + configuration that is required to actually 'switch + on' this behavior. Simply annotating the + 'setter' properties of your classes is not enough + to get this behavior. You need to enable a component that is aware of + the @Required annotation and that can + process it appropriately. + + This component is the + RequiredAnnotationBeanPostProcessor class. This + is a special BeanPostProcessor + implementation that is @Required-aware + and actually provides the 'blow up if this required property + has not been set' logic. It is very easy + to configure; simply drop the following bean definition into your Spring + XML configuration. + + <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/> + + Finally, one can configure an instance of the + RequiredAnnotationBeanPostProcessor class to look + for another + Annotation type. This is great if you + already have your own @Required-style + annotation. Simply plug it into the definition of a + RequiredAnnotationBeanPostProcessor and you are + good to go. + + By way of an example, let's suppose you (or your organization / + team) have defined an attribute called @ + Mandatory. You can make a + RequiredAnnotationBeanPostProcessor instance + @Mandatory-aware like so: + + <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"> + <property name="requiredAnnotationType" value="your.company.package.Mandatory"/> +</bean> + + Here is the source code for the + @Mandatory annotation. You will need to + ensure that your custom annotation type is itself annotated with + appropriate annotations for its target and runtime retention + policy. + + package your.company.package; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -251,256 +152,38 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Mandatory { -}]]> -
-
- Other @Annotations in Spring - - Annotations are also used in a number of other places throughout Spring. - Rather than being described here, these annotations are described in that - section or chapter of the reference documentation to which they are most - relevant. - - - - - - - - - - - - - - - - - - -
-
-
- Integration with Jakarta Commons Attributes - - 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. - - - Commons Attributes 2.2 - (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.) - - - We've already seen two examples of Commons Attributes attributes - definitions. In general, we will need to express: - - - - - The name of the attribute class. This can - be a fully qualified name (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. - - - - - Any necessary parameterization. This is done via - constructor arguments or JavaBean properties. - - - - Bean properties look as follows: - - - It's possible to combine constructor arguments and JavaBean - properties (as in Spring IoC). - - - 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. - - - To run Commons Attributes as part of the build process, you will - need to do the following: - - - 1. Copy the necessary library jars to - $ANT_HOME/lib. Four Jars are required, and all are - distributed with Spring: - - - - the Commons Attributes compiler jar and API jar - - - xJavadoc.jar from XDoclet - - - commons-collections.jar from Jakarta Commons - - - - 2. Import the Commons Attributes ant tasks into your project build - script, as follows: - - ]]> - - 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 for storing the generated files: - - +} +
- - - +
+ Other @Annotations in Spring -]]> - - 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. - - - Commons Attributes also provides Maven support. Please refer to - Commons Attributes documentation for further information. - - - 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. - - - 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 additional step, Commons Attributes will - create an index of all the attributes defined on your sources, for - efficient lookup at runtime. The step looks like this: - - - - + Annotations are also used in a number of other places throughout + Spring. Rather than being described here, these annotations are + described in that section or chapter of the reference documentation to + which they are most relevant. -]]> - - 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. - - - 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. Also, Commons Attributes is a static API, while Spring provides a - metadata interface that you can easily mock. - -
-
- Metadata and Spring AOP autoproxying - - 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. - -
- Fundamentals - - This builds on the Spring AOP autoproxy functionality. - Configuration might look like this: - - + + + + - - - + + + - - - - - - - - + + + -]]> - - The basic concepts here should be familiar from the discussion of - autoproxying in the AOP chapter. - - - The most important bean definitions are the auto-proxy creator - and the advisor. Note that the actual bean names are not important; - what matters is their class. - - - The bean definition of class - org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator - will automatically advise ("auto-proxy") 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, however, do know about attributes. - - - Thus we simply need an AOP advisor that will provide declarative - transaction management based on attributes. - - - It is 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.) - - - Finally, the attributes bean is the Commons - Attributes Attributes implementation. Replace it with another - implementation of the - org.springframework.metadata.Attributes - interface to source attributes from a different source. - -
-
- Declarative transaction management - - The most common use of source-level attributes is to provide - declarative transaction management. 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. - - Please note that you can specify transaction attributes at either class - or method level. Class-level attributes, if specified, will be "inherited" - by all methods whereas method attributes will wholly override any - class-level attributes. -
-
- \ No newline at end of file + + + + + + + + +
+
+
diff --git a/spring-framework-reference/src/spring-framework-reference.xml b/spring-framework-reference/src/spring-framework-reference.xml index 9b18161341a..1815f40b02a 100644 --- a/spring-framework-reference/src/spring-framework-reference.xml +++ b/spring-framework-reference/src/spring-framework-reference.xml @@ -331,6 +331,7 @@ +