From 395e3d008cc3fa63dbfc7319fad0f29120e84053 Mon Sep 17 00:00:00 2001 From: Jay Bryant Date: Fri, 24 Aug 2018 16:18:42 -0500 Subject: [PATCH] Edit the core content reference documentation I edited for the usual stuff: spelling, punctuation, grammar, formatting, usage, and voice. --- src/docs/asciidoc/core/core-aop-api.adoc | 1086 ++++---- src/docs/asciidoc/core/core-aop.adoc | 2294 +++++++++-------- src/docs/asciidoc/core/core-appendix.adoc | 669 +++-- src/docs/asciidoc/core/core-beans.adoc | 32 +- .../asciidoc/core/core-databuffer-codec.adoc | 123 +- src/docs/asciidoc/core/core-expressions.adoc | 738 +++--- src/docs/asciidoc/core/core-null-safety.adoc | 46 +- src/docs/asciidoc/core/core-resources.adoc | 477 ++-- src/docs/asciidoc/core/core-validation.adoc | 974 +++---- 9 files changed, 3549 insertions(+), 2890 deletions(-) diff --git a/src/docs/asciidoc/core/core-aop-api.adoc b/src/docs/asciidoc/core/core-aop-api.adoc index ad5c5e1bd3f..2506fe69449 100644 --- a/src/docs/asciidoc/core/core-aop-api.adoc +++ b/src/docs/asciidoc/core/core-aop-api.adoc @@ -3,38 +3,34 @@ - -[[aop-api-introduction]] -== Introduction - -The previous chapter described the Spring's support for AOP using -@AspectJ and schema-based aspect definitions. In this chapter we discuss the lower-level +The previous chapter described the Spring's support for AOP with +@AspectJ and schema-based aspect definitions. In this chapter, we discuss the lower-level Spring AOP APIs and the AOP support typically used in Spring 1.2 applications. For new applications, we recommend the use of the Spring 2.0 and later AOP support described in -the previous chapter, but when working with existing applications, or when reading books -and articles, you may come across Spring 1.2 style examples. Spring 5 remains backwards -compatible with Spring 1.2 and everything described in this chapter is fully supported +the previous chapter. However, when you work with existing applications (or when you read books +and articles), you may come across Spring 1.2-style examples. Spring 5 remains backwards +compatible with Spring 1.2, and everything described in this chapter is fully supported in Spring 5. - [[aop-api-pointcuts]] == Pointcut API in Spring -Let's look at how Spring handles the crucial pointcut concept. +This section describes how Spring handles the crucial pointcut concept. [[aop-api-concepts]] === Concepts -Spring's pointcut model enables pointcut reuse independent of advice types. It's -possible to target different advice using the same pointcut. +Spring's pointcut model enables pointcut reuse independent of advice types. You can +target different advice with 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: +target advices to particular classes and methods. The complete interface follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -46,15 +42,17 @@ target advices to particular classes and methods. The complete interface is show } ---- +==== 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" +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: +classes. If the `matches()` method always returns true, all target classes are +matched. The following listing shows the `ClassFilter` interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -63,10 +61,11 @@ matched: boolean matches(Class clazz); } ---- +==== -The `MethodMatcher` interface is normally more important. The complete interface is -shown below: +The `MethodMatcher` interface is normally more important. The complete interface follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -79,84 +78,84 @@ shown below: boolean matches(Method m, Class targetClass, Object[] args); } ---- +==== -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 +The `matches(Method, Class)` method is used to test whether this pointcut ever +matches 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 +two-argument `matches` method returns `true` for a given method, and the `isRuntime()` method +for the MethodMatcher returns `true`, the three-argument matches method is invoked on +every method invocation. This lets a pointcut 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. +Most `MethodMatcher` implementations are static, meaning that their `isRuntime()` method returns `false`. +In this case, the three-argument `matches` method is never invoked. -[TIP] -==== -If possible, try to make pointcuts static, allowing the AOP framework to cache the +TIP: If possible, try to make pointcuts static, allowing the AOP framework to cache the results of pointcut evaluation when an AOP proxy is created. -==== [[aop-api-pointcut-ops]] -=== Operations on pointcuts +=== Operations on Pointcuts -Spring supports operations on pointcuts: notably, __union__ and __intersection__. +Spring supports operations (notably, union and intersection) on pointcuts. -* 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. +Union means the methods that either pointcut matches. +Intersection means the methods that both pointcuts match. +Union is usually more useful. +You can compse pointcuts by using the static methods in the +`org.springframework.aop.support.Pointcuts` class or by using the +`ComposablePointcut` class in the same package. However, using AspectJ pointcut +expressions is usually a simpler approach. [[aop-api-pointcuts-aspectj]] -=== AspectJ expression pointcuts +=== 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. +uses an AspectJ-supplied library to parse an AspectJ pointcut expression string. -See the previous chapter for a discussion of supported AspectJ pointcut primitives. +See the <> for a discussion of supported AspectJ pointcut primitives. [[aop-api-pointcuts-impls]] -=== Convenience pointcut implementations +=== Convenience Pointcut Implementations + +Spring provides several convenient pointcut implementations. You can use some of them directly. +Others are intended to be subclassed in application-specific pointcuts. -Spring provides several convenient pointcut implementations. Some can be used out of the -box; others are intended to be subclassed in application-specific pointcuts. [[aop-api-pointcuts-static]] -==== Static 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 +Static pointcuts are based on the method and the target class and cannot take into account the +method's arguments. Static pointcuts suffice -- and are best -- for most usages. +Spring can 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. +The rest of this section describes some of the static pointcut implementations that are included with Spring. [[aop-api-pointcuts-regex]] -===== Regular expression pointcuts +===== 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.JdkRegexpMethodPointcut` is a generic regular -expression pointcut, using the regular expression support in the JDK. +expression pointcut that uses the regular expression support in the JDK. -Using the `JdkRegexpMethodPointcut` 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 +With the `JdkRegexpMethodPointcut` class, you can provide a list of pattern strings. If +any of these is a match, the pointcut evaluates to `true`. (So, the result is effectively the union of these pointcuts.) -The usage is shown below: +The following example shows how to use `JdkRegexpMethodPointcut`: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -170,13 +169,15 @@ The usage is shown below: ---- +==== -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`. +Spring provides a convenience class named `RegexpMethodPointcutAdvisor`, which lets us +also reference an `Advice` (remember that an `Advice` can be an interceptor, before advice, +throws advice, and others). Behind the scenes, Spring uses a `JdkRegexpMethodPointcut`. Using `RegexpMethodPointcutAdvisor` simplifies wiring, as the one bean encapsulates both -pointcut and advice, as shown below: +pointcut and advice, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -193,54 +194,57 @@ pointcut and advice, as shown below: ---- +==== + +You can use `RegexpMethodPointcutAdvisor` with any `Advice` type. + -__RegexpMethodPointcutAdvisor__ can be used with any Advice type. [[aop-api-pointcuts-attribute-driven]] -===== Attribute-driven pointcuts +===== 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). -An important type of static pointcut is a __metadata-driven__ pointcut. This uses the -values of metadata attributes: typically, source-level metadata. [[aop-api-pointcuts-dynamic]] ==== 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 +method arguments as well as static information. This means that they must be +evaluated with every method invocation and that the result cannot be cached, as arguments will vary. The main example is the `control flow` pointcut. [[aop-api-pointcuts-cflow]] -===== Control flow pointcuts +===== Control Flow Pointcuts -Spring control flow pointcuts are conceptually similar to AspectJ __cflow__ 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. +in the `com.mycompany.web` package or by the `SomeCaller` class. Control flow pointcuts +are specified by using the `org.springframework.aop.support.ControlFlowPointcut` class. -[NOTE] -==== -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 +NOTE: Control flow pointcuts are significantly more expensive to evaluate at runtime than even +other dynamic pointcuts. In Java 1.4, the cost is about five times that of other dynamic pointcuts. -==== [[aop-api-pointcuts-superclasses]] -=== Pointcut superclasses +=== 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): +Because static pointcuts are most useful, you should probably subclass +`StaticMethodMatcherPointcut`. This requires implementing only one +abstract method (although you can override other methods to customize behavior). The +following example shows how to subclass `StaticMethodMatcherPointcut`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -251,6 +255,7 @@ abstract method (although it's possible to override other methods to customize b } } ---- +==== There are also superclasses for dynamic pointcuts. @@ -259,63 +264,60 @@ You can use custom pointcuts with any advice type in Spring 1.0 RC2 and above. [[aop-api-pointcuts-custom]] -=== Custom pointcuts +=== 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. - -[NOTE] -==== -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." -==== +Because pointcuts in Spring AOP are Java classes rather than language features (as in +AspectJ), you can declare custom pointcuts, whether static or dynamic. Custom +pointcuts in Spring can be arbitrarily complex. However, we recommend using the AspectJ pointcut +expression language, if you can. +NOTE: 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.`" [[aop-api-advice]] == Advice API in Spring -Let's now look at how Spring AOP handles advice. +Now we can examine how Spring AOP handles advice. [[aop-api-advice-lifecycle]] -=== Advice lifecycles +=== 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. +objects or be 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 +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. +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. +Ypou can use a mix of shared and per-instance advice in the same AOP proxy. [[aop-api-advice-types]] -=== Advice types in Spring +=== 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. +Spring provides several advice types and is extensible to support +arbitrary advice types. This section describes the basic concepts and standard advice types. [[aop-api-advice-around]] -==== Interception around advice +==== Interception Around Advice -The most fundamental advice type in Spring is __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 +Spring is compliant with the AOP `Alliance` interface for around advice that uses method +interception. Classes that implement `MethodInterceptor` and that implement around advice should also implement the following interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -324,14 +326,16 @@ following interface: 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 +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: +The following example shows a simple `MethodInterceptor` implementation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -345,39 +349,37 @@ A simple `MethodInterceptor` implementation looks as follows: } } ---- - -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! - -[NOTE] ==== -MethodInterceptors offer interoperability with other AOP Alliance-compliant AOP + +Note the call to the `proceed()` method of `MethodInvocation`. This proceeds down the +interceptor chain towards the join point. Most interceptors 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 do not want to do this without good reason. + +NOTE: `MethodInterceptor` implementations 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 +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. -==== + [[aop-api-advice-before]] -==== Before advice +==== 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. +A simpler advice type is a before advice. This does not need a `MethodInvocation` +object, since it is called only 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 +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). +The following listing shows the `MethodBeforeAdvice` interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -386,16 +388,22 @@ unlikely that Spring will ever implement it). 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 +(Spring's API design would allow for +field before advice, although the usual objects apply to field interception and it is +unlikely for Spring to ever implement it.) + +Note that 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, it aborts further execution of the interceptor chain. The exception +propagates back up the interceptor chain. If it is unchecked or on the signature of +the invoked method, it is passed directly to the client. Otherwise, it is wrapped in an unchecked exception by the AOP proxy. -An example of a before advice in Spring, which counts all method invocations: +The following example shows a before advice in Spring, which counts all method invocations: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -412,34 +420,36 @@ An example of a before advice in Spring, which counts all method invocations: } } ---- +==== + +TIP: Before advice can be used with any pointcut. -[TIP] -==== -Before advice can be used with any pointcut. -==== [[aop-api-advice-throws]] -==== Throws advice +==== Throws Advice -__Throws advice__ is invoked after the return of the join point if the join point threw +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 +`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: +advice methods. These should be in the following form: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- 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. +arguments. The next two listing show classes that are examples of throws advice. -The advice below is invoked if a `RemoteException` is thrown (including subclasses): +The following advice is invoked if a `RemoteException` is thrown (including from subclasses): +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -450,11 +460,13 @@ The advice below is invoked if a `RemoteException` is thrown (including subclass } } ---- +==== -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: +Unlike the preceding +advice, the next example declares four arguments, so that it has access to the invoked method, method +arguments, and target object. The following advice is invoked if a `ServletException` is thrown: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -465,11 +477,13 @@ arguments and target object: } } ---- +==== -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. +The final example illustrates how these two methods could be used in a single class +that handles both `RemoteException` and `ServletException`. Any number of throws advice +methods can be combined in a single class. The following listing shows the final example: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -484,30 +498,27 @@ methods can be combined in a single class. } } ---- - -[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!__ ==== -[TIP] -==== -Throws advice can be used with any pointcut. -==== +NOTE: If a throws-advice method throws an exception itself, it overrides the +original exception (that is, it changes the exception thrown to the user). The overriding +exception is typically a RuntimeException, which is is compatible with any method +signature. However, if a throws-advice method throws a checked exception, it must +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!_ + +TIP: Throws advice can be used with any pointcut. + [[aop-api-advice-after-returning]] -==== After Returning advice +==== After Returning Advice An after returning advice in Spring must implement the -__org.springframework.aop.AfterReturningAdvice__ interface, shown below: +`org.springframework.aop.AfterReturningAdvice` interface, which the following listing shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -517,13 +528,15 @@ __org.springframework.aop.AfterReturningAdvice__ interface, shown below: throws Throwable; } ---- +==== An after returning advice has access to the return value (which it cannot modify), -invoked method, methods arguments and target. +the invoked method, the method's arguments, and the target. The following after returning advice counts all successful method invocations that have not thrown exceptions: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -541,24 +554,24 @@ not thrown exceptions: } } ---- +==== -This advice doesn't change the execution path. If it throws an exception, this will be +This advice does not change the execution path. If it throws an exception, it is thrown up the interceptor chain instead of the return value. -[TIP] -==== -After returning advice can be used with any pointcut. -==== +TIP: After returning advice can be used with any pointcut. + [[aop-api-advice-introduction]] -==== Introduction advice +==== Introduction Advice Spring treats introduction advice as a special kind of interception advice. -Introduction requires an `IntroductionAdvisor`, and an `IntroductionInterceptor`, -implementing the following interface: +Introduction requires an `IntroductionAdvisor` and an `IntroductionInterceptor` that +implement the following interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -567,16 +580,18 @@ implementing the following interface: 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 +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 +Introduction advice cannot be used with any pointcut, as it applies only at the class, +rather than the method, level. You can only use introduction advice with the `IntroductionAdvisor`, which has the following methods: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -592,8 +607,9 @@ rather than method, level. You can only use introduction advice with the Class[] getInterfaces(); } ---- +==== -There is no `MethodMatcher`, and hence no `Pointcut`, associated with introduction +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. @@ -601,9 +617,10 @@ 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 +Consider an example from the Spring test suite and suppose we want to introduce the following interface to one or more objects: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -613,40 +630,44 @@ introduce the following interface to one or more objects: 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: +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 +First, we 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 +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 +actual implementation of the introduced interfaces, concealing the use of interception +to do so. You can set the delegate to any object using a constructor argument. The +default delegate (when the no-argument constructor is used) is `this`. Thus, in the next example, +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)` +`IntroductionInterceptor`) and supports introductions against any of them. +Subclasses such as `LockMixin` can 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. +`IntroductionAdvisor` used controls which interfaces are actually exposed. An +introduced interface conceals any implementation of the same interface by the target. -Thus `LockMixin` extends `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 +Thus, `LockMixin` extends `DelegatingIntroductionInterceptor` and implements `Lockable` +itself. The superclass automatically picks up that `Lockable` can be supported for +introduction, so we do not 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. +The following example shows the example `LockMixin` class: + +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -675,19 +696,22 @@ to that held in the target object. } ---- +==== -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 +Often, you need not override the `invoke()` method. The +`DelegatingIntroductionInterceptor` implementation (which calls the `delegate` method if +the method is introduced, otherwise proceeds towards the join point) usually +suffices. 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`. +The required introduction only needs to hold a distinct +`LockMixin` instance and specify the introduced interfaces (in this case, only +`Lockable`). A more complex example might take a reference to the introduction +interceptor (which would be defined as a prototype). In this case, there is no +configuration relevant for a `LockMixin`, so we create it by using `new`. +The following example shows our `LockMixinAdvisor` class: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -698,58 +722,54 @@ configuration relevant for a `LockMixin`, so we simply create it using `new`. } } ---- +==== -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, +We can apply this advisor very simply, because it requires no configuration. (However, it +is 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 +We can apply this advisor programmatically by using the `Advised.addAdvisor()` method or +(the recommended way) in XML configuration, as any other advisor. All proxy creation +choices discussed below, including "`auto proxy creators,`" correctly handle introductions and stateful mixins. - [[aop-api-advisor]] -== Advisor API in Spring +== The Advisor API in Spring -In Spring, an Advisor is an aspect that contains just a single advice object associated +In Spring, an Advisor is an aspect that contains only 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 +advisor class. 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 +example, you could use an interception around advice, throws advice, and before advice in +one proxy configuration. Spring automatically creates the necessary interceptor chain. - [[aop-pfb]] -== Using the ProxyFactoryBean to create AOP proxies +== 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.) +If you use the Spring IoC container (an `ApplicationContext` or `BeanFactory`) for your +business objects (and you should be!), you want to use one of Spring's AOP +`FactoryBean` implementations. (Remember that a factory bean introduces a layer of indirection, letting +it create objects of a different type.) -[NOTE] -==== -The Spring AOP support also uses factory beans under the covers. -==== +NOTE: The Spring 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. +`org.springframework.aop.framework.ProxyFactoryBean`. This gives complete control over +the pointcuts, any advice that applies, and their ordering. However, there are simpler +options that are preferable if you do not need such control. @@ -757,13 +777,13 @@ 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. +level of indirection. If you define a `ProxyFactoryBean` named `foo`, objects that +reference `foo` do not see the `ProxyFactoryBean` instance itself but an object +created by the implementation of the `getObject()` method in the `ProxyFactoryBean` . This +method creates an AOP proxy that wraps 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 +class to create AOP proxies is 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 @@ -772,52 +792,53 @@ framework), benefiting from all the pluggability provided by Dependency Injectio [[aop-pfb-2]] -=== JavaBean properties +=== 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 <>). +* Specify whether to use CGLIB (described later and see also <>). Some key properties are inherited from `org.springframework.aop.framework.ProxyConfig` -(the superclass for all AOP proxy factories in Spring). These key properties include: +(the superclass for all AOP proxy factories in Spring). These key properties include +the following: * `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 <>). -* `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 + target class's interfaces. If this property value is set to `true`, then CGLIB proxies + are created (but see also <>). +* `optimize`: Controls whether or not aggressive optimizations are applied to proxies + created through CGLIB. You should not blithely use this setting unless you fully + understand 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`, 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` + when you do not want callers to be able to manipulate the proxy (through 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 + `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. -Other properties specific to `ProxyFactoryBean` include: +Other properties specific to `ProxyFactoryBean` include the following: -* `proxyInterfaces`: array of String interface names. If this isn't supplied, a CGLIB - proxy for the target class will be used (but see also <>). -* `interceptorNames`: String array of `Advisor`, interceptor or other advice names to +* `proxyInterfaces`: An array of `String` interface names. If this is not supplied, a CGLIB + proxy for the target class is used (but see also <>). +* `interceptorNames`: A `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 + that the first interceptor in the list is 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 +factories. You cannot mention bean references here, since doing so results in the `ProxyFactoryBean` ignoring the singleton setting of the advice. ++ +You can append an interceptor name with an asterisk (`*`). Doing so results in the +application of all advisor beans with names that start with the part before the asterisk +to be applied. You can find an example of using this feature in <>. -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 +* 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 @@ -829,66 +850,66 @@ to be applied. An example of using this feature can be found in < ---- - -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. - -[NOTE] ==== -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 + +Note that the `interceptorNames` property takes a list of `String`, which holds the bean names of the +interceptors or advisors in the current factory. You can use advisors, interceptors, before, after +returning, and throws advice objects. The ordering of advisors is significant. + +NOTE: You might be wondering why the list does not hold bean references. The reason for this is +that, if the singleton property of the `ProxyFactoryBean` 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. -==== +independent instance would need to be returned, so it is necessary to be able to obtain +an instance of the prototype from the factory. Holding a reference is not sufficient. -The "person" bean definition above can be used in place of a Person implementation, as +The `person` bean definition shown earlier can be used in place of a `Person` implementation, as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- 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: +with an ordinary Java object. The following example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -950,16 +972,19 @@ with an ordinary Java object: ---- +==== -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 +The `PersonUser` class in this example exposes a property of type `Person`. As far as +it is 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). +to cast it to the `Advised` interface (discussed later). -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: +You can conceal the distinction between target and proxy by using an anonymous +inner bean. Only the `ProxyFactoryBean` definition is different. The +advice is included only for completeness. The following example shows how to use an +anonymous inner bean: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -986,58 +1011,61 @@ advice is included only for completeness: ---- +==== -This has the advantage that there's only one object of type `Person`: useful if we want +Using an anonymous inner bean has the advantage that there is only one object of type `Person`. This is 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. +object or need to avoid any ambiguity with Spring IoC autowiring. There is 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. +factory might actually be an advantage (for example, in certain test scenarios). [[aop-api-proxying-class]] -=== Proxying classes +=== 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 +Imagine that in our earlier example, there was no `Person` interface. We needed to advise +a class called `Person` that did not implement any business interface. In this case, you +can configure Spring to use CGLIB proxying rather than dynamic proxies. To do so, set the +`proxyTargetClass` property on the `ProxyFactoryBean` shown earlier to `true`. While it is best to +program to interfaces rather than classes, the ability to advise classes that do not 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 +is not 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. +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. +* `Final` methods cannot be advised, as they cannot be overridden. * There is no need to add CGLIB to your classpath. As of Spring 3.2, CGLIB is repackaged - and included in the spring-core JAR. In other words, CGLIB-based AOP will work "out of - the box" just as do JDK dynamic proxies. + and included in the spring-core JAR. In other words, CGLIB-based AOP works "`out of + the box`", as do JDK dynamic proxies. -There's little performance difference between CGLIB proxying and dynamic proxies. As of +There is 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. [[aop-global-advisors]] -=== Using 'global' advisors +=== 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: +By appending an asterisk to an interceptor name, all advisors with bean names that match +the part before the asterisk are added to the advisor chain. This can come in handy +if you need to add a standard set of "`global`" advisors. The following example defines +two global advisors: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1053,19 +1081,20 @@ if you need to add a standard set of 'global' advisors: ---- - +==== [[aop-concise-proxy]] -== Concise proxy definitions +== 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: +First, we create a parent, template, bean definition for the proxy, as follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1079,11 +1108,14 @@ First a parent, __template__, bean definition is created for the proxy: ---- +==== -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. +This is never instantiated itself, so it can actually be incomplete. Then, each proxy +that needs to be created is a child bean definition, which wraps the target of the +proxy as an inner bean definition, since the target is never used on its own anyway. +The following example shows such a child bean: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1094,10 +1126,12 @@ proxy as an inner bean definition, since the target will never be used on its ow ---- +==== -It is of course possible to override properties from the parent template, such as in -this case, the transaction propagation settings: +You can override properties from the parent template. In the following example, +we override the transaction propagation settings: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1116,30 +1150,31 @@ this case, the transaction propagation settings: ---- +==== -Note that in the example above, we have explicitly marked the parent bean definition as -__abstract__ by using the __abstract__ attribute, as described +Note that in the parent bean example, we explicitly marked the parent bean definition as +being abstract by setting the `abstract` attribute to `true`, as described <>, 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 +instantiated. Application contexts (but not simple bean factories), by default, +pre-instantiate all singletons. Therefore, it is important (at least for singleton beans) +that, if you have a (parent) bean definition that 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 actually tries to pre-instantiate it. - [[aop-prog]] -== Creating AOP proxies programmatically with the ProxyFactory +== Creating AOP Proxies Programmatically with the `ProxyFactory` -It's easy to create AOP proxies programmatically using Spring. This enables you to use +It is easy to create AOP proxies programmatically with Spring. This lets you 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: +The interfaces implemented by the target object are +automatically proxied. The following listing shows creation of a proxy for a target object, with one +interceptor and one advisor: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1148,39 +1183,37 @@ automatically be proxied: 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 +object, as in the preceding example, or specify the interfaces to be proxied in an alternate constructor. -You can add advices (with interceptors as a specialized kind of advice) and/or advisors, -and manipulate them for the life of the ProxyFactory. If you add an -IntroductionInterceptionAroundAdvisor, you can cause the proxy to implement additional +You can add advices (with interceptors as a specialized kind of advice), advisors, or both +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. +There are also convenience methods on `ProxyFactory` (inherited from `AdvisedSupport`) +that let you add other advice types, such as before and throws advice. +`AdvisedSupport` is the superclass of both `ProxyFactory` and `ProxyFactoryBean`. -[TIP] -==== -Integrating AOP proxy creation with the IoC framework is best practice in most +TIP: 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. -==== - +as you should in general. [[aop-api-advised]] -== Manipulating advised objects +== Manipulating Advised Objects -However you create AOP proxies, you can manipulate them using the +However you create AOP proxies, you can manipulate them BY 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 +interface, no matter which other interfaces it implements. This interface includes the following methods: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1204,27 +1237,29 @@ following methods: 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 +The `getAdvisors()` method returns 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 is the object that you added. If you added an +interceptor or other advice type, Spring wrapped this in an advisor with a +pointcut that always returns `true`. Thus, if you added a `MethodInterceptor`, the advisor +returned for this index is a `DefaultPointcutAdvisor` that returns 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 +The `addAdvisor()` methods can be used to add any `Advisor`. Usually, the advisor holding +pointcut and advice is the generic `DefaultPointcutAdvisor`, which you can use 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 +By default, it is possible to add or remove advisors or interceptors even once a proxy +has been created. The only restriction is that it is impossible to add or remove an +introduction advisor, as existing proxies from the factory do 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 +The following example shows casting an AOP proxy to the `Advised` interface and examining and manipulating its advice: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1243,64 +1278,64 @@ manipulating its advice: assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length); ---- - -[NOTE] ==== -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 + +NOTE: It is questionable whether it is 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). We 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 +advice, getting inside a method invocation that we want to test. (For example, the advice can +get inside a transaction created for that method, perhaps 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 +Depending on how you created the proxy, you can usually set a `frozen` flag. In that +case, the `Advised` `isFrozen()` method returns `true`, and any attempts to modify +advice through addition or removal results 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. - [[aop-autoproxy]] == Using the "auto-proxy" facility -So far we've considered explicit creation of AOP proxies using a `ProxyFactoryBean` or +So far, we have considered explicit creation of AOP proxies by using a `ProxyFactoryBean` or similar factory bean. -Spring also allows us to use "auto-proxy" bean definitions, which can automatically -proxy selected bean definitions. This is built on Spring "bean post processor" +Spring also lets us use "`auto-proxy`" bean definitions, which can automatically +proxy selected bean definitions. This is built on Spring's "`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 auto-proxying: you don't need to use `ProxyFactoryBean`. +to configure the auto-proxy infrastructure. This lets you declare the targets +eligible for auto-proxying. You neet not use `ProxyFactoryBean`. There are two ways to do this: -* Using an auto-proxy creator that refers to specific beans in the current context. -* A special case of auto-proxy creation that deserves to be considered separately; +* By using an auto-proxy creator that refers to specific beans in the current context. +* A special case of auto-proxy creation that deserves to be considered separately: auto-proxy creation driven by source-level metadata attributes. [[aop-autoproxy-choices]] -=== Autoproxy bean definitions +=== Auto-proxy Bean Definitions + +This section covers the auto-proxy creators provided by the +`org.springframework.aop.framework.autoproxy` package. -The `org.springframework.aop.framework.autoproxy` package provides the following -standard auto-proxy creators. [[aop-api-autoproxy]] -==== BeanNameAutoProxyCreator +==== `BeanNameAutoProxyCreator` The `BeanNameAutoProxyCreator` class is a `BeanPostProcessor` that automatically creates -AOP proxies for beans with names matching literal values or wildcards. +AOP proxies for beans with names that match literal values or wildcards. The following +example shows how to create a `BeanNameAutoProxyCreator` bean: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1313,28 +1348,29 @@ AOP proxies for beans with names matching literal values or wildcards. ---- +==== As with `ProxyFactoryBean`, there is an `interceptorNames` property rather than a list -of interceptors, to allow correct behavior for prototype advisors. Named "interceptors" +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 +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. +Bean definitions whose names match, such as `jdkMyBean` and `onlyJdk` in the preceding +example, are plain old bean definitions with the target class. An AOP proxy is +automatically created by the `BeanNameAutoProxyCreator`. The same advice is applied +to all matching beans. Note that, if advisors are used (rather than the interceptor in +the preceding example), the pointcuts may apply differently to different beans. [[aop-api-autoproxy-default]] -==== DefaultAdvisorAutoProxyCreator +==== `DefaultAdvisorAutoProxyCreator` -A more general and extremely powerful auto proxy creator is -`DefaultAdvisorAutoProxyCreator`. This will automagically apply eligible advisors in the +A more general and extremely powerful auto-proxy creator is +`DefaultAdvisorAutoProxyCreator`. This automagically applies eligible advisors in the current context, without the need to include specific bean names in the auto-proxy advisor's bean definition. It offers the same merit of consistent configuration and avoidance of duplication as `BeanNameAutoProxyCreator`. @@ -1342,25 +1378,29 @@ 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 +* Specifying any number of advisors in the same or related contexts. Note that these + must be advisors, not 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 +The `DefaultAdvisorAutoProxyCreator` automatically evaluates 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). +(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. +the object is not proxied. As bean definitions are added for new business objects, +they are automatically 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.) +Auto-proxying 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` returns an AOP proxy, not the target business object. (The "`inner +bean`" idiom shown earlier also offers this benefit.) +The following example creates a `DefaultAdvisorAutoProxyCreator` bean and the other +elements discussed in this section: + +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1378,71 +1418,71 @@ bean" idiom shown earlier also offers this benefit.) ---- +==== 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. +you can add new business objects without including specific proxy configuration. +You can also easily drop in additional aspects (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, +The `DefaultAdvisorAutoProxyCreator` offers support for filtering (by using a naming +convention so that only certain advisors are evaluated, which allows the 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. - +correct ordering if this is an issue. The `TransactionAttributeSourceAdvisor` used in the +preceding example has a configurable order value. The default setting is unordered. [[aop-targetsource]] -== Using TargetSources +== Using `TargetSource` Implementations -Spring offers the concept of a __TargetSource__, expressed in the +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` +returning the "`target object`" that implements 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. +Developers who use Spring AOP do not normally need to work directly with `TargetSource` implementations, 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, by using a pool to manage instances. -If you do not specify a TargetSource, a default implementation is used that wraps a +If you do not specify a `TargetSource`, a default implementation is used to wrap 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. +The rest of this section describes the standard target sources provided with Spring and how you can use them. -[TIP] -==== -When using a custom target source, your target will usually need to be a prototype +TIP: 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. -==== [[aop-ts-swap]] -=== Hot swappable target sources +=== 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. +The `org.springframework.aop.target.HotSwappableTargetSource` exists to let the target +of an AOP proxy be switched while letting callers keep their references to it. Changing the target source's target takes effect immediately. The -`HotSwappableTargetSource` is threadsafe. +`HotSwappableTargetSource` is thread-safe. -You can change the target via the `swap()` method on HotSwappableTargetSource as follows: +You can change the target by using the `swap()` method on HotSwappableTargetSource, as the follow example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper"); Object oldTarget = swapper.swap(newTarget); ---- +==== -The XML definitions required look as follows: +The following example shows the required XML definitions: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1456,19 +1496,20 @@ The XML definitions required look as follows: ---- +==== -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 preceding `swap()` call changes the target of the swappable bean. Clients that hold a +reference to that bean are unaware of the change but 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 +Although this example does not add any advice (it is not necessary to add advice to +use a `TargetSource`), any `TargetSource` can be used in conjunction with arbitrary advice. [[aop-ts-pool]] -=== Pooling target sources +=== 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 @@ -1478,20 +1519,17 @@ A crucial difference between Spring pooling and SLSB pooling is that Spring pool 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 Commons Pool 2.2, 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 +Spring provides support for Commons Pool 2.2, which provides a +fairly efficient pooling implementation. You need the `commons-pool` Jar on your +application's classpath to use this feature. You can also subclass `org.springframework.aop.target.AbstractPoolingTargetSource` to support any other pooling API. -[NOTE] +NOTE: Commons Pool 1.5+ is also supported but is deprecated as of Spring Framework 4.2. + +The following listig shows an example configuration: + ==== -Commons Pool 1.5+ is also supported but deprecated as of Spring Framework 4.2. -==== - - -Sample configuration is shown below: - [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1510,23 +1548,25 @@ Sample configuration is shown below: ---- +==== -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 javadocs of -`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. +Note that the target object (`businessObjectTarget` in the preceding example) must be a +prototype. This lets the `PoolingTargetSource` implementation create new instances +of the target to grow the pool as necessary. See the {api-spring-framework}aop/target/AbstractPoolingTargetSource.html[Javadoc of +`AbstractPoolingTargetSource`] and the concrete subclass you wish to use for information +about its properties. `maxSize` is the most basic and is 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. +In this case, `myInterceptor` is the name of an interceptor that would need to be +defined in the same IoC context. However, you need not specify interceptors to +use pooling. If you want only pooling and no other advice, do not set the +`interceptorNames` property at all. -It's possible to configure Spring so as to be able to cast any pooled object to the +You can configure Spring 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: +about the configuration and current size of the pool through an introduction. You +need to define an advisor similar to the following: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1535,45 +1575,46 @@ need to define an advisor like this: ---- +==== 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. +`AbstractPoolingTargetSource` class, hence the use of `MethodInvokingFactoryBean`. This +advisor's name (`poolConfigAdvisor`, here) must be in the list of interceptors names in +the `ProxyFactoryBean` that exposes the pooled object. -The cast will look as follows: +The cast is defined as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- PoolingConfig conf = (PoolingConfig) beanFactory.getBean("businessObject"); System.out.println("Max pool size is " + conf.getMaxSize()); ---- - -[NOTE] ==== -Pooling stateless service objects is not usually necessary. We don't believe it should + +NOTE: Pooling stateless service objects is not usually necessary. We do not 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 auto-proxying. It's possible to set the TargetSources +Simpler pooling is available by using auto-proxying. You can set the `TargetSource` implementations used by any auto-proxy creator. [[aop-ts-prototype]] -=== Prototype target sources +=== 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 +Setting up a "`prototype`" target source is similar to setting up a pooling `TargetSource`. In this +case, a new instance of the target is created on every method invocation. Although +the cost of creating a new object is not high in a modern JVM, the cost of wiring up the +new object (satisfying its IoC dependencies) may be more expensive. Thus, you should not 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.) +To do this, you could modify the `poolTargetSource` definition shown earlier as follows +(we also changed the name, for clarity): +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1581,22 +1622,24 @@ To do this, you could modify the `poolTargetSource` definition shown above as fo ---- +==== -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 +The only property is 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. [[aop-ts-threadlocal]] -=== ThreadLocal target sources +=== `ThreadLocal` 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 +incoming request (per thread that is). The concept of a `ThreadLocal` provides a JDK-wide +facility to transparently store a resource alongside a thread. Setting up a `ThreadLocalTargetSource` is pretty much the same as was explained for the other types -of target source: +of target source, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1604,35 +1647,32 @@ of target source: ---- - -[NOTE] ==== -ThreadLocals come with serious issues (potentially resulting in memory leaks) when -incorrectly using them in a multi-threaded and multi-classloader environments. One + +NOTE: `ThreadLocal` instances come with serious issues (potentially resulting in memory leaks) when +incorrectly using them in multi-threaded and multi-classloader environments. You 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 +the `ThreadLocal` itself (except in the wrapper class). Also, you should +always remember to correctly set and unset (where the latter simply involves 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. -==== - +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 +`ThreadLocal` instances without other proper handling code. [[aop-extensibility]] -== Defining new Advice types +== Defining New Advice 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 +addition to the 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 `org.springframework.aop.framework.adapter` package is an SPI package that lets +support for new custom advice types 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` marker interface. -Please refer to the `org.springframework.aop.framework.adapter` javadocs for further +See the {api-spring-framework}/aop/framework/adapter/package-frame.html[`org.springframework.aop.framework.adapter` Javadoc] for further information. diff --git a/src/docs/asciidoc/core/core-aop.adoc b/src/docs/asciidoc/core/core-aop.adoc index 2d3eae9ceb3..5049f667126 100644 --- a/src/docs/asciidoc/core/core-aop.adoc +++ b/src/docs/asciidoc/core/core-aop.adoc @@ -1,103 +1,94 @@ [[aop]] = Aspect Oriented Programming with Spring - - - -[[aop-introduction]] -== Introduction - -__Aspect-Oriented Programming__ (AOP) complements Object-Oriented Programming (OOP) by +Aspect-oriented Programming (AOP) complements Object-oriented Programming (OOP) by providing another way of thinking about program structure. The key unit of modularity in -OOP is the class, whereas in AOP the unit of modularity is the __aspect__. Aspects -enable the modularization of concerns such as transaction management that cut across -multiple types and objects. (Such concerns are often termed __crosscutting__ concerns in +OOP is the class, whereas in AOP the unit of modularity is the aspect. Aspects +enable the modularization of concerns (such as transaction management) that cut across +multiple types and objects. (Such concerns are often termed "`crosscutting`" concerns in AOP literature.) -One of the key components of Spring is the __AOP framework__. While the Spring IoC -container does not depend on AOP, meaning you do not need to use AOP if you don't want -to, AOP complements Spring IoC to provide a very capable middleware solution. +One of the key components of Spring is the AOP framework. While the Spring IoC +container does not depend on AOP (meaning you do not need to use AOP if you don't want +to), AOP complements Spring IoC to provide a very capable middleware solution. .Spring 2.0+ AOP **** -Spring 2.0 introduced a simpler and more powerful way of writing custom aspects using +Spring 2.0 introduced a simpler and more powerful way of writing custom aspects by using either a <> or the <>. Both of these styles offer fully typed advice and use of the AspectJ pointcut -language, while still using Spring AOP for weaving. +language while still using Spring AOP for weaving. -The Spring 2.0+ schema- and @AspectJ-based AOP support is discussed in this chapter. +This chapter discusses the Spring 2.0+ schema- and @AspectJ-based AOP support. The lower-level AOP support, as commonly exposed in Spring 1.2 applications, is discussed in <>. **** -AOP is used in the Spring Framework to... +AOP is used in the Spring Framework to: -* ... provide declarative enterprise services, especially as a replacement for EJB +* Provide declarative enterprise services, especially as a replacement for EJB declarative services. The most important such service is - <>. -* ... allow users to implement custom aspects, complementing their use of OOP with AOP. + <>. +* Let users implement custom aspects, complementing their use of OOP with AOP. -[NOTE] -==== -If you are interested only in generic declarative services or other pre-packaged +NOTE: If you are interested only in generic declarative services or other pre-packaged declarative middleware services such as pooling, you do not need to work directly with Spring AOP, and can skip most of this chapter. -==== [[aop-introduction-defn]] -=== AOP concepts +== AOP Concepts Let us begin by defining some central AOP concepts and terminology. These terms are not -Spring-specific... unfortunately, AOP terminology is not particularly intuitive; -however, it would be even more confusing if Spring used its own terminology. +Spring-specific. Unfortunately, AOP terminology is not particularly intuitive. +However, it would be even more confusing if Spring used its own terminology. -* __Aspect__: a modularization of a concern that cuts across multiple classes. +* Aspect: A modularization of a concern that cuts across multiple classes. Transaction management is a good example of a crosscutting concern in enterprise Java - applications. In Spring AOP, aspects are implemented using regular classes + applications. In Spring AOP, aspects are implemented by using regular classes (the <>) or regular classes annotated with the - `@Aspect` annotation (the <>). -* __Join point__: a point during the execution of a program, such as the execution of a - method or the handling of an exception. In Spring AOP, a join point __always__ + `@Aspect` annotation (the <>). +* Join point: A point during the execution of a program, such as the execution of a + method or the handling of an exception. In Spring AOP, a join point always represents a method execution. -* __Advice__: action taken by an aspect at a particular join point. Different types of - advice include "around", "before" and "after" advice. (Advice types are discussed - below.) Many AOP frameworks, including Spring, model an advice as an __interceptor__, - maintaining a chain of interceptors __around__ the join point. -* __Pointcut__: a predicate that matches join points. Advice is associated with a +* Advice: Action taken by an aspect at a particular join point. Different types of + advice include "`around`", "`before`" and "`after`" advice. (Advice types are discussed + later.) Many AOP frameworks, including Spring, model an advice as an interceptor and + maintain a chain of interceptors around the join point. +* Pointcut: A predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points as matched by pointcut expressions is central to AOP, and Spring uses the AspectJ pointcut expression language by default. -* __Introduction__: declaring additional methods or fields on behalf of a type. Spring - AOP allows you to introduce new interfaces (and a corresponding implementation) to any +* Introduction: Declaring additional methods or fields on behalf of a type. Spring + AOP lets you introduce new interfaces (and a corresponding implementation) to any advised object. For example, you could use an introduction to make a bean implement an `IsModified` interface, to simplify caching. (An introduction is known as an inter-type declaration in the AspectJ community.) -* __Target object__: object being advised by one or more aspects. Also referred to as - the __advised__ object. Since Spring AOP is implemented using runtime proxies, this - object will always be a __proxied__ object. -* __AOP proxy__: an object created by the AOP framework in order to implement the aspect +* Target object: An object being advised by one or more aspects. Also referred to as + the "`advised object`". Since Spring AOP is implemented by using runtime proxies, this + object is always a proxied object. +* AOP proxy: An object created by the AOP framework in order to implement the aspect contracts (advise method executions and so on). In the Spring Framework, an AOP proxy - will be a JDK dynamic proxy or a CGLIB proxy. -* __Weaving__: linking aspects with other application types or objects to create an + is a JDK dynamic proxy or a CGLIB proxy. +* Weaving: linking aspects with other application types or objects to create an advised object. This can be done at compile time (using the AspectJ compiler, for example), load time, or at runtime. Spring AOP, like other pure Java AOP frameworks, performs weaving at runtime. -Types of advice: +Spring AOP includes the following types of advice: -* __Before advice__: Advice that executes before a join point, but which does not have +* Before advice: Advice that runs before a join point but that does not have the ability to prevent execution flow proceeding to the join point (unless it throws an exception). -* __After returning advice__: Advice to be executed after a join point completes - normally: for example, if a method returns without throwing an exception. -* __After throwing advice__: Advice to be executed if a method exits by throwing an +* After returning advice: Advice to be run after a join point completes + normally (for example, if a method returns without throwing an exception). +* After throwing advice: Advice to be executed if a method exits by throwing an exception. -* __After (finally) advice__: Advice to be executed regardless of the means by which a +* After (finally) advice: Advice to be executed regardless of the means by which a join point exits (normal or exceptional return). -* __Around advice__: Advice that surrounds a join point such as a method invocation. +* Around advice: Advice that surrounds a join point such as a method invocation. This is the most powerful kind of advice. Around advice can perform custom behavior before and after the method invocation. It is also responsible for choosing whether to proceed to the join point or to shortcut the advised method execution by returning its @@ -110,26 +101,26 @@ update a cache with the return value of a method, you are better off implementin after returning advice than an around advice, although an around advice can accomplish the same thing. Using the most specific advice type provides a simpler programming model with less potential for errors. For example, you do not need to invoke the `proceed()` -method on the `JoinPoint` used for around advice, and hence cannot fail to invoke it. +method on the `JoinPoint` used for around advice, and, hence, you cannot fail to invoke it. -In Spring 2.0, all advice parameters are statically typed, so that you work with advice +In Spring 2.0, all advice parameters are statically typed so that you work with advice parameters of the appropriate type (the type of the return value from a method execution for example) rather than `Object` arrays. -The concept of join points, matched by pointcuts, is the key to AOP which distinguishes +The concept of join points matched by pointcuts is the key to AOP, which distinguishes it from older technologies offering only interception. Pointcuts enable advice to be -targeted independently of the Object-Oriented hierarchy. For example, an around advice -providing declarative transaction management can be applied to a set of methods spanning +targeted independently of the object-oriented hierarchy. For example, you can apply an around advice +providing declarative transaction management to a set of methods that span multiple objects (such as all business operations in the service layer). [[aop-introduction-spring-defn]] -=== Spring AOP capabilities and goals +== Spring AOP Capabilities and Goals Spring AOP is implemented in pure Java. There is no need for a special compilation -process. Spring AOP does not need to control the class loader hierarchy, and is thus -suitable for use in a Servlet container or application server. +process. Spring AOP does not need to control the class loader hierarchy and is thus +suitable for use in a servlet container or application server. Spring AOP currently supports only method execution join points (advising the execution of methods on Spring beans). Field interception is not implemented, although support for @@ -138,73 +129,72 @@ to advise field access and update join points, consider a language such as Aspec Spring AOP's approach to AOP differs from that of most other AOP frameworks. The aim is not to provide the most complete AOP implementation (although Spring AOP is quite -capable); it is rather to provide a close integration between AOP implementation and -Spring IoC to help solve common problems in enterprise applications. +capable). Rather, the aim is to provide a close integration between AOP implementation and +Spring IoC, to help solve common problems in enterprise applications. Thus, for example, the Spring Framework's AOP functionality is normally used in -conjunction with the Spring IoC container. Aspects are configured using normal bean -definition syntax (although this allows powerful "autoproxying" capabilities): this is a -crucial difference from other AOP implementations. There are some things you cannot do -easily or efficiently with Spring AOP, such as advise very fine-grained objects (such as -domain objects typically): AspectJ is the best choice in such cases. However, our +conjunction with the Spring IoC container. Aspects are configured by using normal bean +definition syntax (although this allows powerful "`auto-proxying`" capabilities). This is a +crucial difference from other AOP implementations. You cannot do some things +easily or efficiently with Spring AOP, such as advise very fine-grained objects (typically, +domain objects). AspectJ is the best choice in such cases. However, our experience is that Spring AOP provides an excellent solution to most problems in enterprise Java applications that are amenable to AOP. -Spring AOP will never strive to compete with AspectJ to provide a comprehensive AOP -solution. We believe that both proxy-based frameworks like Spring AOP and full-blown -frameworks such as AspectJ are valuable, and that they are complementary, rather than in +Spring AOP never strives to compete with AspectJ to provide a comprehensive AOP +solution. We believe that both proxy-based frameworks such as Spring AOP and full-blown +frameworks such as AspectJ are valuable and that they are complementary, rather than in competition. Spring seamlessly integrates Spring AOP and IoC with AspectJ, to enable -all uses of AOP to be catered for within a consistent Spring-based application +all uses of AOP within a consistent Spring-based application architecture. This integration does not affect the Spring AOP API or the AOP Alliance -API: Spring AOP remains backward-compatible. See <> for a +API. Spring AOP remains backward-compatible. See <> for a discussion of the Spring AOP APIs. [NOTE] ==== -One of the central tenets of the Spring Framework is that of __non-invasiveness__; this +One of the central tenets of the Spring Framework is that of non-invasiveness. This is the idea that you should not be forced to introduce framework-specific classes and -interfaces into your business/domain model. However, in some places the Spring Framework +interfaces into your business or domain model. However, in some places, the Spring Framework does give you the option to introduce Spring Framework-specific dependencies into your -codebase: the rationale in giving you such options is because in certain scenarios it +codebase. The rationale in giving you such options is because, in certain scenarios, it might be just plain easier to read or code some specific piece of functionality in such -a way. The Spring Framework (almost) always offers you the choice though: you have the +a way. However, the Spring Framework (almost) always offers you the choice: You have the freedom to make an informed decision as to which option best suits your particular use case or scenario. One such choice that is relevant to this chapter is that of which AOP framework (and -which AOP style) to choose. You have the choice of AspectJ and/or Spring AOP, and you +which AOP style) to choose. You have the choice of AspectJ, Spring AOP, or both. You also have the choice of either the @AspectJ annotation-style approach or the Spring XML configuration-style approach. The fact that this chapter chooses to introduce the @AspectJ-style approach first should not be taken as an indication that the Spring team favors the @AspectJ annotation-style approach over the Spring XML configuration-style. -See <> for a more complete discussion of the whys and wherefores of each +See <> for a more complete discussion of the "`whys and wherefores`" of each style. ==== [[aop-introduction-proxies]] -=== AOP Proxies +== AOP Proxies -Spring AOP defaults to using standard JDK __dynamic proxies__ for AOP proxies. This +Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied. Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than -interfaces. CGLIB is used by default if a business object does not implement an -interface. As it is good practice to program to interfaces rather than classes; business -classes normally will implement one or more business interfaces. It is possible to +interfaces. By default, CGLIB is used if a business object does not implement an +interface. As it is good practice to program to interfaces rather than classes, business +classes normally implement one or more business interfaces. It is possible to <>, in those (hopefully rare) cases where you -need to advise a method that is not declared on an interface, or where you need to +need to advise a method that is not declared on an interface or where you need to pass a proxied object to a method as a concrete type. -It is important to grasp the fact that Spring AOP is __proxy-based__. See +It is important to grasp the fact that Spring AOP is proxy-based. See <> for a thorough examination of exactly what this implementation detail actually means. - [[aop-ataspectj]] == @AspectJ support @@ -212,39 +202,36 @@ implementation detail actually means. annotations. The @AspectJ style was introduced by the http://www.eclipse.org/aspectj[AspectJ project] as part of the AspectJ 5 release. Spring interprets the same annotations as AspectJ 5, using a library supplied by AspectJ -for pointcut parsing and matching. The AOP runtime is still pure Spring AOP though, and +for pointcut parsing and matching. The AOP runtime is still pure Spring AOP, though, and there is no dependency on the AspectJ compiler or weaver. -[NOTE] -==== -Using the AspectJ compiler and weaver enables use of the full AspectJ language, and is +NOTE: Using the AspectJ compiler and weaver enables use of the full AspectJ language and is discussed in <>. -==== [[aop-aspectj-support]] === Enabling @AspectJ Support -To use @AspectJ aspects in a Spring configuration you need to enable Spring support for -configuring Spring AOP based on @AspectJ aspects, and __autoproxying__ beans based on -whether or not they are advised by those aspects. By autoproxying we mean that if Spring -determines that a bean is advised by one or more aspects, it will automatically generate -a proxy for that bean to intercept method invocations and ensure that advice is executed +To use @AspectJ aspects in a Spring configuration, you need to enable Spring support for +configuring Spring AOP based on @AspectJ aspects and auto-proxying beans based on +whether or not they are advised by those aspects. By auto-proxying, we mean that, if Spring +determines that a bean is advised by one or more aspects, it automatically generates +a proxy for that bean to intercept method invocations and ensures that advice is executed as needed. -The @AspectJ support can be enabled with XML or Java style configuration. In either -case you will also need to ensure that AspectJ's `aspectjweaver.jar` library is on the +The @AspectJ support can be enabled with XML- or Java-style configuration. In either +case, you also need to ensure that AspectJ's `aspectjweaver.jar` library is on the classpath of your application (version 1.8 or later). This library is available in the -`'lib'` directory of an AspectJ distribution or via the Maven Central repository. +`lib` directory of an AspectJ distribution or from the Maven Central repository. [[aop-enable-aspectj-java]] -==== Enabling @AspectJ Support with Java configuration - -To enable @AspectJ support with Java `@Configuration` add the `@EnableAspectJAutoProxy` -annotation: +==== Enabling @AspectJ Support with Java Configuration +To enable @AspectJ support with Java `@Configuration`, add the `@EnableAspectJAutoProxy` +annotation, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -254,21 +241,25 @@ annotation: } ---- +==== + [[aop-enable-aspectj-xml]] -==== Enabling @AspectJ Support with XML configuration +==== Enabling @AspectJ Support with XML Configuration -To enable @AspectJ support with XML based configuration use the `aop:aspectj-autoproxy` -element: +To enable @AspectJ support with XML-based configuration, use the `aop:aspectj-autoproxy` +element, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -This assumes that you are using schema support as described in +This assumes that you use schema support as described in <>. See <> for how to import the tags in the `aop` namespace. @@ -276,27 +267,30 @@ namespace. [[aop-at-aspectj]] -=== Declaring an aspect +=== Declaring an Aspect -With the @AspectJ support enabled, any bean defined in your application context with a -class that is an @AspectJ aspect (has the `@Aspect` annotation) will be automatically -detected by Spring and used to configure Spring AOP. The following example shows the -minimal definition required for a not-very-useful aspect: +With @AspectJ support enabled, any bean defined in your application context with a +class that is an @AspectJ aspect (has the `@Aspect` annotation) is automatically +detected by Spring and used to configure Spring AOP. The next two examples show the +minimal definition required for a not-very-useful aspect. -A regular bean definition in the application context, pointing to a bean class that has +The first of the two example shows a regular bean definition in the application context that points to a bean class that has the `@Aspect` annotation: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- - + ---- +==== -And the `NotVeryUsefulAspect` class definition, annotated with -`org.aspectj.lang.annotation.Aspect` annotation; +The second of the two examples shows the `NotVeryUsefulAspect` class definition, which is annotated with +the `org.aspectj.lang.annotation.Aspect` annotation; +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -308,63 +302,60 @@ And the `NotVeryUsefulAspect` class definition, annotated with } ---- +==== -Aspects (classes annotated with `@Aspect`) may have methods and fields just like any -other class. They may also contain pointcut, advice, and introduction (inter-type) +Aspects (classes annotated with `@Aspect`) can have methods and fields, the same as any +other class. They can also contain pointcut, advice, and introduction (inter-type) declarations. .Autodetecting aspects through component scanning -[NOTE] -==== -You may register aspect classes as regular beans in your Spring XML configuration, or -autodetect them through classpath scanning - just like any other Spring-managed bean. -However, note that the __@Aspect__ annotation is __not__ sufficient for autodetection in -the classpath: For that purpose, you need to add a separate __@Component__ annotation -(or alternatively a custom stereotype annotation that qualifies, as per the rules of +NOTE: You can register aspect classes as regular beans in your Spring XML configuration or +autodetect them through classpath scanning -- the same as any other Spring-managed bean. +However, note that the `@Aspect` annotation is not sufficient for autodetection in +the classpath. For that purpose, you need to add a separate `@Component` annotation +(or, alternatively, a custom stereotype annotation that qualifies, as per the rules of Spring's component scanner). -==== .Advising aspects with other aspects? -[NOTE] -==== -In Spring AOP, it is __not__ possible to have aspects themselves be the target of advice -from other aspects. The __@Aspect__ annotation on a class marks it as an aspect, and -hence excludes it from auto-proxying. -==== +NOTE: In Spring AOP, aspects themselves cannot be the targets of advice +from other aspects. The `@Aspect` annotation on a class marks it as an aspect and, +hence, excludes it from auto-proxying. [[aop-pointcuts]] -=== Declaring a pointcut +=== Declaring a Pointcut -Recall that pointcuts determine join points of interest, and thus enable us to control -when advice executes. __Spring AOP only supports method execution join points for Spring -beans__, so you can think of a pointcut as matching the execution of methods on Spring +Pointcuts determine join points of interest and thus enable us to control +when advice executes. Spring AOP only supports method execution join points for Spring +beans, so you can think of a pointcut as matching the execution of methods on Spring beans. A pointcut declaration has two parts: a signature comprising a name and any -parameters, and a pointcut expression that determines __exactly__ which method +parameters and a pointcut expression that determines exactly which method executions we are interested in. In the @AspectJ annotation-style of AOP, a pointcut signature is provided by a regular method definition, and the pointcut expression is -indicated using the `@Pointcut` annotation (the method serving as the pointcut signature -__must__ have a `void` return type). +indicated by using the `@Pointcut` annotation (the method serving as the pointcut signature +must have a `void` return type). -An example will help make this distinction between a pointcut signature and a pointcut -expression clear. The following example defines a pointcut named `'anyOldTransfer'` that -will match the execution of any method named `'transfer'`: +An example may help make this distinction between a pointcut signature and a pointcut +expression clear. The following example defines a pointcut named `anyOldTransfer` that +matches the execution of any method named `transfer`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @Pointcut("execution(* transfer(..))")// the pointcut expression private void anyOldTransfer() {}// the pointcut signature ---- +==== The pointcut expression that forms the value of the `@Pointcut` annotation is a regular AspectJ 5 pointcut expression. For a full discussion of AspectJ's pointcut language, see the http://www.eclipse.org/aspectj/doc/released/progguide/index.html[AspectJ -Programming Guide] (and for extensions, the +Programming Guide] (and, for extensions, the http://www.eclipse.org/aspectj/doc/released/adk15notebook/index.html[AspectJ 5 -Developers Notebook]) or one of the books on AspectJ such as "Eclipse AspectJ" by Colyer -et. al. or "AspectJ in Action" by Ramnivas Laddad. +Developer's Notebook]) or one of the books on AspectJ (such as _Eclipse AspectJ_, by Colyer +et. al., or _AspectJ in Action_, by Ramnivas Laddad). [[aop-pointcuts-designators]] @@ -373,55 +364,55 @@ et. al. or "AspectJ in Action" by Ramnivas Laddad. Spring AOP supports the following AspectJ pointcut designators (PCD) for use in pointcut expressions: +* `execution`: For matching method execution join points. This is the primary + pointcut designator to use when working with Spring AOP. +* `within`: Limits matching to join points within certain types (the execution + of a method declared within a matching type when using Spring AOP). +* `this`: Limits matching to join points (the execution of methods when using Spring + AOP) where the bean reference (Spring AOP proxy) is an instance of the given type. +* `target`: Limits matching to join points (the execution of methods when using + Spring AOP) where the target object (application object being proxied) is an instance + of the given type. +* `args`: Limits matching to join points (the execution of methods when using Spring + AOP) where the arguments are instances of the given types. +* `@target`: Limits matching to join points (the execution of methods when using + Spring AOP) where the class of the executing object has an annotation of the given type. +* `@args`: Limits matching to join points (the execution of methods when using Spring + AOP) where the runtime type of the actual arguments passed have annotations of the + given types. +* `@within`: Limits matching to join points within types that have the given + annotation (the execution of methods declared in types with the given annotation when + using Spring AOP). +* `@annotation`: Limits matching to join points where the subject of the join point + (the method being executed in Spring AOP) has the given annotation. + .Other pointcut types **** The full AspectJ pointcut language supports additional pointcut designators that are not -supported in Spring. These are: `call, get, set, preinitialization, -staticinitialization, initialization, handler, adviceexecution, withincode, cflow, -cflowbelow, if, @this`, and `@withincode`. Use of these pointcut designators in pointcut -expressions interpreted by Spring AOP will result in an `IllegalArgumentException` being +supported in Spring: `call`, `get`, `set`, `preinitialization`, +`staticinitialization`, `initialization`, `handler`, `adviceexecution`, `withincode`, `cflow`, +`cflowbelow`, `if`, `@this`, and `@withincode`. Use of these pointcut designators in pointcut +expressions interpreted by Spring AOP results in an `IllegalArgumentException` being thrown. The set of pointcut designators supported by Spring AOP may be extended in future releases to support more of the AspectJ pointcut designators. **** -* __execution__ - for matching method execution join points, this is the primary - pointcut designator you will use when working with Spring AOP -* __within__ - limits matching to join points within certain types (simply the execution - of a method declared within a matching type when using Spring AOP) -* __this__ - limits matching to join points (the execution of methods when using Spring - AOP) where the bean reference (Spring AOP proxy) is an instance of the given type -* __target__ - limits matching to join points (the execution of methods when using - Spring AOP) where the target object (application object being proxied) is an instance - of the given type -* __args__ - limits matching to join points (the execution of methods when using Spring - AOP) where the arguments are instances of the given types -* __@target__ - limits matching to join points (the execution of methods when using - Spring AOP) where the class of the executing object has an annotation of the given type -* __@args__ - limits matching to join points (the execution of methods when using Spring - AOP) where the runtime type of the actual arguments passed have annotations of the - given type(s) -* __@within__ - limits matching to join points within types that have the given - annotation (the execution of methods declared in types with the given annotation when - using Spring AOP) -* __@annotation__ - limits matching to join points where the subject of the join point - (method being executed in Spring AOP) has the given annotation - -Because Spring AOP limits matching to only method execution join points, the discussion -of the pointcut designators above gives a narrower definition than you will find in the -AspectJ programming guide. In addition, AspectJ itself has type-based semantics and at -an execution join point both `this` and `target` refer to the same object - the +Because Spring AOP limits matching to only method execution join points, the preceding discussion +of the pointcut designators gives a narrower definition than you can find in the +AspectJ programming guide. In addition, AspectJ itself has type-based semantics and, at +an execution join point, both `this` and `target` refer to the same object: the object executing the method. Spring AOP is a proxy-based system and differentiates -between the proxy object itself (bound to `this`) and the target object behind the -proxy (bound to `target`). +between the proxy object itself (which is bound to `this`) and the target object behind the +proxy (which is bound to `target`). [NOTE] ==== Due to the proxy-based nature of Spring's AOP framework, calls within the target object -are by definition __not__ intercepted. For JDK proxies, only public interface method +are, by definition, not intercepted. For JDK proxies, only public interface method calls on the proxy can be intercepted. With CGLIB, public and protected method calls on -the proxy will be intercepted, and even package-visible methods if necessary. However, +the proxy are intercepted (and even package-visible methods, if necessary). However, common interactions through proxies should always be designed through public signatures. Note that pointcut definitions are generally matched against any intercepted method. @@ -431,78 +422,88 @@ potential non-public interactions through proxies, it needs to be defined accord If your interception needs include method calls or even constructors within the target class, consider the use of Spring-driven <> instead of Spring's proxy-based AOP framework. This constitutes a different mode of AOP usage -with different characteristics, so be sure to make yourself familiar with weaving first +with different characteristics, so be sure to make yourself familiar with weaving before making a decision. ==== -Spring AOP also supports an additional PCD named `bean`. This PCD allows you to limit -the matching of join points to a particular named Spring bean, or to a set of named +Spring AOP also supports an additional PCD named `bean`. This PCD lets you limit +the matching of join points to a particular named Spring bean or to a set of named Spring beans (when using wildcards). The `bean` PCD has the following form: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- bean(idOrNameOfBean) ---- +==== -The `idOrNameOfBean` token can be the name of any Spring bean: limited wildcard -support using the `*` character is provided, so if you establish some naming -conventions for your Spring beans you can quite easily write a `bean` PCD expression -to pick them out. As is the case with other pointcut designators, the `bean` PCD can -be &&'ed, ||'ed, and ! (negated) too. +The `idOrNameOfBean` token can be the name of any Spring bean. Limited wildcard +support that uses the `*` character is provided, so, if you establish some naming +conventions for your Spring beans, you can write a `bean` PCD expression +to select them. As is the case with other pointcut designators, the `bean` PCD can +be used with the `&&` (and), `||` (or), and `!` (negation) operators, too. [NOTE] ==== -Please note that the `bean` PCD is __only__ supported in Spring AOP - and __not__ in +The `bean` PCD is supported only in Spring AOP and not in native AspectJ weaving. It is a Spring-specific extension to the standard PCDs that -AspectJ defines and therefore not available for aspects declared in the `@Aspect` model. +AspectJ defines and is, therefore, not available for aspects declared in the `@Aspect` model. -The `bean` PCD operates at the __instance__ level (building on the Spring bean name -concept) rather than at the type level only (which is what weaving-based AOP is limited -to). Instance-based pointcut designators are a special capability of Spring's +The `bean` PCD operates at the instance level (building on the Spring bean name +concept) rather than at the type level only (to which weaving-based AOP is limited). +Instance-based pointcut designators are a special capability of Spring's proxy-based AOP framework and its close integration with the Spring bean factory, where it is natural and straightforward to identify specific beans by name. ==== + [[aop-pointcuts-combining]] -==== Combining pointcut expressions +==== Combining Pointcut Expressions -Pointcut expressions can be combined using '&&', '||' and '!'. It is also possible to +You can combine pointcut expressions can be combined by using `&&,` `||` and `!`. You can also refer to pointcut expressions by name. The following example shows three pointcut -expressions: `anyPublicOperation` (which matches if a method execution join point -represents the execution of any public method); `inTrading` (which matches if a method -execution is in the trading module), and `tradingOperation` (which matches if a method -execution represents any public method in the trading module). +expressions: +==== [source,java,indent=0] [subs="verbatim"] ---- @Pointcut("execution(public * *(..))") - private void anyPublicOperation() {} + private void anyPublicOperation() {} <1> @Pointcut("within(com.xyz.someapp.trading..*)") - private void inTrading() {} + private void inTrading() {} <2> @Pointcut("anyPublicOperation() && inTrading()") - private void tradingOperation() {} + private void tradingOperation() {} <3> ---- +<1> `anyPublicOperation` matches if a method execution join point represents the execution +of any public method. +<2> `inTrading` matches if a method execution is in the trading module. +<3> `tradingOperation` matches if a method execution represents any public method in the +trading module. +==== + + It is a best practice to build more complex pointcut expressions out of smaller named -components as shown above. When referring to pointcuts by name, normal Java visibility +components, as shown earlier. When referring to pointcuts by name, normal Java visibility rules apply (you can see private pointcuts in the same type, protected pointcuts in the -hierarchy, public pointcuts anywhere and so on). Visibility does not affect pointcut -__matching__. +hierarchy, public pointcuts anywhere, and so on). Visibility does not affect pointcut +matching. [[aop-common-pointcuts]] -==== Sharing common pointcut definitions +==== Sharing Common Pointcut Definitions -When working with enterprise applications, you often want to refer to modules of the +When working with enterprise applications, developers often want to refer to modules of the application and particular sets of operations from within several aspects. We recommend -defining a "SystemArchitecture" aspect that captures common pointcut expressions for -this purpose. A typical such aspect would look as follows: +defining a "`SystemArchitecture`" aspect that captures common pointcut expressions for +this purpose. Such an aspect typically resembles the following example: +==== [source,java,indent=0] [subs="verbatim"] ---- @@ -565,11 +566,13 @@ this purpose. A typical such aspect would look as follows: } ---- +==== -The pointcuts defined in such an aspect can be referred to anywhere that you need a +You can refer to the pointcuts defined in such an aspect anywhere you need a pointcut expression. For example, to make the service layer transactional, you could -write: +write the following: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -585,6 +588,7 @@ write: ---- +==== The `` and `` elements are discussed in <>. The transaction elements are discussed in <>. @@ -594,270 +598,285 @@ transaction elements are discussed in <> for how to make the proxy object available in the advice body. + +* Any join point (method execution only in Spring AOP) where the target object +implements the `AccountService` interface: ++ ==== - -* any join point (method execution only in Spring AOP) where the target object - implements the `AccountService` interface: - [source,java,indent=0] [subs="verbatim,quotes"] ---- target(com.xyz.service.AccountService) ---- - -[NOTE] ==== -'target' is more commonly used in a binding form :- see the following section on advice ++ +NOTE: 'target' is more commonly used in a binding form. See the <> section for how to make the target object available in the advice body. + +* Any join point (method execution only in Spring AOP) that takes a single parameter +and where the argument passed at runtime is `Serializable`: ++ ==== - -* any join point (method execution only in Spring AOP) which takes a single parameter, - and where the argument passed at runtime is `Serializable`: - [source,java,indent=0] [subs="verbatim,quotes"] ---- args(java.io.Serializable) ---- - -[NOTE] ==== -'args' is more commonly used in a binding form :- see the following section on advice ++ +NOTE: 'args' is more commonly used in a binding form. See the <> section for how to make the method arguments available in the advice body. -==== - -Note that the pointcut given in this example is different to `execution(* -*(java.io.Serializable))`: the args version matches if the argument passed at runtime is -Serializable, the execution version matches if the method signature declares a single ++ +Note that the pointcut given in this example is different from `execution(* +*(java.io.Serializable))`. The args version matches if the argument passed at runtime is +`Serializable`, and the execution version matches if the method signature declares a single parameter of type `Serializable`. -* any join point (method execution only in Spring AOP) where the target object has an - `@Transactional` annotation: - +* Any join point (method execution only in Spring AOP) where the target object has a +`@Transactional` annotation: ++ +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @target(org.springframework.transaction.annotation.Transactional) ---- - -[NOTE] ==== -'@target' can also be used in a binding form :- see the following section on advice for ++ +NOTE: You can also use '@target' in a binding form. See the <> section for how to make the annotation object available in the advice body. + +* Any join point (method execution only in Spring AOP) where the declared type of the +target object has an `@Transactional` annotation: ++ ==== - -* any join point (method execution only in Spring AOP) where the declared type of the - target object has an `@Transactional` annotation: - [source,java,indent=0] [subs="verbatim,quotes"] ---- @within(org.springframework.transaction.annotation.Transactional) ---- - -[NOTE] ==== -'@within' can also be used in a binding form :- see the following section on advice for ++ +NOTE: You can also use '@within' in a binding form. See the <> section for how to make the annotation object available in the advice body. + +* Any join point (method execution only in Spring AOP) where the executing method has an +`@Transactional` annotation: ++ ==== - -* any join point (method execution only in Spring AOP) where the executing method has an - `@Transactional` annotation: - [source,java,indent=0] [subs="verbatim,quotes"] ---- @annotation(org.springframework.transaction.annotation.Transactional) ---- - -[NOTE] ==== -'@annotation' can also be used in a binding form :- see the following section on advice ++ +NOTE: You can also use '@annotation' in a binding form. See the <> section for how to make the annotation object available in the advice body. + +* Any join point (method execution only in Spring AOP) which takes a single parameter, +and where the runtime type of the argument passed has the `@Classified` annotation: ++ ==== - -* any join point (method execution only in Spring AOP) which takes a single parameter, - and where the runtime type of the argument passed has the `@Classified` annotation: - [source,java,indent=0] [subs="verbatim,quotes"] ---- @args(com.xyz.security.Classified) ---- - -[NOTE] ==== -'@args' can also be used in a binding form :- see the following section on advice for ++ +NOTE: You can also use '@args' in a binding form. See the <> section how to make the annotation object(s) available in the advice body. + +* Any join point (method execution only in Spring AOP) on a Spring bean named +`tradeService`: ++ ==== - -* any join point (method execution only in Spring AOP) on a Spring bean named - `tradeService`: - [source,java,indent=0] [subs="verbatim,quotes"] ---- bean(tradeService) ---- +==== -* any join point (method execution only in Spring AOP) on Spring beans having names that - match the wildcard expression `*Service`: - +* Any join point (method execution only in Spring AOP) on Spring beans having names that +match the wildcard expression `*Service`: ++ +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- bean(*Service) ---- +==== + [[writing-good-pointcuts]] -==== Writing good pointcuts +==== Writing Good Pointcuts -During compilation, AspectJ processes pointcuts in order to try and optimize matching +During compilation, AspectJ processes pointcuts in order to optimize matching performance. Examining code and determining if each join point matches (statically or dynamically) a given pointcut is a costly process. (A dynamic match means the match -cannot be fully determined from static analysis and a test will be placed in the code to +cannot be fully determined from static analysis and that a test is placed in the code to determine if there is an actual match when the code is running). On first encountering a -pointcut declaration, AspectJ will rewrite it into an optimal form for the matching -process. What does this mean? Basically pointcuts are rewritten in DNF (Disjunctive +pointcut declaration, AspectJ rewrites it into an optimal form for the matching +process. What does this mean? Basically, pointcuts are rewritten in DNF (Disjunctive Normal Form) and the components of the pointcut are sorted such that those components that are cheaper to evaluate are checked first. This means you do not have to worry about understanding the performance of various pointcut designators and may supply them in any order in a pointcut declaration. -However, AspectJ can only work with what it is told, and for optimal performance of -matching you should think about what they are trying to achieve and narrow the search +However, AspectJ can work only with what it is told. For optimal performance of +matching, you should think about what they are trying to achieve and narrow the search space for matches as much as possible in the definition. The existing designators -naturally fall into one of three groups: kinded, scoping and context: +naturally fall into one of three groups: kinded, scoping, and contextual: -* Kinded designators are those which select a particular kind of join point. For - example: execution, get, set, call, handler -* Scoping designators are those which select a group of join points of interest (of - probably many kinds). For example: within, withincode -* Contextual designators are those that match (and optionally bind) based on context. - For example: this, target, @annotation +* Kinded designators select a particular kind of join point: +`execution`, `get`, `set`, `call`, and `handler`. +* Scoping designators select a group of join points of interest +(probably of many kinds): `within` and `withincode` +* Contextual designators match (and optionally bind) based on context: +`this`, `target`, and `@annotation` -A well written pointcut should try and include at least the first two types (kinded and -scoping), whilst the contextual designators may be included if wishing to match based on -join point context, or bind that context for use in the advice. Supplying either just a -kinded designator or just a contextual designator will work but could affect weaving -performance (time and memory used) due to all the extra processing and analysis. Scoping -designators are very fast to match and their usage means AspectJ can very quickly -dismiss groups of join points that should not be further processed - that is why a good +A well written pointcut should include at least the first two types (kinded and +scoping). You can include the contextual designators to match based on +join point context or bind that context for use in the advice. Supplying only a +kinded designator or only a contextual designator works but could affect weaving +performance (time and memory used), due to extra processing and analysis. Scoping +designators are very fast to match, and using them usage means AspectJ can very quickly +dismiss groups of join points that should not be further processed. A good pointcut should always include one if possible. [[aop-advice]] -=== Declaring advice +=== Declaring Advice -Advice is associated with a pointcut expression, and runs before, after, or around +Advice is associated with a pointcut expression and runs before, after, or around method executions matched by the pointcut. The pointcut expression may be either a -simple reference to a named pointcut, or a pointcut expression declared in place. +simple reference to a named pointcut or a pointcut expression declared in place. [[aop-advice-before]] -==== Before advice +==== Before Advice -Before advice is declared in an aspect using the `@Before` annotation: +You can declare before advice in an aspect by using the `@Before` annotation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -874,9 +893,12 @@ Before advice is declared in an aspect using the `@Before` annotation: } ---- +==== -If using an in-place pointcut expression we could rewrite the above example as: +If we use an in-place pointcut expression, we could rewrite the preceding example as the +following example: +==== [source,java,indent=0] [subs="verbatim"] ---- @@ -893,14 +915,17 @@ If using an in-place pointcut expression we could rewrite the above example as: } ---- +==== + [[aop-advice-after-returning]] -==== After returning advice +==== After Returning Advice -After returning advice runs when a matched method execution returns normally. It is -declared using the `@AfterReturning` annotation: +After returning advice runs when a matched method execution returns normally. You can +declare it by using the `@AfterReturning` annotation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -917,17 +942,17 @@ declared using the `@AfterReturning` annotation: } ---- - -[NOTE] -==== -Note: it is of course possible to have multiple advice declarations, and other members -as well, all inside the same aspect. We're just showing a single advice declaration in -these examples to focus on the issue under discussion at the time. ==== -Sometimes you need access in the advice body to the actual value that was returned. You -can use the form of `@AfterReturning` that binds the return value for this: +NOTE: You can have multiple advice declarations (and other members +as well), all inside the same aspect. We show only a single advice declaration in +these examples to focus the effect of each one. +Sometimes, you need access in the advice body to the actual value that was returned. You +can use the form of `@AfterReturning` that binds the return value to get that access, as +the following example shows: + +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -946,23 +971,27 @@ can use the form of `@AfterReturning` that binds the return value for this: } ---- +==== The name used in the `returning` attribute must correspond to the name of a parameter in -the advice method. When a method execution returns, the return value will be passed to +the advice method. When a method execution returns, the return value is passed to the advice method as the corresponding argument value. A `returning` clause also restricts matching to only those method executions that return a value of the specified -type ( `Object` in this case, which will match any return value). +type (in this case, `Object`, which matches any return value). + +Please note that it is not possible to return a totally different reference when +using after returning advice. -Please note that it is __not__ possible to return a totally different reference when -using after-returning advice. [[aop-advice-after-throwing]] -==== After throwing advice +==== After Throwing Advice After throwing advice runs when a matched method execution exits by throwing an -exception. It is declared using the `@AfterThrowing` annotation: +exception. You can declare it by using the `@AfterThrowing` annotation, as the following +example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -979,12 +1008,15 @@ exception. It is declared using the `@AfterThrowing` annotation: } ---- +==== -Often you want the advice to run only when exceptions of a given type are thrown, and -you also often need access to the thrown exception in the advice body. Use the -`throwing` attribute to both restrict matching (if desired, use `Throwable` as the -exception type otherwise) and bind the thrown exception to an advice parameter. +Often, you want the advice to run only when exceptions of a given type are thrown, and +you also often need access to the thrown exception in the advice body. You can use the +`throwing` attribute to both restrict matching (if desired -- use `Throwable` as the +exception type otherwise) and bind the thrown exception to an advice parameter. The +following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1003,21 +1035,24 @@ exception type otherwise) and bind the thrown exception to an advice parameter. } ---- +==== The name used in the `throwing` attribute must correspond to the name of a parameter in the advice method. When a method execution exits by throwing an exception, the exception -will be passed to the advice method as the corresponding argument value. A `throwing` +is passed to the advice method as the corresponding argument value. A `throwing` clause also restricts matching to only those method executions that throw an exception -of the specified type ( `DataAccessException` in this case). +of the specified type ( `DataAccessException`, in this case). [[aop-advice-after-finally]] -==== After (finally) advice +==== After (Finally) Advice -After (finally) advice runs however a matched method execution exits. It is declared +After (finally) advice runs when a matched method execution exits. It is declared by using the `@After` annotation. After advice must be prepared to handle both normal and -exception return conditions. It is typically used for releasing resources, etc. +exception return conditions. It is typically used for releasing resources and similar purposes. +The following example shows how to use after finally advice: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1034,42 +1069,44 @@ exception return conditions. It is typically used for releasing resources, etc. } ---- +==== + [[aop-ataspectj-around-advice]] -==== Around advice +==== Around Advice -The final kind of advice is around advice. Around advice runs "around" a matched method -execution. It has the opportunity to do work both before and after the method executes, -and to determine when, how, and even if, the method actually gets to execute at all. +The last kind of advice is around advice. Around advice runs "`around`" a matched method's +execution. It has the opportunity to do work both before and after the method executes +and to determine when, how, and even if the method actually gets to execute at all. Around advice is often used if you need to share state before and after a method -execution in a thread-safe manner (starting and stopping a timer for example). Always -use the least powerful form of advice that meets your requirements (i.e. don't use -around advice if simple before advice would do). +execution in a thread-safe manner (starting and stopping a timer, for example). Always +use the least powerful form of advice that meets your requirements (that is, do not use +around advice if before advice would do). -Around advice is declared using the `@Around` annotation. The first parameter of the +Around advice is declared by using the `@Around` annotation. The first parameter of the advice method must be of type `ProceedingJoinPoint`. Within the body of the advice, calling `proceed()` on the `ProceedingJoinPoint` causes the underlying method to -execute. The `proceed` method may also be called passing in an `Object[]` - the values -in the array will be used as the arguments to the method execution when it proceeds. +execute. The `proceed` method can also pass in an `Object[]`. The values +in the array are used as the arguments to the method execution when it proceeds. -[NOTE] -==== -The behavior of proceed when called with an Object[] is a little different than the -behavior of proceed for around advice compiled by the AspectJ compiler. For around +NOTE: The behavior of `proceed` when called with an `Object[]` is a little different than the +behavior of `proceed` for around advice compiled by the AspectJ compiler. For around advice written using the traditional AspectJ language, the number of arguments passed to -proceed must match the number of arguments passed to the around advice (not the number +`proceed` must match the number of arguments passed to the around advice (not the number of arguments taken by the underlying join point), and the value passed to proceed in a given argument position supplants the original value at the join point for the entity -the value was bound to (Don't worry if this doesn't make sense right now!). The approach -taken by Spring is simpler and a better match to its proxy-based, execution only -semantics. You only need to be aware of this difference if you are compiling @AspectJ -aspects written for Spring and using proceed with arguments with the AspectJ compiler +the value was bound to (do not worry if this does not make sense right now). The approach +taken by Spring is simpler and a better match to its proxy-based, execution-only +semantics. You only need to be aware of this difference if you compile @AspectJ +aspects written for Spring and use `proceed` with arguments with the AspectJ compiler and weaver. There is a way to write such aspects that is 100% compatible across both -Spring AOP and AspectJ, and this is discussed in the following section on advice -parameters. -==== +Spring AOP and AspectJ, and this is discussed in the <>. +The following example shows how to use around advice: + +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1090,48 +1127,55 @@ parameters. } ---- +==== -The value returned by the around advice will be the return value seen by the caller of -the method. A simple caching aspect for example could return a value from a cache if it -has one, and invoke proceed() if it does not. Note that proceed may be invoked once, -many times, or not at all within the body of the around advice, all of these are quite +The value returned by the around advice is the return value seen by the caller of +the method. For example, a simple caching aspect could return a value from a cache if it +has one and invoke `proceed()` if it does not. Note that `proceed` may be invoked once, +many times, or not at all within the body of the around advice. All of these are legal. -[[aop-ataspectj-advice-params]] -==== Advice parameters -Spring offers fully typed advice - meaning that you declare the parameters you need -in the advice signature (as we saw for the returning and throwing examples above) rather -than work with `Object[]` arrays all the time. We'll see how to make argument and other -contextual values available to the advice body in a moment. First let's take a look at +[[aop-ataspectj-advice-params]] +==== Advice Parameters + +Spring offers fully typed advice, meaning that you declare the parameters you need +in the advice signature (as we saw earlier for the returning and throwing examples) rather +than work with `Object[]` arrays all the time. We see how to make argument and other +contextual values available to the advice body later in this section. First, we take a look at how to write generic advice that can find out about the method the advice is currently advising. [[aop-ataspectj-advice-params-the-joinpoint]] -===== Access to the current JoinPoint +===== Access to the Current `JoinPoint` -Any advice method may declare as its first parameter, a parameter of type -`org.aspectj.lang.JoinPoint` (please note that around advice is __required__ to declare +Any advice method may declare, as its first parameter, a parameter of type +`org.aspectj.lang.JoinPoint` (note that around advice is required to declare a first parameter of type `ProceedingJoinPoint`, which is a subclass of `JoinPoint`. The -`JoinPoint` interface provides a number of useful methods such as `getArgs()` (returns -the method arguments), `getThis()` (returns the proxy object), `getTarget()` (returns -the target object), `getSignature()` (returns a description of the method that is being -advised) and `toString()` (prints a useful description of the method being advised). -Please do consult the javadocs for full details. +`JoinPoint` interface provides a number of useful methods: + +* `getArgs()`: Returns the method arguments. +* `getThis()`: Returns the proxy object. +* `getTarget()`: Returns the target object. +* `getSignature()`: Returns a description of the method that is being advised. +* `toString()`: Prints a useful description of the method being advised. + +See the https://www.eclipse.org/aspectj/doc/released/runtime-api/org/aspectj/lang/JoinPoint.html[Javadoc] for more detail. [[aop-ataspectj-advice-params-passing]] -===== Passing parameters to advice +===== Passing Parameters to Advice -We've already seen how to bind the returned value or exception value (using after +We have already seen how to bind the returned value or exception value (using after returning and after throwing advice). To make argument values available to the advice -body, you can use the binding form of `args`. If a parameter name is used in place of a -type name in an args expression, then the value of the corresponding argument will be +body, you can use the binding form of `args`. If you use a parameter name in place of a +type name in an args expression, the value of the corresponding argument is passed as the parameter value when the advice is invoked. An example should make this -clearer. Suppose you want to advise the execution of dao operations that take an Account +clearer. Suppose you want to advise the execution of DAO operations that take an `Account` object as the first parameter, and you need access to the account in the advice body. You could write the following: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1140,17 +1184,19 @@ You could write the following: // ... } ---- +==== -The `args(account,..)` part of the pointcut expression serves two purposes: firstly, it +The `args(account,..)` part of the pointcut expression serves two purposes. First, it restricts matching to only those method executions where the method takes at least one -parameter, and the argument passed to that parameter is an instance of `Account`; -secondly, it makes the actual `Account` object available to the advice via the `account` +parameter, and the argument passed to that parameter is an instance of `Account`. +Second, it makes the actual `Account` object available to the advice through the `account` parameter. -Another way of writing this is to declare a pointcut that "provides" the `Account` -object value when it matches a join point, and then just refer to the named pointcut +Another way of writing this is to declare a pointcut that "`provides`" the `Account` +object value when it matches a join point, and then refer to the named pointcut from the advice. This would look as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1162,17 +1208,19 @@ from the advice. This would look as follows: // ... } ---- +==== -The interested reader is once more referred to the AspectJ programming guide for more +See the AspectJ programming guide for more details. -The proxy object ( `this`), target object ( `target`), and annotations ( `@within, -@target, @annotation, @args`) can all be bound in a similar fashion. The following -example shows how you could match the execution of methods annotated with an -`@Auditable` annotation, and extract the audit code. +The proxy object ( `this`), target object ( `target`), and annotations ( `@within`, +`@target`, `@annotation`, and `@args`) can all be bound in a similar fashion. The next two +examples show how to match the execution of methods annotated with an +`@Auditable` annotation and extract the audit code: -First the definition of the `@Auditable` annotation: +The first of the two examples shows the definition of the `@Auditable` annotation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1182,9 +1230,11 @@ First the definition of the `@Auditable` annotation: AuditCode value(); } ---- +==== -And then the advice that matches the execution of `@Auditable` methods: +The second of the two examples shows the advice that matches the execution of `@Auditable` methods: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1194,13 +1244,15 @@ And then the advice that matches the execution of `@Auditable` methods: // ... } ---- +==== [[aop-ataspectj-advice-params-generics]] -===== Advice parameters and generics +===== Advice Parameters and Generics Spring AOP can handle generics used in class declarations and method parameters. Suppose -you have a generic type like this: +you have a generic type like the following: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1209,10 +1261,12 @@ you have a generic type like this: void sampleGenericCollectionMethod(Collection param); } ---- +==== -You can restrict interception of method types to certain parameter types by simply -typing the advice parameter to the parameter type you want to intercept the method for: +You can restrict interception of method types to certain parameter types by +typing the advice parameter to the parameter type for which you want to intercept the method: +==== [source,java,indent=0] [subs="verbatim"] ---- @@ -1221,11 +1275,12 @@ typing the advice parameter to the parameter type you want to intercept the meth // Advice implementation } ---- +==== -That this works is pretty obvious as we already discussed above. However, it's worth -pointing out that this won't work for generic collections. So you cannot define a -pointcut like this: +This approach does not work for generic collections. So you cannot define a +pointcut as follows: +==== [source,java,indent=0] [subs="verbatim"] ---- @@ -1234,25 +1289,28 @@ pointcut like this: // Advice implementation } ---- +==== -To make this work we would have to inspect every element of the collection, which is not -reasonable as we also cannot decide how to treat `null` values in general. To achieve -something similar to this you have to type the parameter to `Collection` and manually +To make this work, we would have to inspect every element of the collection, which is not +reasonable, as we also cannot decide how to treat `null` values in general. To achieve +something similar to this, you have to type the parameter to `Collection` and manually check the type of the elements. [[aop-ataspectj-advice-params-names]] -===== Determining argument names +===== Determining Argument Names The parameter binding in advice invocations relies on matching names used in pointcut -expressions to declared parameter names in (advice and pointcut) method signatures. -Parameter names are __not__ available through Java reflection, so Spring AOP uses the -following strategies to determine parameter names: - -* If the parameter names have been specified by the user explicitly, then the specified - parameter names are used: both the advice and the pointcut annotations have - an optional "argNames" attribute which can be used to specify the argument names of - the annotated method - these argument names __are__ available at runtime. For example: +expressions to declared parameter names in advice and pointcut method signatures. +Parameter names are not available through Java reflection, so Spring AOP uses the +following strategy to determine parameter names: +* If the parameter names have been explicitly specified by the user, the specified + parameter names are used. Both the advice and the pointcut annotations have + an optional `argNames` attribute that you can use to specify the argument names of + the annotated method. These argument names are available at runtime. The following example + shows how to use the `argNames` attribute: ++ +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1263,13 +1321,14 @@ following strategies to determine parameter names: // ... use code and bean } ---- - +==== ++ If the first parameter is of the `JoinPoint`, `ProceedingJoinPoint`, or -`JoinPoint.StaticPart` type, you may leave out the name of the parameter from the value -of the "argNames" attribute. For example, if you modify the preceding advice to receive -the join point object, the "argNames" attribute need not include it: - -[source,java,indent=0] +`JoinPoint.StaticPart` type, you ca leave out the name of the parameter from the value +of the `argNames` attribute. For example, if you modify the preceding advice to receive +the join point object, the `argNames` attribute need not include it: ++ +====[source,java,indent=0] [subs="verbatim,quotes"] ---- @Before(value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)", @@ -1279,13 +1338,15 @@ the join point object, the "argNames" attribute need not include it: // ... use code, bean, and jp } ---- - +==== ++ The special treatment given to the first parameter of the `JoinPoint`, `ProceedingJoinPoint`, and `JoinPoint.StaticPart` types is particularly convenient for -advice that do not collect any other join point context. In such situations, you may -simply omit the "argNames" attribute. For example, the following advice need not declare -the "argNames" attribute: - +advice instances that do not collect any other join point context. In such situations, you may +omit the `argNames` attribute. For example, the following advice need not declare +the `argNames` attribute: ++ +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1294,40 +1355,39 @@ the "argNames" attribute: // ... use jp } ---- +==== * Using the `'argNames'` attribute is a little clumsy, so if the `'argNames'` attribute - has not been specified, then Spring AOP will look at the debug information for the - class and try to determine the parameter names from the local variable table. This - information will be present as long as the classes have been compiled with debug + has not been specified, Spring AOP looks at the debug information for the + class and tries to determine the parameter names from the local variable table. This + information is present as long as the classes have been compiled with debug information ( `'-g:vars'` at a minimum). The consequences of compiling with this flag - on are: (1) your code will be slightly easier to understand (reverse engineer), (2) - the class file sizes will be very slightly bigger (typically inconsequential), (3) the - optimization to remove unused local variables will not be applied by your compiler. In - other words, you should encounter no difficulties building with this flag on. + on are: (1) your code is slightly easier to understand (reverse engineer), (2) + the class file sizes are very slightly bigger (typically inconsequential), (3) the + optimization to remove unused local variables is not applied by your compiler. In + other words, you should encounter no difficulties by building with this flag on. ++ +NOTE: If an @AspectJ aspect has been compiled by the AspectJ compiler (ajc) even without the +debug information, you need not add the `argNames` attribute, as the compiler +retain the needed information. -[NOTE] -==== -If an @AspectJ aspect has been compiled by the AspectJ compiler (ajc) even without the -debug information then there is no need to add the argNames attribute as the compiler -will retain the needed information. -==== - -* If the code has been compiled without the necessary debug information, then Spring AOP - will attempt to deduce the pairing of binding variables to parameters (for example, if - only one variable is bound in the pointcut expression, and the advice method only - takes one parameter, the pairing is obvious!). If the binding of variables is - ambiguous given the available information, then an `AmbiguousBindingException` will be +* If the code has been compiled without the necessary debug information, Spring AOP + tries to deduce the pairing of binding variables to parameters (for example, if + only one variable is bound in the pointcut expression, and the advice method + takes only one parameter, the pairing is obvious). If the binding of variables is + ambiguous given the available information, an `AmbiguousBindingException` is thrown. -* If all of the above strategies fail then an `IllegalArgumentException` will be thrown. +* If all of the above strategies fail, an `IllegalArgumentException` is thrown. [[aop-ataspectj-advice-proceeding-with-the-call]] -===== Proceeding with arguments +===== Proceeding with Arguments -We remarked earlier that we would describe how to write a proceed call __with -arguments__ that works consistently across Spring AOP and AspectJ. The solution is -simply to ensure that the advice signature binds each of the method parameters in order. -For example: +We remarked earlier that we would describe how to write a `proceed` call with +arguments that works consistently across Spring AOP and AspectJ. The solution is +to ensure that the advice signature binds each of the method parameters in order. +The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1340,33 +1400,34 @@ For example: return pjp.proceed(new Object[] {newPattern}); } ---- +==== -In many cases you will be doing this binding anyway (as in the example above). +In many cases, you do this binding anyway (as in the preceding example). [[aop-ataspectj-advice-ordering]] -==== Advice ordering +==== Advice Ordering What happens when multiple pieces of advice all want to run at the same join point? Spring AOP follows the same precedence rules as AspectJ to determine the order of advice -execution. The highest precedence advice runs first "on the way in" (so given two pieces -of before advice, the one with highest precedence runs first). "On the way out" from a -join point, the highest precedence advice runs last (so given two pieces of after +execution. The highest precedence advice runs first "`on the way in`" (so, given two pieces +of before advice, the one with highest precedence runs first). "`On the way out`" from a +join point, the highest precedence advice runs last (so, given two pieces of after advice, the one with the highest precedence will run second). -When two pieces of advice defined in __different__ aspects both need to run at the same -join point, unless you specify otherwise the order of execution is undefined. You can +When two pieces of advice defined in different aspects both need to run at the same +join point, unless you specify otherwise, the order of execution is undefined. You can control the order of execution by specifying precedence. This is done in the normal Spring way by either implementing the `org.springframework.core.Ordered` interface in the aspect class or annotating it with the `Order` annotation. Given two aspects, the aspect returning the lower value from `Ordered.getValue()` (or the annotation value) has the higher precedence. -When two pieces of advice defined in __the same__ aspect both need to run at the same +When two pieces of advice defined in the same aspect both need to run at the same join point, the ordering is undefined (since there is no way to retrieve the declaration -order via reflection for javac-compiled classes). Consider collapsing such advice -methods into one advice method per join point in each aspect class, or refactor the -pieces of advice into separate aspect classes - which can be ordered at the aspect level. +order through reflection for javac-compiled classes). Consider collapsing such advice +methods into one advice method per join point in each aspect class or refactor the +pieces of advice into separate aspect classes that you can order at the aspect level. @@ -1377,12 +1438,13 @@ Introductions (known as inter-type declarations in AspectJ) enable an aspect to that advised objects implement a given interface, and to provide an implementation of that interface on behalf of those objects. -An introduction is made using the `@DeclareParents` annotation. This annotation is used +You can make an introduction by using the `@DeclareParents` annotation. This annotation is used to declare that matching types have a new parent (hence the name). For example, given an -interface `UsageTracked`, and an implementation of that interface `DefaultUsageTracked`, +interface named `UsageTracked` and an implementation of that interface named `DefaultUsageTracked`, the following aspect declares that all implementors of service interfaces also implement -the `UsageTracked` interface. (In order to expose statistics via JMX for example.) +the `UsageTracked` interface (to expose statistics via JMX for example): +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1399,40 +1461,41 @@ the `UsageTracked` interface. (In order to expose statistics via JMX for example } ---- +==== The interface to be implemented is determined by the type of the annotated field. The -`value` attribute of the `@DeclareParents` annotation is an AspectJ type pattern :- any -bean of a matching type will implement the UsageTracked interface. Note that in the -before advice of the above example, service beans can be directly used as -implementations of the `UsageTracked` interface. If accessing a bean programmatically +`value` attribute of the `@DeclareParents` annotation is an AspectJ type pattern. Any +bean of a matching type implements the `UsageTracked` interface. Note that, in the +before advice of the preceding example, service beans can be directly used as +implementations of the `UsageTracked` interface. If accessing a bean programmatically, you would write the following: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- UsageTracked usageTracked = (UsageTracked) context.getBean("myService"); ---- +==== [[aop-instantiation-models]] -=== Aspect instantiation models +=== Aspect Instantiation Models -[NOTE] -==== -(This is an advanced topic, so if you are just starting out with AOP you can safely skip -it until later.) -==== +NOTE: This is an advanced topic. If you are just starting out with AOP, you can safely skip +it until later. -By default there will be a single instance of each aspect within the application +By default, there is a single instance of each aspect within the application context. AspectJ calls this the singleton instantiation model. It is possible to define -aspects with alternate lifecycles :- Spring supports AspectJ's `perthis` and `pertarget` +aspects with alternate lifecycles. Spring supports AspectJ's `perthis` and `pertarget` instantiation models ( `percflow, percflowbelow,` and `pertypewithin` are not currently supported). -A "perthis" aspect is declared by specifying a `perthis` clause in the `@Aspect` -annotation. Let's look at an example, and then we'll explain how it works. +You can declare a `perthis` aspect by specifying a `perthis` clause in the `@Aspect` +annotation. Consider the following example: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1448,40 +1511,42 @@ annotation. Let's look at an example, and then we'll explain how it works. } ---- +==== -The effect of the `'perthis'` clause is that one aspect instance will be created for -each unique service object executing a business service (each unique object bound to +In the preceding example, the effect of the `'perthis'` clause is that one aspect instance is created for +each unique service object that executes a business service (each unique object bound to 'this' at join points matched by the pointcut expression). The aspect instance is created the first time that a method is invoked on the service object. The aspect goes out of scope when the service object goes out of scope. Before the aspect instance is created, none of the advice within it executes. As soon as the aspect instance has been -created, the advice declared within it will execute at matched join points, but only -when the service object is the one this aspect is associated with. See the AspectJ -programming guide for more information on per-clauses. +created, the advice declared within it executes at matched join points, but only +when the service object is the one with which this aspect is associated. See the AspectJ +Programming Guide for more information on `per` clauses. -The `'pertarget'` instantiation model works in exactly the same way as perthis, but +The `pertarget` instantiation model works in exactly the same way as `perthis`, but it creates one aspect instance for each unique target object at matched join points. [[aop-ataspectj-example]] -=== Example +=== An AOP Example -Now that you have seen how all the constituent parts work, let's put them together to do -something useful! +Now that you have seen how all the constituent parts work, we can put them together to do +something useful. The execution of business services can sometimes fail due to concurrency issues (for -example, deadlock loser). If the operation is retried, it is quite likely to succeed -next time round. For business services where it is appropriate to retry in such -conditions (idempotent operations that don't need to go back to the user for conflict -resolution), we'd like to transparently retry the operation to avoid the client seeing a +example, a deadlock loser). If the operation is retried, it is likely to succeed +on the next try. For business services where it is appropriate to retry in such +conditions (idempotent operations that do not need to go back to the user for conflict +resolution), we want to transparently retry the operation to avoid the client seeing a `PessimisticLockingFailureException`. This is a requirement that clearly cuts across -multiple services in the service layer, and hence is ideal for implementing via an +multiple services in the service layer and, hence, is ideal for implementing through an aspect. -Because we want to retry the operation, we will need to use around advice so that we can -call proceed multiple times. Here's how the basic aspect implementation looks: +Because we want to retry the operation, we need to use around advice so that we can +call `proceed` multiple times. The following listing shows the basic aspect implementation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1523,17 +1588,19 @@ call proceed multiple times. Here's how the basic aspect implementation looks: } ---- +==== -Note that the aspect implements the `Ordered` interface so we can set the precedence of +Note that the aspect implements the `Ordered` interface so that we can set the precedence of the aspect higher than the transaction advice (we want a fresh transaction each time we -retry). The `maxRetries` and `order` properties will both be configured by Spring. The -main action happens in the `doConcurrentOperation` around advice. Notice that for the -moment we're applying the retry logic to all `businessService()s`. We try to proceed, -and if we fail with an `PessimisticLockingFailureException` we simply try again unless +retry). The `maxRetries` and `order` properties are both configured by Spring. The +main action happens in the `doConcurrentOperation` around advice. Notice that, for the +moment, we apply the retry logic to each `businessService()`. We try to proceed, +and if we fail with a `PessimisticLockingFailureException`, we try again, unless we have exhausted all of our retry attempts. -The corresponding Spring configuration is: +The corresponding Spring configuration follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1544,10 +1611,12 @@ The corresponding Spring configuration is: ---- +==== -To refine the aspect so that it only retries idempotent operations, we might define an +To refine the aspect so that it retries only idempotent operations, we might define the following `Idempotent` annotation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1556,11 +1625,13 @@ To refine the aspect so that it only retries idempotent operations, we might def // marker annotation } ---- +==== -and use the annotation to annotate the implementation of service operations. The change -to the aspect to only retry idempotent operations simply involves refining the pointcut -expression so that only `@Idempotent` operations match: +We can then use the annotation to annotate the implementation of service operations. The change +to the aspect to retry only idempotent operations involves refining the pointcut +expression so that only `@Idempotent` operations match, as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1570,22 +1641,22 @@ expression so that only `@Idempotent` operations match: ... } ---- - +==== [[aop-schema]] -== Schema-based AOP support +== Schema-based AOP Support -If you prefer an XML-based format, then Spring also offers support for defining aspects -using the new "aop" namespace tags. The exact same pointcut expressions and advice kinds -are supported as when using the @AspectJ style, hence in this section we will focus on -the new __syntax__ and refer the reader to the discussion in the previous section +If you prefer an XML-based format, Spring also offers support for defining aspects +using the new `aop` namespace tags. The exact same pointcut expressions and advice kinds +as when using the @AspectJ style are supported. Hence, in this section we focus on +the new syntax and refer the reader to the discussion in the previous section (<>) for an understanding of writing pointcut expressions and the binding of advice parameters. To use the aop namespace tags described in this section, you need to import the -`spring-aop` schema as described in <>. See <> for how to import the tags in the `aop` namespace. @@ -1593,29 +1664,27 @@ for how to import the tags in the `aop` namespace. Within your Spring configurations, all aspect and advisor elements must be placed within an `` element (you can have more than one `` element in an application context configuration). An `` element can contain pointcut, -advisor, and aspect elements (note these must be declared in that order). +advisor, and aspect elements (note that these must be declared in that order). -[WARNING] -==== -The `` style of configuration makes heavy use of Spring's +WARNING: The `` style of configuration makes heavy use of Spring's <> mechanism. This can cause issues (such as advice not -being woven) if you are already using explicit auto-proxying via the use of -`BeanNameAutoProxyCreator` or suchlike. The recommended usage pattern is to use either -just the `` style, or just the `AutoProxyCreator` style. -==== +being woven) if you already use explicit auto-proxying through the use of +`BeanNameAutoProxyCreator` or something similar. The recommended usage pattern is to use either +only the `` style or only the `AutoProxyCreator` style and never mix them. [[aop-schema-declaring-an-aspect]] -=== Declaring an aspect +=== Declaring an Aspect -Using the schema support, an aspect is simply a regular Java object defined as a bean in -your Spring application context. The state and behavior is captured in the fields and -methods of the object, and the pointcut and advice information is captured in the XML. +When you use the schema support, an aspect is a regular Java object defined as a bean in +your Spring application context. The state and behavior are captured in the fields and +methods of the object, and the pointcut and advice information are captured in the XML. -An aspect is declared using the element, and the backing bean is referenced -using the `ref` attribute: +You can declare an aspect by using the element, and reference the backing bean +by using the `ref` attribute, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1629,21 +1698,23 @@ using the `ref` attribute: ... ---- +==== -The bean backing the aspect (`"aBean"` in this case) can of course be configured and +The bean that backs the aspect (`aBean` in this case) can of course be configured and dependency injected just like any other Spring bean. [[aop-schema-pointcuts]] -=== Declaring a pointcut +=== Declaring a Pointcut -A named pointcut can be declared inside an element, enabling the pointcut -definition to be shared across several aspects and advisors. +You can declare a named pointcut inside an `` element, letting the pointcut +definition be shared across several aspects and advisors. -A pointcut representing the execution of any business service in the service layer could +A pointcut that represents the execution of any business service in the service layer can be defined as follows: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -1654,13 +1725,15 @@ be defined as follows: ---- +==== Note that the pointcut expression itself is using the same AspectJ pointcut expression -language as described in <>. If you are using the schema based +language as described in <>. If you use the schema based declaration style, you can refer to named pointcuts defined in types (@Aspects) within the pointcut expression. Another way of defining the above pointcut -would be: +would be as follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1671,11 +1744,14 @@ would be: ---- +==== -Assuming you have a `SystemArchitecture` aspect as described in <>. +Assume that you have a `SystemArchitecture` aspect as described in <>. -Declaring a pointcut inside an aspect is very similar to declaring a top-level pointcut: +Then declaring a pointcut inside an aspect is very similar to declaring a top-level pointcut, +as the following example shows: +=== [source,xml,indent=0] [subs="verbatim"] ---- @@ -1692,11 +1768,13 @@ Declaring a pointcut inside an aspect is very similar to declaring a top-level p ---- +==== -Much the same way in an @AspectJ aspect, pointcuts declared using the schema based -definition style may collect join point context. For example, the following pointcut -collects the 'this' object as the join point context and passes it to advice: +In much the same way as an @AspectJ aspect, pointcuts declared by using the schema based +definition style can collect join point context. For example, the following pointcut +collects the `this` object as the join point context and passes it to the advice: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -1715,10 +1793,12 @@ collects the 'this' object as the join point context and passes it to advice: ---- +==== The advice must be declared to receive the collected join point context by including -parameters of the matching names: +parameters of the matching names, as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1726,11 +1806,13 @@ parameters of the matching names: ... } ---- +==== -When combining pointcut sub-expressions, `&&` is awkward within an XML document, and so -the keywords `and`, `or`, and `not` can be used in place of `&&`, `||`, and `!` -respectively. For example, the previous pointcut may be better written as: +When combining pointcut sub-expressions, `&&` is awkward within an XML document, so +you can use the `and`, `or`, and `not` keywords in place of `&&`, `||`, and `!`, +respectively. For example, the previous pointcut can be better written as follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1747,27 +1829,30 @@ respectively. For example, the previous pointcut may be better written as: ---- +==== -Note that pointcuts defined in this way are referred to by their XML id and cannot be +Note that pointcuts defined in this way are referred to by their XML `id` and cannot be used as named pointcuts to form composite pointcuts. The named pointcut support in the -schema based definition style is thus more limited than that offered by the @AspectJ +schema-based definition style is thus more limited than that offered by the @AspectJ style. [[aop-schema-advice]] -=== Declaring advice +=== Declaring Advice -The same five advice kinds are supported as for the @AspectJ style, and they have +The schema-based AOP support uses the same five kinds of advice as the @AspectJ style, and they have exactly the same semantics. + [[aop-schema-advice-before]] -==== Before advice +==== Before Advice Before advice runs before a matched method execution. It is declared inside an -`` using the element. +`` by using the element, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1781,11 +1866,13 @@ Before advice runs before a matched method execution. It is declared inside an ---- +==== -Here `dataAccessOperation` is the id of a pointcut defined at the top ( ``) +Here, `dataAccessOperation` is the `id` of a pointcut defined at the top (``) level. To define the pointcut inline instead, replace the `pointcut-ref` attribute with -a `pointcut` attribute: +a `pointcut` attribute, as follows: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -1799,23 +1886,27 @@ a `pointcut` attribute: ---- +==== As we noted in the discussion of the @AspectJ style, using named pointcuts can significantly improve the readability of your code. -The method attribute identifies a method ( `doAccessCheck`) that provides the body of +The `method` attribute identifies a method (`doAccessCheck`) that provides the body of the advice. This method must be defined for the bean referenced by the aspect element -containing the advice. Before a data access operation is executed (a method execution -join point matched by the pointcut expression), the "doAccessCheck" method on the aspect -bean will be invoked. +that contains the advice. Before a data access operation is executed (a method execution +join point matched by the pointcut expression), the `doAccessCheck` method on the aspect +bean is invoked. + [[aop-schema-advice-after-returning]] -==== After returning advice +==== After Returning Advice After returning advice runs when a matched method execution completes normally. It is -declared inside an `` in the same way as before advice. For example: +declared inside an `` in the same way as before advice. The following example +shows how to declare it: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1829,11 +1920,13 @@ declared inside an `` in the same way as before advice. For example: ---- +==== -Just as in the @AspectJ style, it is possible to get hold of the return value within the -advice body. Use the returning attribute to specify the name of the parameter to which -the return value should be passed: +As in the @AspectJ style, you can get the return value within the +advice body. To do so, use the returning attribute to specify the name of the parameter to which +the return value should be passed, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1848,24 +1941,30 @@ the return value should be passed: ---- +==== -The doAccessCheck method must declare a parameter named `retVal`. The type of this -parameter constrains matching in the same way as described for @AfterReturning. For -example, the method signature may be declared as: +The `doAccessCheck` method must declare a parameter named `retVal`. The type of this +parameter constrains matching in the same way as described for `@AfterReturning`. For +example, you can decleare the method signature as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- public void doAccessCheck(Object retVal) {... ---- +==== + [[aop-schema-advice-after-throwing]] -==== After throwing advice +==== After Throwing Advice After throwing advice executes when a matched method execution exits by throwing an -exception. It is declared inside an `` using the after-throwing element: +exception. It is declared inside an `` by using the after-throwing element, +as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1879,11 +1978,13 @@ exception. It is declared inside an `` using the after-throwing elem ---- +==== -Just as in the @AspectJ style, it is possible to get hold of the thrown exception within -the advice body. Use the throwing attribute to specify the name of the parameter to -which the exception should be passed: +As in the @AspectJ style, you can get the thrown exception within +the advice body. To do so, use the throwing attribute to specify the name of the parameter to +which the exception should be passed as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1898,24 +1999,29 @@ which the exception should be passed: ---- +==== -The doRecoveryActions method must declare a parameter named `dataAccessEx`. The type of -this parameter constrains matching in the same way as described for @AfterThrowing. For -example, the method signature may be declared as: +The `doRecoveryActions` method must declare a parameter named `dataAccessEx`. The type of +this parameter constrains matching in the same way as described for `@AfterThrowing`. For +example, the method signature may be declared as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- public void doRecoveryActions(DataAccessException dataAccessEx) {... ---- +==== + [[aop-schema-advice-after-finally]] -==== After (finally) advice +==== After (Finally) Advice -After (finally) advice runs however a matched method execution exits. It is declared -using the `after` element: +After (finally) advice runs no matter how a matched method execution exits. You can declare it +by using the `after` element, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1929,26 +2035,30 @@ using the `after` element: ---- +==== + [[aop-schema-advice-around]] -==== Around advice +==== Around Advice -The final kind of advice is around advice. Around advice runs "around" a matched method -execution. It has the opportunity to do work both before and after the method executes, -and to determine when, how, and even if, the method actually gets to execute at all. -Around advice is often used if you need to share state before and after a method -execution in a thread-safe manner (starting and stopping a timer for example). Always -use the least powerful form of advice that meets your requirements; don't use around -advice if simple before advice would do. +The last kind of advice is around advice. Around advice runs "`around`" a matched method +execution. It has the opportunity to do work both before and after the method executes +and to determine when, how, and even if the method actually gets to execute at all. +Around advice is often used to share state before and after a method +execution in a thread-safe manner (starting and stopping a timer, for example). Always +use the least powerful form of advice that meets your requirements. Do not use around +advice if before advice can do the job. -Around advice is declared using the `aop:around` element. The first parameter of the +You can declare around advice by using the `aop:around` element. The first parameter of the advice method must be of type `ProceedingJoinPoint`. Within the body of the advice, calling `proceed()` on the `ProceedingJoinPoint` causes the underlying method to -execute. The `proceed` method may also be calling passing in an `Object[]` - the values -in the array will be used as the arguments to the method execution when it proceeds. See -<> for notes on calling proceed with an `Object[]`. +execute. The `proceed` method may also be called with an `Object[]`. The values +in the array are used as the arguments to the method execution when it proceeds. See +<> for notes on calling `proceed` with an `Object[]`. +The following example shows how to declare around advice in XML: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1962,10 +2072,12 @@ in the array will be used as the arguments to the method execution when it proce ---- +==== -The implementation of the `doBasicProfiling` advice would be exactly the same as in the -@AspectJ example (minus the annotation of course): +The implementation of the `doBasicProfiling` advice can be exactly the same as in the +@AspectJ example (minus the annotation, of course), as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1976,20 +2088,23 @@ The implementation of the `doBasicProfiling` advice would be exactly the same as return retVal; } ---- +==== + [[aop-schema-params]] -==== Advice parameters +==== Advice Parameters -The schema based declaration style supports fully typed advice in the same way as -described for the @AspectJ support - by matching pointcut parameters by name against +The schema-based declaration style supports fully typed advice in the same way as +described for the @AspectJ support -- by matching pointcut parameters by name against advice method parameters. See <> for details. If you wish to explicitly specify argument names for the advice methods (not relying on the -detection strategies previously described) then this is done using the `arg-names` -attribute of the advice element, which is treated in the same manner to the "argNames" -attribute in an advice annotation as described in <>. -For example: +detection strategies previously described), you can do so by using the `arg-names` +attribute of the advice element, which is treated in the same manner as the `argNames` +attribute in an advice annotation (as described in <>). +The following example shows how to specify an argument name in XML: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1998,35 +2113,39 @@ For example: method="audit" arg-names="auditable"/> ---- +==== The `arg-names` attribute accepts a comma-delimited list of parameter names. -Find below a slightly more involved example of the XSD-based approach that illustrates -some around advice used in conjunction with a number of strongly typed parameters. +The following slightly more involved example of the XSD-based approach shows +some around advice used in conjunction with a number of strongly typed parameters: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- package x.y.service; - public interface FooService { + public interface PersonService { - Foo getFoo(String fooName, int age); + Person getPerson(String personName, int age); } public class DefaultFooService implements FooService { - public Foo getFoo(String name, int age) { - return new Foo(name, age); + public Person getPerson(String name, int age) { + return new Person(name, age); } } ---- +==== Next up is the aspect. Notice the fact that the `profile(..)` method accepts a number of strongly-typed parameters, the first of which happens to be the join point used to -proceed with the method call: the presence of this parameter is an indication that the -`profile(..)` is to be used as `around` advice: +proceed with the method call. The presence of this parameter is an indication that the +`profile(..)` is to be used as `around` advice, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2049,10 +2168,12 @@ proceed with the method call: the presence of this parameter is an indication th } } ---- +==== -Finally, here is the XML configuration that is required to effect the execution of the -above advice for a particular join point: +Finally, the following example XML configuration effects the execution of the +preceding advice for a particular join point: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2064,7 +2185,7 @@ above advice for a particular join point: http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> - + @@ -2072,11 +2193,11 @@ above advice for a particular join point: - - @@ -2084,27 +2205,32 @@ above advice for a particular join point: ---- +==== -If we had the following driver script, we would get output something like this on -standard output: +Consider the following driver script: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; - import x.y.service.FooService; + import x.y.service.PersonService; public final class Boot { public static void main(final String[] args) throws Exception { BeanFactory ctx = new ClassPathXmlApplicationContext("x/y/plain.xml"); - FooService foo = (FooService) ctx.getBean("fooService"); - foo.getFoo("Pengo", 12); + PersonService person = (PersonService) ctx.getBean("personService"); + person.getPerson("Pengo", 12); } } ---- +==== +With such a Boot class, we would get output similar to the folloiwng on standard output: + +==== [literal] [subs="verbatim,quotes"] ---- @@ -2114,32 +2240,35 @@ ms % Task name ----------------------------------------- 00000 ? execution(getFoo) ---- +==== + [[aop-ordering]] -==== Advice ordering +==== Advice Ordering When multiple advice needs to execute at the same join point (executing method) the ordering rules are as described in <>. The precedence between aspects is determined by either adding the `Order` annotation to the bean -backing the aspect or by having the bean implement the `Ordered` interface. +that backs the aspect or by having the bean implement the `Ordered` interface. [[aop-schema-introductions]] === Introductions -Introductions (known as inter-type declarations in AspectJ) enable an aspect to declare -that advised objects implement a given interface, and to provide an implementation of +Introductions (known as inter-type declarations in AspectJ) let an aspect declare +that advised objects implement a given interface and provide an implementation of that interface on behalf of those objects. -An introduction is made using the `aop:declare-parents` element inside an `aop:aspect` -This element is used to declare that matching types have a new parent (hence the name). -For example, given an interface `UsageTracked`, and an implementation of that interface +You can make an introduction by using the `aop:declare-parents` element inside an `aop:aspect`. +You can use the `aop:declare-parents` element to declare that matching types have a new parent (hence the name). +For example, given an interface named `UsageTracked` and an implementation of that interface named `DefaultUsageTracked`, the following aspect declares that all implementors of service interfaces also implement the `UsageTracked` interface. (In order to expose statistics -via JMX for example.) +through JMX for example.) +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2157,9 +2286,11 @@ via JMX for example.) ---- +==== -The class backing the `usageTracking` bean would contain the method: +The class that backs the `usageTracking` bean would then contain the following method: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2167,24 +2298,27 @@ The class backing the `usageTracking` bean would contain the method: usageTracked.incrementUseCount(); } ---- +==== -The interface to be implemented is determined by `implement-interface` attribute. The -value of the `types-matching` attribute is an AspectJ type pattern :- any bean of a -matching type will implement the `UsageTracked` interface. Note that in the before -advice of the above example, service beans can be directly used as implementations of -the `UsageTracked` interface. If accessing a bean programmatically you would write the +The interface to be implemented is determined by the `implement-interface` attribute. The +value of the `types-matching` attribute is an AspectJ type pattern. Any bean of a +matching type implements the `UsageTracked` interface. Note that, in the before +advice of the preceding example, service beans can be directly used as implementations of +the `UsageTracked` interface. To access a bean programmatically, you could write the following: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- UsageTracked usageTracked = (UsageTracked) context.getBean("myService"); ---- +==== [[aop-schema-instatiation-models]] -=== Aspect instantiation models +=== Aspect Instantiation Models The only supported instantiation model for schema-defined aspects is the singleton model. Other instantiation models may be supported in future releases. @@ -2194,17 +2328,17 @@ model. Other instantiation models may be supported in future releases. [[aop-schema-advisors]] === Advisors -The concept of "advisors" is brought forward from the AOP support defined in Spring +The concept of "`advisors`" comes from the AOP support defined in Spring and does not have a direct equivalent in AspectJ. An advisor is like a small self-contained aspect that has a single piece of advice. The advice itself is -represented by a bean, and must implement one of the advice interfaces described in -<>. Advisors can take advantage of AspectJ pointcut expressions -though. +represented by a bean and must implement one of the advice interfaces described in +<>. Advisors can take advantage of AspectJ pointcut expressions. -Spring supports the advisor concept with the `` element. You will most +Spring supports the advisor concept with the `` element. You most commonly see it used in conjunction with transactional advice, which also has its own -namespace support in Spring. Here's how it looks: +namespace support in Spring. The following example shows an advisor: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -2225,8 +2359,9 @@ namespace support in Spring. Here's how it looks: ---- +==== -As well as the `pointcut-ref` attribute used in the above example, you can also use the +As well as the `pointcut-ref` attribute used in the preceding example, you can also use the `pointcut` attribute to define a pointcut expression inline. To define the precedence of an advisor so that the advice can participate in ordering, @@ -2235,24 +2370,25 @@ use the `order` attribute to define the `Ordered` value of the advisor. [[aop-schema-example]] -=== Example +=== An AOP Schema Example -Let's see how the concurrent locking failure retry example from -<> looks when rewritten using the schema support. +This section shows how the concurrent locking failure retry example from +<> looks when rewritten with the schema support. The execution of business services can sometimes fail due to concurrency issues (for -example, deadlock loser). If the operation is retried, it is quite likely it will -succeed next time round. For business services where it is appropriate to retry in such -conditions (idempotent operations that don't need to go back to the user for conflict -resolution), we'd like to transparently retry the operation to avoid the client seeing a +example, a deadlock loser). If the operation is retried, it is likely to succeed +on the next try. For business services where it is appropriate to retry in such +conditions (idempotent operations that do not need to go back to the user for conflict +resolution), we want to transparently retry the operation to avoid the client seeing a `PessimisticLockingFailureException`. This is a requirement that clearly cuts across -multiple services in the service layer, and hence is ideal for implementing via an +multiple services in the service layer and, hence, is ideal for implementing through an aspect. -Because we want to retry the operation, we'll need to use around advice so that we can -call proceed multiple times. Here's how the basic aspect implementation looks (it's just -a regular Java class using the schema support): +Because we want to retry the operation, we need to use around advice so that we can +call `proceed` multiple times. The following listing shows the basic aspect implementation +(which is a regular Java class that uses the schema support): +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2292,22 +2428,21 @@ a regular Java class using the schema support): } ---- +==== -Note that the aspect implements the `Ordered` interface so we can set the precedence of +Note that the aspect implements the `Ordered` interface so that we can set the precedence of the aspect higher than the transaction advice (we want a fresh transaction each time we -retry). The `maxRetries` and `order` properties will both be configured by Spring. The +retry). The `maxRetries` and `order` properties are both configured by Spring. The main action happens in the `doConcurrentOperation` around advice method. We try to -proceed, and if we fail with a `PessimisticLockingFailureException` we simply try again +proceed. If we fail with a `PessimisticLockingFailureException`, we try again, unless we have exhausted all of our retry attempts. -[NOTE] -==== -This class is identical to the one used in the @AspectJ example, but with the +NOTE: This class is identical to the one used in the @AspectJ example, but with the annotations removed. + +The corresponding Spring configuration is as follows: + ==== - -The corresponding Spring configuration is: - [source,xml,indent=0] [subs="verbatim"] ---- @@ -2332,11 +2467,14 @@ The corresponding Spring configuration is: ---- +==== -Notice that for the time being we assume that all business services are idempotent. If -this is not the case we can refine the aspect so that it only retries genuinely -idempotent operations, by introducing an `Idempotent` annotation: +Notice that, for the time, being we assume that all business services are idempotent. If +this is not the case, we can refine the aspect so that it retries only genuinely +idempotent operations, by introducing an `Idempotent` annotation and using the annotation +to annotate the implementation of service operations, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2345,11 +2483,13 @@ idempotent operations, by introducing an `Idempotent` annotation: // marker annotation } ---- +==== -and using the annotation to annotate the implementation of service operations. The -change to the aspect to retry only idempotent operations simply involves refining the -pointcut expression so that only `@Idempotent` operations match: +The +change to the aspect to retry only idempotent operations involves refining the +pointcut expression so that only `@Idempotent` operations match, as follows: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -2357,41 +2497,41 @@ pointcut expression so that only `@Idempotent` operations match: expression="execution(* com.xyz.myapp.service.*.*(..)) and @annotation(com.xyz.myapp.service.Idempotent)"/> ---- - +==== [[aop-choosing]] -== Choosing which AOP declaration style to use +== Choosing which AOP Declaration Style to Use Once you have decided that an aspect is the best approach for implementing a given -requirement, how do you decide between using Spring AOP or AspectJ, and between the -Aspect language (code) style, @AspectJ annotation style, or the Spring XML style? These +requirement, how do you decide between using Spring AOP or AspectJ and between the +Aspect language (code) style, the @AspectJ annotation style, or the Spring XML style? These decisions are influenced by a number of factors including application requirements, development tools, and team familiarity with AOP. [[aop-spring-or-aspectj]] -=== Spring AOP or full AspectJ? +=== Spring AOP or Full AspectJ? -Use the simplest thing that can work. Spring AOP is simpler than using full AspectJ as +Use the simplest thing that can work. Spring AOP is simpler than using full AspectJ, as there is no requirement to introduce the AspectJ compiler / weaver into your development and build processes. If you only need to advise the execution of operations on Spring -beans, then Spring AOP is the right choice. If you need to advise objects not managed by -the Spring container (such as domain objects typically), then you will need to use -AspectJ. You will also need to use AspectJ if you wish to advise join points other than -simple method executions (for example, field get or set join points, and so on). +beans, Spring AOP is the right choice. If you need to advise objects not managed by +the Spring container (such as domain objects, typically), you need to use +AspectJ. You also need to use AspectJ if you wish to advise join points other than +simple method executions (for example, field get or set join points and so on). -When using AspectJ, you have the choice of the AspectJ language syntax (also known as -the "code style") or the @AspectJ annotation style. Clearly, if you are not using Java -5+ then the choice has been made for you... use the code style. If aspects play a large +When you use AspectJ, you have the choice of the AspectJ language syntax (also known as +the "`code style`") or the @AspectJ annotation style. Clearly, if you do not use Java +5+, the choice has been made for you: Use the code style. If aspects play a large role in your design, and you are able to use the http://www.eclipse.org/ajdt/[AspectJ -Development Tools (AJDT)] plugin for Eclipse, then the AspectJ language syntax is the -preferred option: it is cleaner and simpler because the language was purposefully -designed for writing aspects. If you are not using Eclipse, or have only a few aspects -that do not play a major role in your application, then you may want to consider using -the @AspectJ style and sticking with a regular Java compilation in your IDE, and adding +Development Tools (AJDT)] plugin for Eclipse, the AspectJ language syntax is the +preferred option. It is cleaner and simpler because the language was purposefully +designed for writing aspects. If you do not use Eclipse or have only a few aspects +that do not play a major role in your application, you may want to consider using +the @AspectJ style, sticking with regular Java compilation in your IDE, and adding an aspect weaving phase to your build script. @@ -2399,27 +2539,28 @@ an aspect weaving phase to your build script. [[aop-ataspectj-or-xml]] === @AspectJ or XML for Spring AOP? -If you have chosen to use Spring AOP, then you have a choice of @AspectJ or XML style. +If you have chosen to use Spring AOP, you have a choice of @AspectJ or XML style. There are various tradeoffs to consider. -The XML style will be most familiar to existing Spring users and it is backed by genuine -POJOs. When using AOP as a tool to configure enterprise services then XML can be a good +The XML style may most familiar to existing Spring users, and it is backed by genuine +POJOs. When using AOP as a tool to configure enterprise services, XML can be a good choice (a good test is whether you consider the pointcut expression to be a part of your -configuration you might want to change independently). With the XML style arguably it is +configuration that you might want to change independently). With the XML style, it is arguably clearer from your configuration what aspects are present in the system. -The XML style has two disadvantages. Firstly it does not fully encapsulate the +The XML style has two disadvantages. First, it does not fully encapsulate the implementation of the requirement it addresses in a single place. The DRY principle says that there should be a single, unambiguous, authoritative representation of any piece of -knowledge within a system. When using the XML style, the knowledge of __how__ a -requirement is implemented is split across the declaration of the backing bean class, -and the XML in the configuration file. When using the @AspectJ style there is a single -module - the aspect - in which this information is encapsulated. Secondly, the XML style -is slightly more limited in what it can express than the @AspectJ style: only the -"singleton" aspect instantiation model is supported, and it is not possible to combine +knowledge within a system. When using the XML style, the knowledge of how a +requirement is implemented is split across the declaration of the backing bean class +and the XML in the configuration file. When you use the @AspectJ style, this information +is encapsulated in a single single module: the aspect. Secondly, the XML style +is slightly more limited in what it can express than the @AspectJ style: Only the +"`singleton`" aspect instantiation model is supported, and it is not possible to combine named pointcuts declared in XML. For example, in the @AspectJ style you can write -something like: +something like the following: +==== [source,java,indent=0] [subs="verbatim"] ---- @@ -2432,6 +2573,7 @@ something like: @Pointcut(propertyAccess() && operationReturningAnAccount()) public void accountPropertyAccess() {} ---- +==== In the XML style I can declare the first two pointcuts: @@ -2448,57 +2590,57 @@ In the XML style I can declare the first two pointcuts: The downside of the XML approach is that you cannot define the `accountPropertyAccess` pointcut by combining these definitions. -The @AspectJ style supports additional instantiation models, and richer pointcut +The @AspectJ style supports additional instantiation models and richer pointcut composition. It has the advantage of keeping the aspect as a modular unit. It also has -the advantage the @AspectJ aspects can be understood (and thus consumed) both by Spring -AOP and by AspectJ - so if you later decide you need the capabilities of AspectJ to -implement additional requirements then it is very easy to migrate to an AspectJ-based -approach. On balance the Spring team prefer the @AspectJ style whenever you have aspects -that do more than simple "configuration" of enterprise services. +the advantage that the @AspectJ aspects can be understood (and thus consumed) both by Spring +AOP and by AspectJ. So, if you later decide you need the capabilities of AspectJ to +implement additional requirements, you can easily migrate to an AspectJ-based +approach. On balance, the Spring team prefers the @AspectJ style whenever you have aspects +that do more than simple configuration of enterprise services. [[aop-mixing-styles]] -== Mixing aspect types +== Mixing Aspect Types -It is perfectly possible to mix @AspectJ style aspects using the autoproxying support, -schema-defined `` aspects, `` declared advisors and even -proxies and interceptors defined using the Spring 1.2 style in the same configuration. -All of these are implemented using the same underlying support mechanism and will +It is perfectly possible to mix @AspectJ style aspects by using the auto-proxying support, +schema-defined `` aspects, `` declared advisors, and even +proxies and interceptors defined with the Spring 1.2 style in the same configuration. +All of these are implemented by using the same underlying support mechanism and can co-exist without any difficulty. - [[aop-proxying]] -== Proxying mechanisms +== Proxying Mechanisms Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice). -If the target object to be proxied implements at least one interface then a JDK dynamic -proxy will be used. All of the interfaces implemented by the target type will be -proxied. If the target object does not implement any interfaces then a CGLIB proxy will -be created. +If the target object to be proxied implements at least one interface, a JDK dynamic +proxy is used. All of the interfaces implemented by the target type are +proxied. If the target object does not implement any interfaces, a CGLIB proxy is +created. If you want to force the use of CGLIB proxying (for example, to proxy every method -defined for the target object, not just those implemented by its interfaces) you can do -so. However, there are some issues to consider: +defined for the target object, not only those implemented by its interfaces), you can do +so. However, you should consider the following issues: * `final` methods cannot be advised, as they cannot be overridden. * As of Spring 3.2, it is no longer necessary to add CGLIB to your project classpath, as - CGLIB classes are repackaged under org.springframework and included directly in the - spring-core JAR. This means that CGLIB-based proxy support 'just works' in the same + CGLIB classes are repackaged under `org.springframework` and included directly in the + spring-core JAR. This means that CGLIB-based proxy support "`just works`", in the same way that JDK dynamic proxies always have. -* As of Spring 4.0, the constructor of your proxied object will NOT be called twice - anymore since the CGLIB proxy instance will be created via Objenesis. Only if your +* As of Spring 4.0, the constructor of your proxied object is NOT called twice + any more, since the CGLIB proxy instance is created through Objenesis. Only if your JVM does not allow for constructor bypassing, you might see double invocations and corresponding debug log entries from Spring's AOP support. -To force the use of CGLIB proxies set the value of the `proxy-target-class` attribute of -the `` element to true: +To force the use of CGLIB proxies, set the value of the `proxy-target-class` attribute of +the `` element to true, as follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2506,42 +2648,47 @@ the `` element to true: ---- +==== -To force CGLIB proxying when using the @AspectJ autoproxy support, set the -`'proxy-target-class'` attribute of the `` element to `true`: +To force CGLIB proxying when you use the @AspectJ auto-proxy support, set the +`proxy-target-class` attribute of the `` element to `true`, as +follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== [NOTE] ==== Multiple `` sections are collapsed into a single unified auto-proxy creator -at runtime, which applies the __strongest__ proxy settings that any of the +at runtime, which applies the _strongest_ proxy settings that any of the `` sections (typically from different XML bean definition files) specified. This also applies to the `` and `` elements. -To be clear: using `proxy-target-class="true"` on ``, -`` or `` elements will force the use of CGLIB -proxies __for all three of them__. +To be clear, using `proxy-target-class="true"` on ``, +``, or `` elements forces the use of CGLIB +proxies _for all three of them_. ==== [[aop-understanding-aop-proxies]] -=== Understanding AOP proxies +=== Understanding AOP Proxies -Spring AOP is __proxy-based__. It is vitally important that you grasp the semantics of +Spring AOP is proxy-based. It is vitally important that you grasp the semantics of what that last statement actually means before you write your own aspects or use any of the Spring AOP-based aspects supplied with the Spring Framework. Consider first the scenario where you have a plain-vanilla, un-proxied, -nothing-special-about-it, straight object reference, as illustrated by the following -code snippet. +nothing-special-about-it, straight object reference, as the following +code snippet shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2557,12 +2704,14 @@ code snippet. } } ---- +==== -If you invoke a method on an object reference, the method is invoked __directly__ on -that object reference, as can be seen below. +If you invoke a method on an object reference, the method is invoked directly on +that object reference, as the following image and listing show: image::images/aop-proxy-plain-pojo-call.png[] +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2577,12 +2726,14 @@ image::images/aop-proxy-plain-pojo-call.png[] } } ---- +==== Things change slightly when the reference that client code has is a proxy. Consider the -following diagram and code snippet. +following diagram and code snippet: image::images/aop-proxy-call.png[] +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2601,25 +2752,27 @@ image::images/aop-proxy-call.png[] } } ---- +==== -The key thing to understand here is that the client code inside the `main(..)` of the -`Main` class __has a reference to the proxy__. This means that method calls on that -object reference will be calls on the proxy, and as such the proxy will be able to +The key thing to understand here is that the client code inside the `main(..)` method of the +`Main` class has a reference to the proxy. This means that method calls on that +object reference are calls on the proxy. As a result, the proxy can delegate to all of the interceptors (advice) that are relevant to that particular method -call. However, once the call has finally reached the target object, the `SimplePojo` -reference in this case, any method calls that it may make on itself, such as -`this.bar()` or `this.foo()`, are going to be invoked against the __this__ reference, -and __not__ the proxy. This has important implications. It means that self-invocation is -__not__ going to result in the advice associated with a method invocation getting a +call. However, once the call has finally reached the target object (the `SimplePojo`, +reference in this case), any method calls that it may make on itself, such as +`this.bar()` or `this.foo()`, are going to be invoked against the `this` reference, +and not the proxy. This has important implications. It means that self-invocation is +not going to result in the advice associated with a method invocation getting a chance to execute. -Okay, so what is to be done about this? The best approach (the term best is used loosely -here) is to refactor your code such that the self-invocation does not happen. For sure, -this does entail some work on your part, but it is the best, least-invasive approach. -The next approach is absolutely horrendous, and I am almost reticent to point it out -precisely because it is so horrendous. You can (choke!) totally tie the logic within -your class to Spring AOP by doing this: +Okay, so what is to be done about this? The best approach (the term, "`best,`" is used loosely +here) is to refactor your code such that the self-invocation does not happen. +This does entail some work on your part, but it is the best, least-invasive approach. +The next approach is absolutely horrendous, and we hesitate to point it out, +precisely because it is so horrendous. You can (painful as it is to us) totally tie the logic within +your class to Spring AOP, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2635,11 +2788,14 @@ your class to Spring AOP by doing this: } } ---- +==== -This totally couples your code to Spring AOP, __and__ it makes the class itself aware of +This totally couples your code to Spring AOP, and it makes the class itself aware of the fact that it is being used in an AOP context, which flies in the face of AOP. It -also requires some additional configuration when the proxy is being created: +also requires some additional configuration when the proxy is being created, as the +following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2659,27 +2815,27 @@ also requires some additional configuration when the proxy is being created: } } ---- +==== Finally, it must be noted that AspectJ does not have this self-invocation issue because it is not a proxy-based AOP framework. - [[aop-aspectj-programmatic]] -== Programmatic creation of @AspectJ Proxies +== Programmatic Creation of @AspectJ Proxies -In addition to declaring aspects in your configuration using either `` or -``, it is also possible programmatically to create proxies that -advise target objects. For the full details of Spring's AOP API, see the next chapter. -Here we want to focus on the ability to automatically create proxies using @AspectJ +In addition to declaring aspects in your configuration by using either `` or +``, it is also possible to programmatically create proxies that +advise target objects. For the full details of Spring's AOP API, see the <>. +Here, we want to focus on the ability to automatically create proxies by using @AspectJ aspects. -The class `org.springframework.aop.aspectj.annotation.AspectJProxyFactory` can be used +You can use the `org.springframework.aop.aspectj.annotation.AspectJProxyFactory` class to create a proxy for a target object that is advised by one or more @AspectJ aspects. -Basic usage for this class is very simple, as illustrated below. See the javadocs for -full information. +The basic usage for this class is very simple, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2696,43 +2852,47 @@ full information. // now get the proxy object... MyInterfaceType proxy = factory.getProxy(); ---- +==== +See the {api-spring-framework}/aop/aspectj/annotation/AspectJProxyFactory.html[Javadoc] for more information. [[aop-using-aspectj]] -== Using AspectJ with Spring applications +== Using AspectJ with Spring Applications -Everything we've covered so far in this chapter is pure Spring AOP. In this section, -we're going to look at how you can use the AspectJ compiler/weaver instead of, or in -addition to, Spring AOP if your needs go beyond the facilities offered by Spring AOP +Everything we have covered so far in this chapter is pure Spring AOP. In this section, +we look at how you can use the AspectJ compileror weaver instead of or in +addition to Spring AOP if your needs go beyond the facilities offered by Spring AOP alone. -Spring ships with a small AspectJ aspect library, which is available standalone in your -distribution as `spring-aspects.jar`; you'll need to add this to your classpath in order +Spring ships with a small AspectJ aspect library, which is available stand-alone in your +distribution as `spring-aspects.jar`. You need to add this to your classpath in order to use the aspects in it. <> and <> discuss the content of this library and how you can use it. <> discusses how to dependency inject AspectJ aspects that are woven using the AspectJ compiler. Finally, <> provides an introduction to load-time weaving for Spring applications -using AspectJ. +that use AspectJ. [[aop-atconfigurable]] -=== Using AspectJ to dependency inject domain objects with Spring +=== Using AspectJ to Dependency Inject Domain Objects with Spring The Spring container instantiates and configures beans defined in your application -context. It is also possible to ask a bean factory to configure a __pre-existing__ -object given the name of a bean definition containing the configuration to be applied. -The `spring-aspects.jar` contains an annotation-driven aspect that exploits this -capability to allow dependency injection of __any object__. The support is intended to -be used for objects created __outside of the control of any container__. Domain objects -often fall into this category because they are often created programmatically using the -`new` operator, or by an ORM tool as a result of a database query. +context. It is also possible to ask a bean factory to configure a pre-existing +object, given the name of a bean definition that contains the configuration to be applied. +`spring-aspects.jar` contains an annotation-driven aspect that exploits this +capability to allow dependency injection of any object. The support is intended to +be used for objects created outside of the control of any container. Domain objects +often fall into this category because they are often created programmatically with the +`new` operator or by an ORM tool as a result of a database query. -The `@Configurable` annotation marks a class as eligible for Spring-driven -configuration. In the simplest case it can be used just as a marker annotation: +The `@Configurable` annotation marks a class as being eligible for Spring-driven +configuration. In the simplest case, you can use purely it as a marker annotation, as the +following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2745,14 +2905,16 @@ configuration. In the simplest case it can be used just as a marker annotation: // ... } ---- +==== -When used as a marker interface in this way, Spring will configure new instances of the -annotated type ( `Account` in this case) using a bean definition (typically -prototype-scoped) with the same name as the fully-qualified type name ( -`com.xyz.myapp.domain.Account`). Since the default name for a bean is the +When used as a marker interface in this way, Spring configures new instances of the +annotated type (`Account`, in this case) by using a bean definition (typically +prototype-scoped) with the same name as the fully-qualified type name +()`com.xyz.myapp.domain.Account`). Since the default name for a bean is the fully-qualified name of its type, a convenient way to declare the prototype definition -is simply to omit the `id` attribute: +is to omit the `id` attribute, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2760,10 +2922,12 @@ is simply to omit the `id` attribute: ---- +==== If you want to explicitly specify the name of the prototype bean definition to use, you -can do so directly in the annotation: +can do so directly in the annotation, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2776,68 +2940,72 @@ can do so directly in the annotation: // ... } ---- +==== -Spring will now look for a bean definition named "account" and use that as the +Spring now looks for a bean definition named `account` and uses that as the definition to configure new `Account` instances. You can also use autowiring to avoid having to specify a dedicated bean definition at -all. To have Spring apply autowiring use the `autowire` property of the -`@Configurable` annotation: specify either `@Configurable(autowire=Autowire.BY_TYPE)` or -`@Configurable(autowire=Autowire.BY_NAME` for autowiring by type or by name -respectively. As an alternative, as of Spring 2.5 it is preferable to specify explicit, +all. To have Spring apply autowiring, use the `autowire` property of the +`@Configurable` annotation. You can specify either `@Configurable(autowire=Autowire.BY_TYPE)` or +`@Configurable(autowire=Autowire.BY_NAME` for autowiring by type or by name, +respectively. As an alternative, as of Spring 2.5, it is preferable to specify explicit, annotation-driven dependency injection for your `@Configurable` beans by using `@Autowired` or `@Inject` at the field or method level (see <> for further details). -Finally you can enable Spring dependency checking for the object references in the newly -created and configured object by using the `dependencyCheck` attribute (for example: +Finally, you can enable Spring dependency checking for the object references in the newly +created and configured object by using the `dependencyCheck` attribute (for example, `@Configurable(autowire=Autowire.BY_NAME,dependencyCheck=true)`). If this attribute is -set to true, then Spring will validate after configuration that all properties (__which -are not primitives or collections__) have been set. +set to `true`, Spring validates after configuration that all properties (which +are not primitives or collections) have been set. -Using the annotation on its own does nothing of course. It is the +Note that using the annotation on its own does nothing. It is the `AnnotationBeanConfigurerAspect` in `spring-aspects.jar` that acts on the presence of -the annotation. In essence the aspect says "after returning from the initialization of a +the annotation. In essence, the aspect says, "`after returning from the initialization of a new object of a type annotated with `@Configurable`, configure the newly created object -using Spring in accordance with the properties of the annotation". In this context, -__initialization__ refers to newly instantiated objects (e.g., objects instantiated with +using Spring in accordance with the properties of the annotation`". In this context, +"`initialization`" refers to newly instantiated objects (for example, objects instantiated with the `new` operator) as well as to `Serializable` objects that are undergoing -deserialization (e.g., via +deserialization (for example, through http://docs.oracle.com/javase/6/docs/api/java/io/Serializable.html[readResolve()]). [NOTE] -==== -One of the key phrases in the above paragraph is '__in essence__'. For most cases, the -exact semantics of '__after returning from the initialization of a new object__' will be -fine... in this context, '__after initialization__' means that the dependencies will be -injected __after__ the object has been constructed - this means that the dependencies -will not be available for use in the constructor bodies of the class. If you want the -dependencies to be injected __before__ the constructor bodies execute, and thus be -available for use in the body of the constructors, then you need to define this on the -`@Configurable` declaration like so: +===== +One of the key phrases in the above paragraph is "`in essence`". For most cases, the +exact semantics of "`after returning from the initialization of a new object`" are +fine. In this context, "`after initialization`" means that the dependencies are +injected after the object has been constructed. This means that the dependencies +are not available for use in the constructor bodies of the class. If you want the +dependencies to be injected before the constructor bodies execute and thus be +available for use in the body of the constructors, you need to define this on the +`@Configurable` declaration, as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @Configurable(preConstruction=true) ---- +==== -You can find out more information about the language semantics of the various pointcut +You can find more information about the language semantics of the various pointcut types in AspectJ http://www.eclipse.org/aspectj/doc/next/progguide/semantics-joinPoints.html[in this appendix] of the http://www.eclipse.org/aspectj/doc/next/progguide/index.html[AspectJ Programming Guide]. -==== +===== -For this to work the annotated types must be woven with the AspectJ weaver - you can -either use a build-time Ant or Maven task to do this (see for example the +For this to work, the annotated types must be woven with the AspectJ weaver. You can +either use a build-time Ant or Maven task to do this (see, for example, the http://www.eclipse.org/aspectj/doc/released/devguide/antTasks.html[AspectJ Development Environment Guide]) or load-time weaving (see <>). The -`AnnotationBeanConfigurerAspect` itself needs configuring by Spring (in order to obtain -a reference to the bean factory that is to be used to configure new objects). If you are -using Java based configuration simply add `@EnableSpringConfigured` to any -`@Configuration` class. +`AnnotationBeanConfigurerAspect` itself needs to be configured by Spring (in order to obtain +a reference to the bean factory that is to be used to configure new objects). If you +use Java-based configuration, you can add `@EnableSpringConfigured` to any +`@Configuration` class, as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2847,24 +3015,28 @@ using Java based configuration simply add `@EnableSpringConfigured` to any } ---- +==== If you prefer XML based configuration, the Spring <> -defines a convenient `context:spring-configured` element: +defines a convenient `context:spring-configured` element, which you can use as follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -Instances of `@Configurable` objects created __before__ the aspect has been configured -will result in a message being issued to the debug log and no configuration of the +Instances of `@Configurable` objects created before the aspect has been configured +result in a message being issued to the debug log and no configuration of the object taking place. An example might be a bean in the Spring configuration that creates -domain objects when it is initialized by Spring. In this case you can use the -"depends-on" bean attribute to manually specify that the bean depends on the -configuration aspect. +domain objects when it is initialized by Spring. In this case, you can use the +`depends-on` bean attribute to manually specify that the bean depends on the +configuration aspect. The following example shows how to use the `depends-on` attribute: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2876,57 +3048,57 @@ configuration aspect. ---- +==== -[NOTE] -==== -Do not activate `@Configurable` processing through the bean configurer aspect unless you +NOTE: Do not activate `@Configurable` processing through the bean configurer aspect unless you really mean to rely on its semantics at runtime. In particular, make sure that you do -not use `@Configurable` on bean classes which are registered as regular Spring beans -with the container: You would get double initialization otherwise, once through the +not use `@Configurable` on bean classes that are registered as regular Spring beans +with the container. Doing so results in double initialization, once through the container and once through the aspect. -==== + [[aop-configurable-testing]] -==== Unit testing @Configurable objects +==== Unit Testing `@Configurable` Objects One of the goals of the `@Configurable` support is to enable independent unit testing of domain objects without the difficulties associated with hard-coded lookups. If -`@Configurable` types have not been woven by AspectJ then the annotation has no affect -during unit testing, and you can simply set mock or stub property references in the -object under test and proceed as normal. If `@Configurable` types __have__ been woven by -AspectJ then you can still unit test outside of the container as normal, but you will +`@Configurable` types have not been woven by AspectJ, the annotation has no affect +during unit testing. You can set mock or stub property references in the +object under test and proceed as normal. If `@Configurable` types have been woven by +AspectJ, you can still unit test outside of the container as normal, but you see a warning message each time that you construct an `@Configurable` object indicating that it has not been configured by Spring. -[[aop-configurable-container]] -==== Working with multiple application contexts -The `AnnotationBeanConfigurerAspect` used to implement the `@Configurable` support is an +[[aop-configurable-container]] +==== Working with Multiple Application Contexts + +The `AnnotationBeanConfigurerAspect` that is used to implement the `@Configurable` support is an AspectJ singleton aspect. The scope of a singleton aspect is the same as the scope of -`static` members, that is to say there is one aspect instance per classloader that -defines the type. This means that if you define multiple application contexts within the -same classloader hierarchy you need to consider where to define the +`static` members: There is one aspect instance per classloader that +defines the type. This means that, if you define multiple application contexts within the +same classloader hierarchy, you need to consider where to define the `@EnableSpringConfigured` bean and where to place `spring-aspects.jar` on the classpath. -Consider a typical Spring web-app configuration with a shared parent application context -defining common business services and everything needed to support them, and one child -application context per servlet containing definitions particular to that servlet. All -of these contexts will co-exist within the same classloader hierarchy, and so the -`AnnotationBeanConfigurerAspect` can only hold a reference to one of them. In this case +Consider a typical Spring web application configuration that has a shared parent application context +that defines common business services, everything needed to support those services, and one child +application context for each servlet (which contains definitions particular to that servlet). All +of these contexts co-exist within the same classloader hierarchy, and so the +`AnnotationBeanConfigurerAspect` can hold a reference to only one of them. In this case, we recommend defining the `@EnableSpringConfigured` bean in the shared (parent) -application context: this defines the services that you are likely to want to inject +application context. This defines the services that you are likely to want to inject into domain objects. A consequence is that you cannot configure domain objects with -references to beans defined in the child (servlet-specific) contexts using the -@Configurable mechanism (probably not something you want to do anyway!). +references to beans defined in the child (servlet-specific) contexts by using the +@Configurable mechanism (which is probably not something you want to do anyway). -When deploying multiple web-apps within the same container, ensure that each -web-application loads the types in `spring-aspects.jar` using its own classloader (for +When deploying multiple web applications within the same container, ensure that each +web application loads the types in `spring-aspects.jar` by using its own classloader (for example, by placing `spring-aspects.jar` in `'WEB-INF/lib'`). If `spring-aspects.jar` is -only added to the container wide classpath (and hence loaded by the shared parent -classloader), all web applications will share the same aspect instance which is probably -not what you want. +added only to the container-wide classpath (and hence loaded by the shared parent +classloader), all web applications share the same aspect instance (which is probably +not what you want). @@ -2934,40 +3106,38 @@ not what you want. === Other Spring aspects for AspectJ In addition to the `@Configurable` aspect, `spring-aspects.jar` contains an AspectJ -aspect that can be used to drive Spring's transaction management for types and methods +aspect that you can use to drive Spring's transaction management for types and methods annotated with the `@Transactional` annotation. This is primarily intended for users who want to use the Spring Framework's transaction support outside of the Spring container. The aspect that interprets `@Transactional` annotations is the -`AnnotationTransactionAspect`. When using this aspect, you must annotate the -__implementation__ class (and/or methods within that class), __not__ the interface (if +`AnnotationTransactionAspect`. When you use this aspect, you must annotate the +implementation class (or methods within that class or both), not the interface (if any) that the class implements. AspectJ follows Java's rule that annotations on -interfaces are __not inherited__. +interfaces are not inherited. A `@Transactional` annotation on a class specifies the default transaction semantics for -the execution of any __public__ operation in the class. +the execution of any public operation in the class. A `@Transactional` annotation on a method within the class overrides the default transaction semantics given by the class annotation (if present). Methods of any visibility may be annotated, including private methods. Annotating non-public methods directly is the only way to get transaction demarcation for the execution of such methods. -[TIP] -==== -Since Spring Framework 4.2, `spring-aspects` provides a similar aspect that offers the +TIP: Since Spring Framework 4.2, `spring-aspects` provides a similar aspect that offers the exact same features for the standard `javax.transaction.Transactional` annotation. Check `JtaAnnotationTransactionAspect` for more details. -==== -For AspectJ programmers that want to use the Spring configuration and transaction -management support but don't want to (or cannot) use annotations, `spring-aspects.jar` +For AspectJ programmers who want to use the Spring configuration and transaction +management support but do not want to (or cannot) use annotations, `spring-aspects.jar` also contains `abstract` aspects you can extend to provide your own pointcut definitions. See the sources for the `AbstractBeanConfigurerAspect` and `AbstractTransactionAspect` aspects for more information. As an example, the following excerpt shows how you could write an aspect to configure all instances of objects -defined in the domain model using prototype bean definitions that match the -fully-qualified class names: +defined in the domain model by using prototype bean definitions that match the +fully qualified class names: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2985,49 +3155,54 @@ fully-qualified class names: } ---- +==== [[aop-aj-configure]] -=== Configuring AspectJ aspects using Spring IoC +=== Configuring AspectJ Aspects by Using Spring IoC -When using AspectJ aspects with Spring applications, it is natural to both want and -expect to be able to configure such aspects using Spring. The AspectJ runtime itself is -responsible for aspect creation, and the means of configuring the AspectJ created -aspects via Spring depends on the AspectJ instantiation model (the `per-xxx` clause) +When you use AspectJ aspects with Spring applications, it is natural to both want and +expect to be able to configure such aspects with Spring. The AspectJ runtime itself is +responsible for aspect creation, and the means of configuring the AspectJ-created +aspects through Spring depends on the AspectJ instantiation model (the `per-xxx` clause) used by the aspect. -The majority of AspectJ aspects are __singleton__ aspects. Configuration of these -aspects is very easy: simply create a bean definition referencing the aspect type as -normal, and include the bean attribute `'factory-method="aspectOf"'`. This ensures that +The majority of AspectJ aspects are singleton aspects. Configuration of these +aspects is easy. You can create a bean definition that references the aspect type as +normal and include the `factory-method="aspectOf"` bean attribute. This ensures that Spring obtains the aspect instance by asking AspectJ for it rather than trying to create -an instance itself. For example: +an instance itself. The following example shows how to use the `factory-method="aspectOf"` attribute: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- + factory-method="aspectOf"> <1> ---- +<1> Note the `factory-method="aspectOf"` attribute +==== -Non-singleton aspects are harder to configure: however it is possible to do so by +Non-singleton aspects are harder to configure. However, it is possible to do so by creating prototype bean definitions and using the `@Configurable` support from `spring-aspects.jar` to configure the aspect instances once they have bean created by the AspectJ runtime. If you have some @AspectJ aspects that you want to weave with AspectJ (for example, using load-time weaving for domain model types) and other @AspectJ aspects that you want -to use with Spring AOP, and these aspects are all configured using Spring, then you will -need to tell the Spring AOP @AspectJ autoproxying support which exact subset of the -@AspectJ aspects defined in the configuration should be used for autoproxying. You can +to use with Spring AOP, and these aspects are all configured in Spring, you +need to tell the Spring AOP @AspectJ auto-proxying support which exact subset of the +@AspectJ aspects defined in the configuration should be used for auto-proxying. You can do this by using one or more `` elements inside the `` declaration. Each `` element specifies a name pattern, and only beans with -names matched by at least one of the patterns will be used for Spring AOP autoproxy -configuration: +names matched by at least one of the patterns are used for Spring AOP auto-proxy +configuration. The following example shows how to use `` elements: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3036,72 +3211,68 @@ configuration: ---- +==== -[NOTE] -==== -Do not be misled by the name of the `` element: using it will -result in the creation of __Spring AOP proxies__. The @AspectJ style of aspect -declaration is just being used here, but the AspectJ runtime is __not__ involved. -==== +NOTE: Do not be misled by the name of the `` element. Using it +results in the creation of Spring AOP proxies. The @AspectJ style of aspect +declaration is being used here, but the AspectJ runtime is not involved. [[aop-aj-ltw]] -=== Load-time weaving with AspectJ in the Spring Framework +=== Load-time Weaving with AspectJ in the Spring Framework Load-time weaving (LTW) refers to the process of weaving AspectJ aspects into an application's class files as they are being loaded into the Java virtual machine (JVM). The focus of this section is on configuring and using LTW in the specific context of the -Spring Framework: this section is not an introduction to LTW though. For full details on -the specifics of LTW and configuring LTW with just AspectJ (with Spring not being +Spring Framework. This section is not a general introduction to LTW. For full details on +the specifics of LTW and configuring LTW with only AspectJ (with Spring not being involved at all), see the http://www.eclipse.org/aspectj/doc/released/devguide/ltw.html[LTW section of the AspectJ Development Environment Guide]. -The value-add that the Spring Framework brings to AspectJ LTW is in enabling much -finer-grained control over the weaving process. 'Vanilla' AspectJ LTW is effected using +The value that the Spring Framework brings to AspectJ LTW is in enabling much +finer-grained control over the weaving process. 'Vanilla' AspectJ LTW is effected by using a Java (5+) agent, which is switched on by specifying a VM argument when starting up a -JVM. It is thus a JVM-wide setting, which may be fine in some situations, but often is a -little too coarse. Spring-enabled LTW enables you to switch on LTW on a -__per-ClassLoader__ basis, which obviously is more fine-grained and which can make more +JVM. It is, thus, a JVM-wide setting, which may be fine in some situations but is often a +little too coarse. Spring-enabled LTW lets you switch on LTW on a +per-`ClassLoader` basis, which is more fine-grained and which can make more sense in a 'single-JVM-multiple-application' environment (such as is found in a typical application server environment). Further, <>, this support enables -load-time weaving __without making any modifications to the application server's launch -script__ that will be needed to add `-javaagent:path/to/aspectjweaver.jar` or (as we +load-time weaving without making any modifications to the application server's launch +script that is needed to add `-javaagent:path/to/aspectjweaver.jar` or (as we describe later in this section) `-javaagent:path/to/org.springframework.instrument-{version}.jar` (previously named -`spring-agent.jar`). Developers simply modify one or more files that form the +`spring-agent.jar`). Developers modify one or more files that form the application context to enable load-time weaving instead of relying on administrators who -typically are in charge of the deployment configuration such as the launch script. +typically are in charge of the deployment configuration, such as the launch script. Now that the sales pitch is over, let us first walk through a quick example of AspectJ -LTW using Spring, followed by detailed specifics about elements introduced in the -following example. For a complete example, please see the +LTW that uses Spring, followed by detailed specifics about elements introduced in the +example. For a complete example, see the https://github.com/spring-projects/spring-petclinic[Petclinic sample application]. [[aop-aj-ltw-first-example]] -==== A first example +==== A First Example -Let us assume that you are an application developer who has been tasked with diagnosing +Assume that you are an application developer who has been tasked with diagnosing the cause of some performance problems in a system. Rather than break out a profiling -tool, what we are going to do is switch on a simple profiling aspect that will enable us -to very quickly get some performance metrics, so that we can then apply a finer-grained +tool, we are going to switch on a simple profiling aspect that lets us +quickly get some performance metrics. We can then apply a finer-grained profiling tool to that specific area immediately afterwards. -[NOTE] -==== -The example presented here uses XML style configuration, it is also possible to -configure and use @AspectJ with <>. -Specifically the `@EnableLoadTimeWeaving` annotation can be used as an alternative to +NOTE: The example presented here uses XML configuration. You can also +configure and use @AspectJ with <>. +Specifically, you can use the `@EnableLoadTimeWeaving` annotation as an alternative to `` (see <> for details). + +The following example shows the profiling aspect, which is not fancy -- it is a time-based +profiler that uses the @AspectJ-style of aspect declaration: + ==== - -Here is the profiling aspect. Nothing too fancy, just a quick-and-dirty time-based -profiler, using the @AspectJ-style of aspect declaration. - [source,java,indent=0] [subs="verbatim"] ---- @@ -3133,12 +3304,14 @@ profiler, using the @AspectJ-style of aspect declaration. public void methodsToBeProfiled(){} } ---- +==== -We will also need to create an `META-INF/aop.xml` file, to inform the AspectJ weaver +We also need to create an `META-INF/aop.xml` file, to inform the AspectJ weaver that we want to weave our `ProfilingAspect` into our classes. This file convention, namely the presence of a file (or files) on the Java classpath called -`META-INF/aop.xml` is standard AspectJ. +`META-INF/aop.xml` is standard AspectJ. The following example shows the `aop.xml` file: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3157,14 +3330,16 @@ namely the presence of a file (or files) on the Java classpath called ---- +==== -Now to the Spring-specific portion of the configuration. We need to configure a -`LoadTimeWeaver` (all explained later, just take it on trust for now). This load-time +Now we can move on to the Spring-specific portion of the configuration. We need to configure a +`LoadTimeWeaver` (explained later). This load-time weaver is the essential component responsible for weaving the aspect configuration in one or more `META-INF/aop.xml` files into the classes in your application. The good -thing is that it does not require a lot of configuration, as can be seen below (there -are some more options that you can specify, but these are detailed later). +thing is that it does not require a lot of configuration (there +are some more options that you can specify, but these are detailed later), as can be seen in the following example: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3186,11 +3361,13 @@ are some more options that you can specify, but these are detailed later). **** ---- +==== -Now that all the required artifacts are in place - the aspect, the `META-INF/aop.xml` -file, and the Spring configuration -, let us create a simple driver class with a -`main(..)` method to demonstrate the LTW in action. +Now that all the required artifacts (the aspect, the `META-INF/aop.xml` +file, and the Spring configuration) are in place, we can create the following driver class with a +`main(..)` method to demonstrate the LTW in action: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -3212,30 +3389,35 @@ file, and the Spring configuration -, let us create a simple driver class with a } } ---- +==== -There is one last thing to do. The introduction to this section did say that one could -switch on LTW selectively on a per- `ClassLoader` basis with Spring, and this is true. -However, just for this example, we are going to use a Java agent (supplied with Spring) -to switch on the LTW. This is the command line we will use to run the above `Main` class: +We have one last thing to do. The introduction to this section did say that one could +switch on LTW selectively on a per-`ClassLoader` basis with Spring, and this is true. +However, for this example, we use a Java agent (supplied with Spring) +to switch on the LTW. We use the folloiwng command to run the `Main` class shown earlier: +==== [literal] [subs="verbatim,quotes"] ---- java -javaagent:C:/projects/foo/lib/global/spring-instrument.jar foo.Main ---- +==== The `-javaagent` is a flag for specifying and enabling http://docs.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html[agents -to instrument programs running on the JVM]. The Spring Framework ships with such an +to instrument programs that run on the JVM]. The Spring Framework ships with such an agent, the `InstrumentationSavingAgent`, which is packaged in the `spring-instrument.jar` that was supplied as the value of the `-javaagent` argument in -the above example. +the preceding example. -The output from the execution of the `Main` program will look something like that below. +The output from the execution of the `Main` program looks something like the next example. (I have introduced a `Thread.sleep(..)` statement into the `calculateEntitlement()` implementation so that the profiler actually captures something other than 0 -milliseconds - the `01234` milliseconds is __not__ an overhead introduced by the AOP :) ) +milliseconds (the `01234` milliseconds is not an overhead introduced by the AOP). +The following listing shows the output we got when we ran our profiler: +==== [literal] [subs="verbatim,quotes"] ---- @@ -3247,11 +3429,13 @@ ms % Task name ------ ----- ---------------------------- 01234 100% calculateEntitlement ---- +==== -Since this LTW is effected using full-blown AspectJ, we are not just limited to advising -Spring beans; the following slight variation on the `Main` program will yield the same -result. +Since this LTW is effected by using full-blown AspectJ, we are not limited only to advising +Spring beans. The following slight variation on the `Main` program yields the same +result: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -3273,66 +3457,60 @@ result. } } ---- - -Notice how in the above program we are simply bootstrapping the Spring container, and -then creating a new instance of the `StubEntitlementCalculationService` totally outside -the context of Spring... the profiling advice still gets woven in. - -The example admittedly is simplistic... however the basics of the LTW support in Spring -have all been introduced in the above example, and the rest of this section will explain -the 'why' behind each bit of configuration and usage in detail. - -[NOTE] ==== -The `ProfilingAspect` used in this example may be basic, but it is quite useful. It is a -nice example of a development-time aspect that developers can use during development (of -course), and then quite easily exclude from builds of the application being deployed + +Notice how, in the preceding program, we bootstrap the Spring container and +then create a new instance of the `StubEntitlementCalculationService` totally outside +the context of Spring. The profiling advice still gets woven in. + +Admittedly, the example is simplistic. However, the basics of the LTW support in Spring +have all been introduced in the earlier example, and the rest of this section explains +the "`why`" behind each bit of configuration and usage in detail. + +NOTE: The `ProfilingAspect` used in this example may be basic, but it is quite useful. It is a +nice example of a development-time aspect that developers can use during development +and then easily exclude from builds of the application being deployed into UAT or production. -==== + [[aop-aj-ltw-the-aspects]] ==== Aspects -The aspects that you use in LTW have to be AspectJ aspects. They can be written in -either the AspectJ language itself or you can write your aspects in the @AspectJ-style. -It means that your aspects are then both valid AspectJ __and__ Spring AOP aspects. +The aspects that you use in LTW have to be AspectJ aspects. You can write them in +either the AspectJ language itself, or you can write your aspects in the @AspectJ-style. +Your aspects are then both valid AspectJ and Spring AOP aspects. Furthermore, the compiled aspect classes need to be available on the classpath. + [[aop-aj-ltw-aop_dot_xml]] ==== 'META-INF/aop.xml' -The AspectJ LTW infrastructure is configured using one or more `META-INF/aop.xml` -files, that are on the Java classpath (either directly, or more typically in jar files). +The AspectJ LTW infrastructure is configured by using one or more `META-INF/aop.xml` +files that are on the Java classpath (either directly or, more typically, in jar files). -The structure and contents of this file is detailed in the main AspectJ reference -documentation, and the interested reader is -http://www.eclipse.org/aspectj/doc/released/devguide/ltw-configuration.html[referred to -that resource]. (I appreciate that this section is brief, but the `aop.xml` file is -100% AspectJ - there is no Spring-specific information or semantics that apply to it, -and so there is no extra value that I can contribute either as a result), so rather than -rehash the quite satisfactory section that the AspectJ developers wrote, I am just -directing you there.) +The structure and contents of this file is detailed in the LTW part http://www.eclipse.org/aspectj/doc/released/devguide/ltw-configuration.html[AspectJ reference +documentation]. Because the aop.xml file is 100% AspectJ, we do not describe it futher here. [[aop-aj-ltw-libraries]] ==== Required libraries (JARS) -At a minimum you will need the following libraries to use the Spring Framework's support +At minimum, you need the following libraries to use the Spring Framework's support for AspectJ LTW: * `spring-aop.jar` (version 2.5 or later, plus all mandatory dependencies) * `aspectjweaver.jar` (version 1.6.8 or later) -If you are using the <>, you will also need: +If you use the <>, you also need: * `spring-instrument.jar` [[aop-aj-ltw-spring]] -==== Spring configuration +==== Spring Configuration The key component in Spring's LTW support is the `LoadTimeWeaver` interface (in the `org.springframework.instrument.classloading` package), and the numerous implementations @@ -3341,23 +3519,20 @@ adding one or more `java.lang.instrument.ClassFileTransformers` to a `ClassLoade runtime, which opens the door to all manner of interesting applications, one of which happens to be the LTW of aspects. -[TIP] -==== -If you are unfamiliar with the idea of runtime class file transformation, you are -encouraged to read the javadoc API documentation for the `java.lang.instrument` package -before continuing. This is not a huge chore because there is - rather annoyingly - -precious little documentation there... the key interfaces and classes will at least be -laid out in front of you for reference as you read through this section. -==== +TIP: If you are unfamiliar with the idea of runtime class file transformation, se +the Javadoc API documentation for the `java.lang.instrument` package +before continuing. While that documentation is not comprehensive, at least you can see the +key interfaces and classes (for reference as you read through this section). Configuring a `LoadTimeWeaver` for a particular `ApplicationContext` can be as easy as -adding one line. (Please note that you almost certainly will need to be using an -`ApplicationContext` as your Spring container - typically a `BeanFactory` will not be -enough because the LTW support makes use of `BeanFactoryPostProcessors`.) +adding one line. (Note that you almost certainly need to use an +`ApplicationContext` as your Spring container -- typically, a `BeanFactory` is not +enough because the LTW support uses `BeanFactoryPostProcessors`.) To enable the Spring Framework's LTW support, you need to configure a `LoadTimeWeaver`, -which typically is done using the `@EnableLoadTimeWeaving` annotation. +which typically is done by using the `@EnableLoadTimeWeaving` annotation, as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -3367,11 +3542,13 @@ which typically is done using the `@EnableLoadTimeWeaving` annotation. } ---- +==== -Alternatively, if you prefer XML based configuration, use the +Alternatively, if you prefer XML-based configuration, use the `` element. Note that the element is defined in the -`context` namespace. +`context` namespace. The following example shows how to use ``: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3389,13 +3566,14 @@ Alternatively, if you prefer XML based configuration, use the ---- +==== -The above configuration will define and register a number of LTW-specific infrastructure -beans for you automatically, such as a `LoadTimeWeaver` and an `AspectJWeavingEnabler`. +The preceding configuration automatically defines and registers a number of LTW-specific infrastructure +beans, such as a `LoadTimeWeaver` and an `AspectJWeavingEnabler`, for you. The default `LoadTimeWeaver` is the `DefaultContextLoadTimeWeaver` class, which attempts -to decorate an automatically detected `LoadTimeWeaver`: the exact type of -`LoadTimeWeaver` that will be 'automatically detected' is dependent upon your runtime -environment (summarized in the following table). +to decorate an automatically detected `LoadTimeWeaver`. The exact type of +`LoadTimeWeaver` that is "`automatically detected`" is dependent upon your runtime +environment. The following table summarizes various `LoadTimeWeaver` implementations: [[aop-aj-ltw-spring-env-impls]] .DefaultContextLoadTimeWeaver LoadTimeWeavers @@ -3418,22 +3596,24 @@ environment (summarized in the following table). | Running in IBM's http://www-01.ibm.com/software/webservers/appserv/was/[WebSphere] | `WebSphereLoadTimeWeaver` -| JVM started with Spring `InstrumentationSavingAgent` __(java - -javaagent:path/to/spring-instrument.jar)__ +| JVM started with Spring `InstrumentationSavingAgent` (`java + -javaagent:path/to/spring-instrument.jar`) | `InstrumentationLoadTimeWeaver` -| Fallback, expecting the underlying ClassLoader to follow common conventions (e.g. +| Fallback, expecting the underlying ClassLoader to follow common conventions (for example applicable to `TomcatInstrumentableClassLoader` and http://www.caucho.com/[Resin]) | `ReflectiveLoadTimeWeaver` |=== -Note that these are just the `LoadTimeWeavers` that are autodetected when using the -`DefaultContextLoadTimeWeaver`: it is of course possible to specify exactly which -`LoadTimeWeaver` implementation that you wish to use. +Note that the table lists only the `LoadTimeWeavers` that are autodetected when you use the +`DefaultContextLoadTimeWeaver`. You can specify exactly which +`LoadTimeWeaver` implementation to use. -To specify a specific `LoadTimeWeaver` with Java configuration implement the -`LoadTimeWeavingConfigurer` interface and override the `getLoadTimeWeaver()` method: +To specify a specific `LoadTimeWeaver` with Java configuration, implement the +`LoadTimeWeavingConfigurer` interface and override the `getLoadTimeWeaver()` method. The +following example specifies a `ReflectiveLoadTimeWeaver`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -3447,11 +3627,13 @@ To specify a specific `LoadTimeWeaver` with Java configuration implement the } } ---- +==== -If you are using XML based configuration you can specify the fully-qualified classname +If you use XML-based configuration, you can specify the fully qualified classname as the value of the `weaver-class` attribute on the `` -element: +element. Again, the following example specifies a `ReflectiveLoadTimeWeaver`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3470,21 +3652,23 @@ element: ---- +==== The `LoadTimeWeaver` that is defined and registered by the configuration can be later -retrieved from the Spring container using the well-known name `loadTimeWeaver`. -Remember that the `LoadTimeWeaver` exists just as a mechanism for Spring's LTW +retrieved from the Spring container by using the well known name, `loadTimeWeaver`. +Remember that the `LoadTimeWeaver` exists only as a mechanism for Spring's LTW infrastructure to add one or more `ClassFileTransformers`. The actual `ClassFileTransformer` that does the LTW is the `ClassPreProcessorAgentAdapter` (from -the `org.aspectj.weaver.loadtime` package) class. See the class-level javadocs of the +the `org.aspectj.weaver.loadtime` package) class. See the class-level Javadoc of the `ClassPreProcessorAgentAdapter` class for further details, because the specifics of how -the weaving is actually effected is beyond the scope of this section. +the weaving is actually effected is beyond the scope of this document. There is one final attribute of the configuration left to discuss: the -`aspectjWeaving` attribute (or `aspectj-weaving` if you are using XML). This is a -simple attribute that controls whether LTW is enabled or not; it is as simple as that. -It accepts one of three possible values, summarized below, with the default value being -`autodetect` if the attribute is not present. +`aspectjWeaving` attribute (or `aspectj-weaving` if you use XML). This +attribute controls whether LTW is enabled or not. +It accepts one of three possible values, with the default value being +`autodetect` if the attribute is not present. The following table summarizes the three +possible values: [[aop-aj-ltw-ltw-tag-attrs]] .AspectJ weaving attribute values @@ -3493,49 +3677,47 @@ It accepts one of three possible values, summarized below, with the default valu | `ENABLED` | `on` -| AspectJ weaving is on, and aspects will be woven at load-time as appropriate. +| AspectJ weaving is on, and aspects are woven at load-time as appropriate. | `DISABLED` | `off` -| LTW is off... no aspect will be woven at load-time. +| LTW is off. No aspect is woven at load-time. | `AUTODETECT` | `autodetect` | If the Spring LTW infrastructure can find at least one `META-INF/aop.xml` file, - then AspectJ weaving is on, else it is off. This is the default value. + then AspectJ weaving is on. Otherwise, it is off. This is the default value. |=== [[aop-aj-ltw-environments]] -==== Environment-specific configuration +==== Environment-specific Configuration -This last section contains any additional settings and configuration that you will need -when using Spring's LTW support in environments such as application servers and web +This last section contains any additional settings and configuration that you need +when you use Spring's LTW support in environments such as application servers and web containers. [[aop-aj-ltw-environment-tomcat]] ===== Tomcat Historically, http://tomcat.apache.org/[Apache Tomcat]'s default class loader did not -support class transformation which is why Spring provides an enhanced implementation +support class transformation, which is why Spring provides an enhanced implementation that addresses this need. Named `TomcatInstrumentableClassLoader`, the loader works on Tomcat 6.0 and above. -[TIP] -==== -Do not define `TomcatInstrumentableClassLoader` anymore on Tomcat 8.0 and higher. +TIP: Do not define `TomcatInstrumentableClassLoader` on Tomcat 8.0 and higher. Instead, let Spring automatically use Tomcat's new native `InstrumentableClassLoader` facility through the `TomcatLoadTimeWeaver` strategy. + +If you still need to use `TomcatInstrumentableClassLoader`, you can register it +individually for each web application as follows: + +. Copy `org.springframework.instrument.tomcat.jar` into `$CATALINA_HOME/lib`, where + `$CATALINA_HOME` represents the root of the Tomcat installation +. Instruct Tomcat to use the custom class loader (instead of the default) by editing the + web application context file, as the following example shows: + ==== - -If you still need to use `TomcatInstrumentableClassLoader`, it can be registered -individually for __each__ web application as follows: - -* Copy `org.springframework.instrument.tomcat.jar` into __$CATALINA_HOME__/lib, where - __$CATALINA_HOME__ represents the root of the Tomcat installation) -* Instruct Tomcat to use the custom class loader (instead of the default) by editing the - web application context file: - [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3544,52 +3726,57 @@ individually for __each__ web application as follows: loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> ---- +==== -Apache Tomcat (6.0+) supports several context locations: +Apache Tomcat 6.0+ supports several context locations: -* server configuration file - __$CATALINA_HOME/conf/server.xml__ -* default context configuration - __$CATALINA_HOME/conf/context.xml__ - that affects all +* Server configuration file: `$CATALINA_HOME/conf/server.xml` +* Default context configuration: `$CATALINA_HOME/conf/context.xml`, which affects all deployed web applications -* per-web application configuration which can be deployed either on the server-side at - __$CATALINA_HOME/conf/[enginename]/[hostname]/[webapp]-context.xml__ or embedded - inside the web-app archive at __META-INF/context.xml__ +* A per-web application configuration, which can be deployed either on the server-side at + `$CATALINA_HOME/conf/[enginename]/[hostname]/[webapp]-context.xml` or embedded + inside the web-app archive at `META-INF/context.xml` -For efficiency, the embedded per-web-app configuration style is recommended because it -will impact only applications that use the custom class loader and does not require any +For efficiency, we recommend the embedded per-web application configuration style, because it +impacts only applications that use the custom class loader and does not require any changes to the server configuration. See the Tomcat 6.0.x http://tomcat.apache.org/tomcat-6.0-doc/config/context.html[documentation] for more details about available context locations. -Alternatively, consider the use of the Spring-provided generic VM agent, to be specified -in Tomcat's launch script (see above). This will make instrumentation available to all -deployed web applications, no matter what ClassLoader they happen to run on. +Alternatively, consider using the Spring-provided generic VM agent, to be specified +in Tomcat's launch script (described earlier in this section). This makes instrumentation available to all +deployed web applications, no matter the `ClassLoader` on which they happen to run. [[aop-aj-ltw-environments-weblogic-oc4j-resin-glassfish-jboss]] -===== WebLogic, WebSphere, Resin, GlassFish, JBoss +===== WebLogic, WebSphere, Resin, GlassFish, and JBoss Recent versions of WebLogic Server (version 10 and above), IBM WebSphere Application -Server (version 7 and above), Resin (3.1 and above) and JBoss (6.x or above) provide a -ClassLoader that is capable of local instrumentation. Spring's native LTW leverages such -ClassLoaders to enable AspectJ weaving. You can enable LTW by simply activating -load-time weaving as described earlier. Specifically, you do __not__ need to modify the +Server (version 7 and above), Resin (version 3.1 and above), and JBoss (version 6.x or above) provide a +`ClassLoader` that is capable of local instrumentation. Spring's native LTW leverages such +ClassLoader implementations to enable AspectJ weaving. You can enable LTW by activating +load-time weaving, as <>. Specifically, you do not need to modify the launch script to add `-javaagent:path/to/spring-instrument.jar`. -Note that GlassFish instrumentation-capable ClassLoader is available only in its EAR -environment. For GlassFish web applications, follow the Tomcat setup instructions as -outlined above. +Note that the GlassFish instrumentation-capable `ClassLoader` is available only in its EAR +environment. For GlassFish web applications, follow the Tomcat setup instructions +<>. -Note that on JBoss 6.x, the app server scanning needs to be disabled to prevent it from +Note that, on JBoss 6.x, you need to disable the app server scanning to prevent it from loading the classes before the application actually starts. A quick workaround is to add to your artifact a file named `WEB-INF/jboss-scanning.xml` with the following content: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== + + [[aop-aj-ltw-environment-generic]] -===== Generic Java applications +===== Generic Java Applications When class instrumentation is required in environments that do not support or are not supported by the existing `LoadTimeWeaver` implementations, a JDK agent can be the only @@ -3597,35 +3784,36 @@ solution. For such cases, Spring provides `InstrumentationLoadTimeWeaver`, which requires a Spring-specific (but very general) VM agent, `org.springframework.instrument-{version}.jar` (previously named `spring-agent.jar`). -To use it, you must start the virtual machine with the Spring agent, by supplying the +To use it, you must start the virtual machine with the Spring agent by supplying the following JVM options: +==== [literal] [subs="verbatim,quotes"] ---- -javaagent:/path/to/org.springframework.instrument-{version}.jar ---- +==== -Note that this requires modification of the VM launch script which may prevent you from +Note that this requires modification of the VM launch script, which may prevent you from using this in application server environments (depending on your operation policies). -Additionally, the JDK agent will instrument the __entire__ VM which can prove expensive. +Additionally, the JDK agent instruments the entire VM, which can be expensive. -For performance reasons, it is recommended to use this configuration only if your target +For performance reasons, we recommend that you use this configuration only if your target environment (such as http://www.eclipse.org/jetty/[Jetty]) does not have (or does not support) a dedicated LTW. - [[aop-resources]] == Further Resources More information on AspectJ can be found on the http://www.eclipse.org/aspectj[AspectJ website]. -The book __Eclipse AspectJ__ by Adrian Colyer et. al. (Addison-Wesley, 2005) provides a +_Eclipse AspectJ_ by Adrian Colyer et. al. (Addison-Wesley, 2005) provides a comprehensive introduction and reference for the AspectJ language. -The book __AspectJ in Action, Second Edition__ by Ramnivas Laddad (Manning, 2009) comes highly -recommended; the focus of the book is on AspectJ, but a lot of general AOP themes are +_AspectJ in Action_, Second Edition by Ramnivas Laddad (Manning, 2009) comes highly +recommended. The focus of the book is on AspectJ, but a lot of general AOP themes are explored (in some depth). diff --git a/src/docs/asciidoc/core/core-appendix.adoc b/src/docs/asciidoc/core/core-appendix.adoc index b0812a1826c..01dea17252d 100644 --- a/src/docs/asciidoc/core/core-appendix.adoc +++ b/src/docs/asciidoc/core/core-appendix.adoc @@ -5,22 +5,23 @@ - [[xsd-schemas]] == XML Schemas This part of the appendix lists XML schemas related to the core container. + [[xsd-schemas-util]] -=== The util schema +=== The `util` Schema -As the name implies, the `util` tags deal with common, __utility__ configuration -issues, such as configuring collections, referencing constants, and suchlike. +As the name implies, the `util` tags deal with common, utility configuration +issues, such as configuring collections, referencing constants, and so forth. To use the tags in the `util` schema, you need to have the following preamble at the top -of your Spring XML configuration file; the text in the snippet below references the -correct schema so that the tags in the `util` namespace are available to you. +of your Spring XML configuration file (the text in the snippet references the +correct schema so that the tags in the `util` namespace are available to you): +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -33,13 +34,16 @@ correct schema so that the tags in the `util` namespace are available to you. ---- +==== + [[xsd-schemas-util-constant]] -==== +==== Using `` -Before... +Consider the following bean definition: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -50,16 +54,18 @@ Before... ---- +==== -The above configuration uses a Spring `FactoryBean` implementation, the -`FieldRetrievingFactoryBean`, to set the value of the `isolation` property on a bean +The preceding configuration uses a Spring `FactoryBean` implementation (the +`FieldRetrievingFactoryBean`) to set the value of the `isolation` property on a bean to the value of the `java.sql.Connection.TRANSACTION_SERIALIZABLE` constant. This is -all well and good, but it is a tad verbose and (unnecessarily) exposes Spring's internal +all well and good, but it is verbose and (unnecessarily) exposes Spring's internal plumbing to the end user. -The following XML Schema-based version is more concise and clearly expresses the -developer's intent (__'inject this constant value'__), and it just reads better. +The following XML Schema-based version is more concise, clearly expresses the +developer's intent ("`inject this constant value`"), and it reads better: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -69,18 +75,23 @@ developer's intent (__'inject this constant value'__), and it just reads better. ---- +==== + + [[xsd-schemas-util-frfb]] -===== Setting a bean property or constructor arg from a field value -{api-spring-framework}/beans/factory/config/FieldRetrievingFactoryBean.html[`FieldRetrievingFactoryBean`] -is a `FactoryBean` which retrieves a `static` or non-static field value. It is typically -used for retrieving `public` `static` `final` constants, which may then be used to set a -property value or constructor arg for another bean. +===== Setting a Bean Property or Constructor Argument from a Field Value -Find below an example which shows how a `static` field is exposed, by using the +{api-spring-framework}/beans/factory/config/FieldRetrievingFactoryBean.html[`FieldRetrievingFactoryBean`] +is a `FactoryBean` that retrieves a `static` or non-static field value. It is typically +used for retrieving `public` `static` `final` constants, which may then be used to set a +property value or constructor argument for another bean. + +The following example shows how a `static` field is exposed, by using the {api-spring-framework}/beans/factory/config/FieldRetrievingFactoryBean.html#setStaticField(java.lang.String)[`staticField`] property: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -89,22 +100,26 @@ property: ---- +==== There is also a convenience usage form where the `static` field is specified as the bean -name: +name, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -This does mean that there is no longer any choice in what the bean id is (so any other -bean that refers to it will also have to use this longer name), but this form is very -concise to define, and very convenient to use as an inner bean since the id doesn't have -to be specified for the bean reference: +This does mean that there is no longer any choice in what the bean `id` is (so any other +bean that refers to it also has to use this longer name), but this form is very +concise to define and very convenient to use as an inner bean since the `id` does not have +to be specified for the bean reference, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -115,18 +130,20 @@ to be specified for the bean reference: ---- +==== -It is also possible to access a non-static (instance) field of another bean, as +You can also access a non-static (instance) field of another bean, as described in the API documentation for the {api-spring-framework}/beans/factory/config/FieldRetrievingFactoryBean.html[`FieldRetrievingFactoryBean`] class. -Injecting enum values into beans as either property or constructor arguments is very -easy to do in Spring, in that you don't actually have to __do__ anything or know +Injecting enumeration values into beans as either property or constructor arguments is +easy to do in Spring. You do not actually have to do anything or know anything about the Spring internals (or even about classes such as the -`FieldRetrievingFactoryBean`). Let's look at an example to see how easy injecting an -enum value is; consider this enum: +`FieldRetrievingFactoryBean`). The following example enumeration shows how easy injecting an +enum value is: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -138,9 +155,11 @@ enum value is; consider this enum: EXTENDED } ---- +==== -Now consider a setter of type `PersistenceContextType`: +Now consider the following setter of type `PersistenceContextType` and the corresponding bean definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -156,8 +175,6 @@ Now consider a setter of type `PersistenceContextType`: } ---- -and the corresponding bean definition: - [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -165,13 +182,16 @@ and the corresponding bean definition: ---- +==== + [[xsd-schemas-util-property-path]] -==== +==== Using `` -Before... +Consider the following example: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -185,16 +205,18 @@ Before... - + ---- +==== -The above configuration uses a Spring `FactoryBean` implementation, the -`PropertyPathFactoryBean`, to create a bean (of type `int`) called `testBean.age` that +The preceding configuration uses a Spring `FactoryBean` implementation (the +`PropertyPathFactoryBean`) to create a bean (of type `int`) called `testBean.age` that has a value equal to the `age` property of the `testBean` bean. -After... +Now consider the following example, which adds a `` element: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -208,23 +230,26 @@ After... - + ---- +==== -The value of the `path` attribute of the `` tag follows the form -`beanName.beanProperty`. +The value of the `path` attribute of the `` element follows the form of +`beanName.beanProperty`. In this case, it picks up the `age` property of the bean named +`testBean`. The value of that `age` property is `10`. [[xsd-schemas-util-property-path-dependency]] -===== Using to set a bean property or constructor-argument +===== Using `` to Set a Bean Property or Constructor Argument `PropertyPathFactoryBean` is a `FactoryBean` that evaluates a property path on a given -target object. The target object can be specified directly or via a bean name. This -value may then be used in another bean definition as a property value or constructor +target object. The target object can be specified directly or by a bean name. You can then use this +value in another bean definition as a property value or constructor argument. -Here's an example where a path is used against another bean, by name: +The following example shows a path being used against another bean, by name: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -238,20 +263,22 @@ Here's an example where a path is used against another bean, by name: - // will result in 11, which is the value of property 'spouse.age' of bean 'person' + // results in 11, which is the value of property 'spouse.age' of bean 'person' ---- +==== -In this example, a path is evaluated against an inner bean: +In the following example, a path is evaluated against an inner bean: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- - + @@ -262,21 +289,26 @@ In this example, a path is evaluated against an inner bean: ---- +==== There is also a shortcut form, where the bean name is the property path. +The following example shows the shortcut form: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- - + ---- +==== This form does mean that there is no choice in the name of the bean. Any reference to it -will also have to use the same id, which is the path. Of course, if used as an inner -bean, there is no need to refer to it at all: +also has to use the same `id`, which is the path. If used as an inner +bean, there is no need to refer to it at all, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -287,17 +319,19 @@ bean, there is no need to refer to it at all: ---- +==== -The result type may be specifically set in the actual definition. This is not necessary -for most use cases, but can be of use for some. Please see the Javadocs for more info on +You can specifically set the result type in the actual definition. This is not necessary +for most use cases, but it can sometimes be useful. See the Javadoc for more info on this feature. [[xsd-schemas-util-properties]] -==== +==== Using `` -Before... +Consider the following example: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -306,26 +340,31 @@ Before... ---- +==== -The above configuration uses a Spring `FactoryBean` implementation, the -`PropertiesFactoryBean`, to instantiate a `java.util.Properties` instance with values +The preceding configuration uses a Spring `FactoryBean` implementation (the +`PropertiesFactoryBean`) to instantiate a `java.util.Properties` instance with values loaded from the supplied <> location). -After... +The following example uses a `util:properties` element to make a more concise representation: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== + [[xsd-schemas-util-list]] -==== +==== Using `` -Before... +Consider the following example: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -341,13 +380,15 @@ Before... ---- +==== -The above configuration uses a Spring `FactoryBean` implementation, the -`ListFactoryBean`, to create a `java.util.List` instance initialized with values taken +The preceding configuration uses a Spring `FactoryBean` implementation (the +`ListFactoryBean`) to create a `java.util.List` instance and initialize it with values taken from the supplied `sourceList`. -After... +The following example uses a `` element to make a more concise representation: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -359,12 +400,14 @@ After... porfiry@gov.org ---- +==== -You can also explicitly control the exact type of `List` that will be instantiated and -populated via the use of the `list-class` attribute on the `` element. For +You can also explicitly control the exact type of `List` that is instantiated and +populated by using the `list-class` attribute on the `` element. For example, if we really need a `java.util.LinkedList` to be instantiated, we could use the following configuration: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -375,16 +418,18 @@ following configuration: d'Arcachon@nemesis.org ---- +==== + +If no `list-class` attribute is supplied, the container chooses a `List` implementation. -If no `list-class` attribute is supplied, a `List` implementation will be chosen by -the container. [[xsd-schemas-util-map]] -==== +==== Using `` -Before... +Consider the following example: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -400,13 +445,15 @@ Before... ---- +==== -The above configuration uses a Spring `FactoryBean` implementation, the -`MapFactoryBean`, to create a `java.util.Map` instance initialized with key-value pairs +The preceding configuration uses a Spring `FactoryBean` implementation (the +`MapFactoryBean`) to create a `java.util.Map` instance initialized with key-value pairs taken from the supplied `'sourceMap'`. -After... +The following example uses a `` element to make a more concise representation: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -418,12 +465,14 @@ After... ---- +==== -You can also explicitly control the exact type of `Map` that will be instantiated and -populated via the use of the `'map-class'` attribute on the `` element. For +You can also explicitly control the exact type of `Map` that is instantiated and +populated by using the `'map-class'` attribute on the `` element. For example, if we really need a `java.util.TreeMap` to be instantiated, we could use the following configuration: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -434,16 +483,18 @@ following configuration: ---- +==== + +If no `'map-class'` attribute is supplied, the container chooses a `Map` implementation. -If no `'map-class'` attribute is supplied, a `Map` implementation will be chosen by the -container. [[xsd-schemas-util-set]] -==== +==== Using `` -Before... +Consider the following example: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -459,13 +510,15 @@ Before... ---- +==== -The above configuration uses a Spring `FactoryBean` implementation, the -`SetFactoryBean`, to create a `java.util.Set` instance initialized with values taken -from the supplied `'sourceSet'`. +The preceding configuration uses a Spring `FactoryBean` implementation (the +`SetFactoryBean`) to create a `java.util.Set` instance initialized with values taken +from the supplied `sourceSet`. -After... +The following example uses a `` element to make a more concise representation: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -477,12 +530,14 @@ After... porfiry@gov.org ---- +==== -You can also explicitly control the exact type of `Set` that will be instantiated and -populated via the use of the `'set-class'` attribute on the `` element. For +You can also explicitly control the exact type of `Set` that is instantiated and +populated by using the `set-class` attribute on the `` element. For example, if we really need a `java.util.TreeSet` to be instantiated, we could use the following configuration: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -493,25 +548,26 @@ following configuration: porfiry@gov.org ---- +==== -If no `'set-class'` attribute is supplied, a `Set` implementation will be chosen by the -container. +If no `set-class` attribute is supplied, the container chooses a `Set` implementation. [[xsd-schemas-aop]] -=== The aop schema +=== The `aop` Schema -The `aop` tags deal with configuring all things AOP in Spring: this includes Spring's +The `aop` tags deal with configuring all things AOP in Spring, including Spring's own proxy-based AOP framework and Spring's integration with the AspectJ AOP framework. These tags are comprehensively covered in the chapter entitled <>. In the interest of completeness, to use the tags in the `aop` schema, you need to have -the following preamble at the top of your Spring XML configuration file; the text in the -following snippet references the correct schema so that the tags in the `aop` namespace -are available to you. +the following preamble at the top of your Spring XML configuration file (the text in the +snippet references the correct schema so that the tags in the `aop` namespace +are available to you): +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -524,18 +580,20 @@ are available to you. ---- +==== [[xsd-schemas-context]] -=== The context schema +=== The `context` Schema The `context` tags deal with `ApplicationContext` configuration that relates to plumbing -- that is, not usually beans that are important to an end-user but rather beans that do -a lot of grunt work in Spring, such as `BeanfactoryPostProcessors`. The following -snippet references the correct schema so that the tags in the `context` namespace are -available to you. +-- that is, not usually beans that are important to an end-user but rather beans that do +a lot of the "`grunt`" work in Spring, such as `BeanfactoryPostProcessors`. The following +snippet references the correct schema so that the elements in the `context` namespace are +available to you: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -548,59 +606,69 @@ available to you. ---- +==== + [[xsd-schemas-context-pphc]] -==== +==== Using `` -This element activates the replacement of `${...}` placeholders, resolved against the +This element activates the replacement of `${...}` placeholders, which are resolved against a specified properties file (as a <>). This element is -a convenience mechanism that sets up a<> for you; if you need more control over the -`PropertyPlaceholderConfigurer`, just define one yourself explicitly. +a convenience mechanism that sets up a <> for you. If you need more control over the +`PropertyPlaceholderConfigurer`, you can explicitly define one yourself. + [[xsd-schemas-context-ac]] -==== +==== Using `` -Activates the Spring infrastructure for various annotations to be detected in bean -classes: Spring's <> and -<>, as well as JSR 250's `@PostConstruct`, -`@PreDestroy` and `@Resource` (if available), and JPA's `@PersistenceContext` and -`@PersistenceUnit` (if available). Alternatively, you can choose to activate the -individual `BeanPostProcessors` for those annotations explicitly. +This element activates the Spring infrastructure to detect annotations in bean +classes: -[NOTE] -==== -This element does __not__ activate processing of Spring's -<> annotation. Use the +* Spring's <> and +<> +* JSR 250's `@PostConstruct`, +`@PreDestroy` and `@Resource` (if available) +* JPA's `@PersistenceContext` and +`@PersistenceUnit` (if available). + +Alternatively, you can choose to explicitly activate the +individual `BeanPostProcessors` for those annotations. + +NOTE: This element does not activate processing of Spring's +<> annotation. You can use the <`>> element for that purpose. -==== + [[xsd-schemas-context-component-scan]] -==== +==== Using `` This element is detailed in <>. + [[xsd-schemas-context-ltw]] -==== +==== Using `` This element is detailed in <>. + [[xsd-schemas-context-sc]] -==== +==== Using `` This element is detailed in <>. + [[xsd-schemas-context-mbe]] -==== +==== Using `` This element is detailed in <>. @@ -608,23 +676,24 @@ Configuring annotation based MBean export>>. [[xsd-schemas-beans]] -=== The beans schema +=== The Beans Schema -Last but not least we have the tags in the `beans` schema. These are the same tags that -have been in Spring since the very dawn of the framework. Examples of the various tags +Last but not least, we have the elements in the `beans` schema. These elements +have been in Spring since the very dawn of the framework. Examples of the various elements in the `beans` schema are not shown here because they are quite comprehensively covered in <> -(and indeed in that entire <>). +(and, indeed, in that entire <>). -Note that it is possible to add zero or more key / value pairs to `` XML definitions. +Note that you can add zero or more key-value pairs to `` XML definitions. What, if anything, is done with this extra metadata is totally up to your own custom -logic (and so is typically only of use if you are writing your own custom tags as described +logic (and so is typically only of use if you write your own custom elements as described in the appendix entitled <>). -Find below an example of the `` tag in the context of a surrounding `` -(please note that without any logic to interpret it the metadata is effectively useless -as-is). +The following example shows the `` element in the context of a surrounding `` +(note that, without any logic to interpret it, the metadata is effectively useless +as it stands). +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -635,50 +704,49 @@ as-is). http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - ____ + <1> ---- +<1> This is the example `meta` element +==== -In the case of the above example, you would assume that there is some logic that will -consume the bean definition and set up some caching infrastructure using the supplied +In the case of the preceding example, you could assume that there is some logic that +consumes the bean definition and sets up some caching infrastructure that uses the supplied metadata. + [[xml-custom]] == XML Schema Authoring - [[xsd-custom-introduction]] -=== Introduction -Since version 2.0, Spring has featured a mechanism for schema-based extensions to the -basic Spring XML format for defining and configuring beans. This section is devoted to -detailing how you would go about writing your own custom XML bean definition parsers and -integrating such parsers into the Spring IoC container. +Since version 2.0, Spring has featured a mechanism for adding schema-based extensions to the +basic Spring XML format for defining and configuring beans. This section covers +how to write your own custom XML bean definition parsers and +integrate such parsers into the Spring IoC container. -To facilitate the authoring of configuration files using a schema-aware XML editor, +To facilitate authoring configuration files that use a schema-aware XML editor, Spring's extensible XML configuration mechanism is based on XML Schema. If you are not familiar with Spring's current XML configuration extensions that come with the standard -Spring distribution, please first read the appendix entitled<>. +Spring distribution, you should first read the appendix entitled <>. -Creating new XML configuration extensions can be done by following these (relatively) -simple steps: +To create new XML configuration extensions: -* <> an XML schema to describe your custom element(s). -* <> a custom `NamespaceHandler` implementation - (this is an easy step, don't worry). -* <> one or more `BeanDefinitionParser` implementations +. <> an XML schema to describe your custom element(s). +. <> a custom `NamespaceHandler` implementation. +. <> one or more `BeanDefinitionParser` implementations (this is where the real work is done). -* <> the above artifacts with Spring (this too - is an easy step). +. <> your new artifacts with Spring. -What follows is a description of each of these steps. For the example, we will create an -XML extension (a custom XML element) that allows us to configure objects of the type -`SimpleDateFormat` (from the `java.text` package) in an easy manner. When we are done, -we will be able to define bean definitions of type `SimpleDateFormat` like this: +For a unified example, we create an +XML extension (a custom XML element) that lets us configure objects of the type +`SimpleDateFormat` (from the `java.text` package). When we are done, +we will be able to define bean definitions of type `SimpleDateFormat` as follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -686,20 +754,22 @@ we will be able to define bean definitions of type `SimpleDateFormat` like this: pattern="yyyy-MM-dd HH:mm" lenient="true"/> ---- +==== -__(Don't worry about the fact that this example is very simple; much more detailed -examples follow afterwards. The intent in this first simple example is to walk you -through the basic steps involved.)__ - +(We include much more detailed +examples follow later in this appendix. The intent of this first simple example is to walk you +through the basic steps of making a custom extension.) [[xsd-custom-schema]] -=== Authoring the schema -Creating an XML configuration extension for use with Spring's IoC container starts with -authoring an XML Schema to describe the extension. What follows is the schema we'll use -to configure `SimpleDateFormat` objects. +=== Authoring the Schema +Creating an XML configuration extension for use with Spring's IoC container starts with +authoring an XML Schema to describe the extension. For our example, we use the following schema +to configure `SimpleDateFormat` objects: + +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -718,7 +788,7 @@ to configure `SimpleDateFormat` objects. - + <1> @@ -727,15 +797,18 @@ to configure `SimpleDateFormat` objects. ---- +<1> The indicated line contains an extension base for all identifiable tags +(meaning they have an `id` attribute that we can use as the bean identifier in the +container). We can use this attribute because we imported the Spring-provided +`beans` namespace. +==== -(The emphasized line contains an extension base for all tags that will be identifiable -(meaning they have an `id` attribute that will be used as the bean identifier in the -container). We are able to use this attribute because we imported the Spring-provided -`'beans'` namespace.) -The above schema will be used to configure `SimpleDateFormat` objects, directly in an -XML application context file using the `` element. +The preceding schema lets us configure `SimpleDateFormat` objects directly in an +XML application context file by using the `` element, as the following +example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -743,12 +816,12 @@ XML application context file using the `` element. pattern="yyyy-MM-dd HH:mm" lenient="true"/> ---- +==== -Note that after we've created the infrastructure classes, the above snippet of XML will -essentially be exactly the same as the following XML snippet. In other words, we're just -creating a bean in the container, identified by the name `'dateFormat'` of type -`SimpleDateFormat`, with a couple of properties set. +Note that, after we have created the infrastructure classes, the preceding snippet of XML is +essentially the same as the following XML snippet: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -757,48 +830,50 @@ creating a bean in the container, identified by the name `'dateFormat'` of type ---- - -[NOTE] ==== -The schema-based approach to creating configuration format allows for tight integration -with an IDE that has a schema-aware XML editor. Using a properly authored schema, you -can use autocompletion to have a user choose between several configuration options + +The second of the two preceding snippets +creates a bean in the container (identified by the name `dateFormat` of type +`SimpleDateFormat`) with a couple of properties set. + +NOTE: The schema-based approach to creating configuration format allows for tight integration +with an IDE that has a schema-aware XML editor. By using a properly authored schema, you +can use autocompletion to let a user choose between several configuration options defined in the enumeration. -==== - [[xsd-custom-namespacehandler]] -=== Coding a NamespaceHandler +=== Coding a `NamespaceHandler` -In addition to the schema, we need a `NamespaceHandler` that will parse all elements of -this specific namespace Spring encounters while parsing configuration files. The -`NamespaceHandler` should in our case take care of the parsing of the `myns:dateformat` +In addition to the schema, we need a `NamespaceHandler` to parse all elements of +this specific namespace that Spring encounters while parsing configuration files. For this example, the +`NamespaceHandler` should take care of the parsing of the `myns:dateformat` element. -The `NamespaceHandler` interface is pretty simple in that it features just three methods: +The `NamespaceHandler` interface features three methods: -* `init()` - allows for initialization of the `NamespaceHandler` and will be called by - Spring before the handler is used -* `BeanDefinition parse(Element, ParserContext)` - called when Spring encounters a +* `init()`: Allows for initialization of the `NamespaceHandler` and is called by + Spring before the handler is used. +* `BeanDefinition parse(Element, ParserContext)`: Called when Spring encounters a top-level element (not nested inside a bean definition or a different namespace). - This method can register bean definitions itself and/or return a bean definition. -* `BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext)` - called + This method can itself register bean definitions, return a bean definition, or both. +* `BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext)`: Called when Spring encounters an attribute or nested element of a different namespace. - The decoration of one or more bean definitions is used for example with the - <>. - We'll start by highlighting a simple example, without using decoration, after which - we will show decoration in a somewhat more advanced example. + The decoration of one or more bean definitions is used (for example) with the + <>. + We start by highlighting a simple example, without using decoration, after which + we show decoration in a somewhat more advanced example. -Although it is perfectly possible to code your own `NamespaceHandler` for the entire +Although you can code your own `NamespaceHandler` for the entire namespace (and hence provide code that parses each and every element in the namespace), it is often the case that each top-level XML element in a Spring XML configuration file results in a single bean definition (as in our case, where a single `` element results in a single `SimpleDateFormat` bean definition). Spring features a -number of convenience classes that support this scenario. In this example, we'll make +number of convenience classes that support this scenario. In the following example, we use the `NamespaceHandlerSupport` class: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -814,30 +889,31 @@ use the `NamespaceHandlerSupport` class: } ---- +==== -The observant reader will notice that there isn't actually a whole lot of parsing logic -in this class. Indeed... the `NamespaceHandlerSupport` class has a built in notion of +You may notice that there is not actually a whole lot of parsing logic +in this class. Indeed, the `NamespaceHandlerSupport` class has a built-in notion of delegation. It supports the registration of any number of `BeanDefinitionParser` -instances, to which it will delegate to when it needs to parse an element in its -namespace. This clean separation of concerns allows a `NamespaceHandler` to handle the -orchestration of the parsing of __all__ of the custom elements in its namespace, while -delegating to `BeanDefinitionParsers` to do the grunt work of the XML parsing; this -means that each `BeanDefinitionParser` will contain just the logic for parsing a single -custom element, as we can see in the next step - +instances, to which it delegates to when it needs to parse an element in its +namespace. This clean separation of concerns lets a `NamespaceHandler` handle the +orchestration of the parsing of all of the custom elements in its namespace while +delegating to `BeanDefinitionParsers` to do the grunt work of the XML parsing. This +means that each `BeanDefinitionParser` contains only the logic for parsing a single +custom element, as we can see in the next step. [[xsd-custom-parser]] -=== BeanDefinitionParser +=== Using `BeanDefinitionParser` -A `BeanDefinitionParser` will be used if the `NamespaceHandler` encounters an XML -element of the type that has been mapped to the specific bean definition parser (which -is `'dateformat'` in this case). In other words, the `BeanDefinitionParser` is -responsible for parsing __one__ distinct top-level XML element defined in the schema. In -the parser, we'll have access to the XML element (and thus its subelements too) so that -we can parse our custom XML content, as can be seen in the following example: +A `BeanDefinitionParser` is used if the `NamespaceHandler` encounters an XML +element of the type that has been mapped to the specific bean definition parser +(`dateformat` in this case). In other words, the `BeanDefinitionParser` is +responsible for parsing one distinct top-level XML element defined in the schema. In +the parser, we' have access to the XML element (and thus to its subelements, too) so that +we can parse our custom XML content, as you can see in the following example: +==== [source,java,indent=0] ---- package org.springframework.samples.xml; @@ -871,10 +947,11 @@ we can parse our custom XML content, as can be seen in the following example: ---- <1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of -the basic grunt work of creating a __single__ `BeanDefinition`. +the basic grunt work of creating a single `BeanDefinition`. <2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our -single `BeanDefinition` will represent. +single `BeanDefinition` represents. +==== In this simple case, this is all that we need to do. The creation of our single `BeanDefinition` is handled by the `AbstractSingleBeanDefinitionParser` superclass, as @@ -882,70 +959,77 @@ is the extraction and setting of the bean definition's unique identifier. - [[xsd-custom-registration]] -=== Registering the handler and the schema -The coding is finished! All that remains to be done is to somehow make the Spring XML -parsing infrastructure aware of our custom element; we do this by registering our custom -`namespaceHandler` and custom XSD file in two special purpose properties files. These -properties files are both placed in a `'META-INF'` directory in your application, and +=== Registering the Handler and the Schema +The coding is finished. All that remains to be done is to make the Spring XML +parsing infrastructure aware of our custom element. We do so by registering our custom +`namespaceHandler` and custom XSD file in two special-purpose properties files. These +properties files are both placed in a `META-INF` directory in your application and can, for example, be distributed alongside your binary classes in a JAR file. The Spring -XML parsing infrastructure will automatically pick up your new extension by consuming -these special properties files, the formats of which are detailed below. +XML parsing infrastructure automatically picks up your new extension by consuming +these special properties files, the formats of which are detailed in the next two sections. [[xsd-custom-registration-spring-handlers]] -==== 'META-INF/spring.handlers' +==== Writing `META-INF/spring.handlers` -The properties file called `'spring.handlers'` contains a mapping of XML Schema URIs to -namespace handler classes. So for our example, we need to write the following: +The properties file called `spring.handlers` contains a mapping of XML Schema URIs to +namespace handler classes. For our example, we need to write the following: +==== [literal] [subs="verbatim,quotes"] ---- http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler ---- +==== -__(The `':'` character is a valid delimiter in the Java properties format, and so the -`':'` character in the URI needs to be escaped with a backslash.)__ +(The `:` character is a valid delimiter in the Java properties format, so +`:` character in the URI needs to be escaped with a backslash.) The first part (the key) of the key-value pair is the URI associated with your custom -namespace extension, and needs to __match exactly__ the value of the `'targetNamespace'` -attribute as specified in your custom XSD schema. +namespace extension and needs to exactly match exactly the value of the `targetNamespace` +attribute, as specified in your custom XSD schema. [[xsd-custom-registration-spring-schemas]] -==== 'META-INF/spring.schemas' +==== Writing 'META-INF/spring.schemas' -The properties file called `'spring.schemas'` contains a mapping of XML Schema locations -(referred to along with the schema declaration in XML files that use the schema as part -of the `'xsi:schemaLocation'` attribute) to __classpath__ resources. This file is needed +The properties file called `spring.schemas` contains a mapping of XML Schema locations +(referred to, along with the schema declaration, in XML files that use the schema as part +of the `xsi:schemaLocation` attribute) to classpath resources. This file is needed to prevent Spring from absolutely having to use a default `EntityResolver` that requires Internet access to retrieve the schema file. If you specify the mapping in this -properties file, Spring will search for the schema on the classpath (in this case -`'myns.xsd'` in the `'org.springframework.samples.xml'` package): +properties file, Spring searches for the schema (in this case, +`myns.xsd` in the `org.springframework.samples.xml` package) on the classpath. +The following snippet shows the line we need to add for our custom schema: +==== [literal] [subs="verbatim,quotes"] ---- http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd ---- +==== -The upshot of this is that you are encouraged to deploy your XSD file(s) right alongside +(Remember that the `:` character must be escaped.) + +You are encouraged to deploy your XSD file (or files) right alongside the `NamespaceHandler` and `BeanDefinitionParser` classes on the classpath. - [[xsd-custom-using]] -=== Using a custom extension in your Spring XML configuration -Using a custom extension that you yourself have implemented is no different from using -one of the 'custom' extensions that Spring provides straight out of the box. Find below -an example of using the custom `` element developed in the previous steps -in a Spring XML configuration file. +=== Using a Custom Extension in Your Spring XML Configuration +Using a custom extension that you yourself have implemented is no different from using +one of the "`custom`" extensions that Spring provides. The following +example uses the custom `` element developed in the previous steps +in a Spring XML configuration file: + +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -958,7 +1042,7 @@ in a Spring XML configuration file. http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd"> - + <1> @@ -969,21 +1053,25 @@ in a Spring XML configuration file. ---- - +<1> Our custom bean. +==== [[xsd-custom-meat]] -=== Meatier examples -Find below some much meatier examples of custom XML extensions. +=== More Detailed Examples + +This section presents some more detailed examples of custom XML extensions. [[xsd-custom-custom-nested]] -==== Nesting custom tags within custom tags -This example illustrates how you might go about writing the various artifacts required +==== Nesting Custom Elements within Custom Elements + +The example presented in this section shows how you to write the various artifacts required to satisfy a target of the following configuration: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1005,13 +1093,16 @@ to satisfy a target of the following configuration: ---- +==== -The above configuration actually nests custom extensions within each other. The class -that is actually configured by the above `` element is the `Component` -class (shown directly below). Notice how the `Component` class does __not__ expose a -setter method for the `'components'` property; this makes it hard (or rather impossible) -to configure a bean definition for the `Component` class using setter injection. +The preceding configuration nests custom extensions within each other. The class +that is actually configured by the `` element is the `Component` +class (shown in the next example). Notice how the `Component` class does not expose a +setter method for the `components` property. This makes it hard (or rather impossible) +to configure a bean definition for the `Component` class by using setter injection. +The following listing shows the `Component` class: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1044,9 +1135,12 @@ to configure a bean definition for the `Component` class using setter injection. } ---- +==== The typical solution to this issue is to create a custom `FactoryBean` that exposes a -setter property for the `'components'` property. +setter property for the `components` property. The following listing shows such a custom +`FactoryBean`: +==== [source,java,indent=0] [subs="verbatim,quotes"] @@ -1089,13 +1183,15 @@ setter property for the `'components'` property. } ---- +==== -This is all very well, and does work nicely, but exposes a lot of Spring plumbing to the +This works nicely, but it exposes a lot of Spring plumbing to the end user. What we are going to do is write a custom extension that hides away all of this Spring plumbing. If we stick to <>, we'll start off by creating the XSD schema to define the structure of our -custom tag. +previously>>, we start off by creating the XSD schema to define the structure of our +custom tag, as the following listing shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1119,9 +1215,11 @@ custom tag. ---- +==== -We'll then create a custom `NamespaceHandler`. +Again following <>, we then create a custom `NamespaceHandler`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1137,10 +1235,13 @@ We'll then create a custom `NamespaceHandler`. } ---- +==== -Next up is the custom `BeanDefinitionParser`. Remember that what we are creating is a -`BeanDefinition` describing a `ComponentFactoryBean`. +Next up is the custom `BeanDefinitionParser`. Remember that we are creating +`BeanDefinition` that describes a `ComponentFactoryBean`. The following listing shows our +custom `BeanDefinitionParser`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1191,9 +1292,12 @@ Next up is the custom `BeanDefinitionParser`. Remember that what we are creating } ---- +==== -Lastly, the various artifacts need to be registered with the Spring XML infrastructure. +Finally, the various artifacts need to be registered with the Spring XML infrastructure, +by modifying the `META-INF/spring.handlers` and `META-INF/spring.schemas` files, as follows: +==== [literal] [subs="verbatim,quotes"] ---- @@ -1207,22 +1311,26 @@ http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler # in 'META-INF/spring.schemas' http\://www.foo.com/schema/component/component.xsd=com/foo/component.xsd ---- +==== [[xsd-custom-custom-just-attributes]] -==== Custom attributes on 'normal' elements -Writing your own custom parser and the associated artifacts isn't hard, but sometimes it -is not the right thing to do. Consider the scenario where you need to add metadata to -already existing bean definitions. In this case you certainly don't want to have to go -off and write your own entire custom extension; rather you just want to add an +==== Custom Attributes on "`Normal`" Elements + +Writing your own custom parser and the associated artifacts is not hard. However, it is sometimes +not the right thing to do. Consider a scenario where you need to add metadata to +already existing bean definitions. In this case, you certainly do not want to have to +write your own entire custom extension. Rather, you merely want to add an additional attribute to the existing bean definition element. -By way of another example, let's say that the service class that you are defining a bean -definition for a service object that will (unknown to it) be accessing a clustered +By way of another example, suppose that you define a bean +definition for a service object that (unknown to it) accesses a clustered http://jcp.org/en/jsr/detail?id=107[JCache], and you want to ensure that the named -JCache instance is eagerly started within the surrounding cluster: +JCache instance is eagerly started within the surrounding cluster. The following +listing shows such a definition: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1231,13 +1339,15 @@ JCache instance is eagerly started within the surrounding cluster: ---- +==== -What we are going to do here is create another `BeanDefinition` when the -`'jcache:cache-name'` attribute is parsed; this `BeanDefinition` will then initialize -the named JCache for us. We will also modify the existing `BeanDefinition` for the -`'checkingAccountService'` so that it will have a dependency on this new -JCache-initializing `BeanDefinition`. +We can then create another `BeanDefinition` when the +`'jcache:cache-name'` attribute is parsed. This `BeanDefinition` then initializes +the named JCache for us. We can also modify the existing `BeanDefinition` for the +`'checkingAccountService'` so that it has a dependency on this new +JCache-initializing `BeanDefinition`. The following listing shows our `JCacheInitializer`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1257,10 +1367,12 @@ JCache-initializing `BeanDefinition`. } ---- +==== -Now onto the custom extension. Firstly, the authoring of the XSD schema describing the -custom attribute (quite easy in this case). +Now we can move onto the custom extension. First, we need to author the XSD schema that describes the +custom attribute, as follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1275,9 +1387,11 @@ custom attribute (quite easy in this case). ---- +==== -Next, the associated `NamespaceHandler`. +Next, we need to create the associated `NamespaceHandler`, as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1294,10 +1408,13 @@ Next, the associated `NamespaceHandler`. } ---- +==== -Next, the parser. Note that in this case, because we are going to be parsing an XML +Next, we need to create the parser. Note that, in this case, because we are going to parse an XML attribute, we write a `BeanDefinitionDecorator` rather than a `BeanDefinitionParser`. +The following listing shows our `BeanDefinitionDecorator`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1353,9 +1470,12 @@ attribute, we write a `BeanDefinitionDecorator` rather than a `BeanDefinitionPar } ---- +==== -Lastly, the various artifacts need to be registered with the Spring XML infrastructure. +Finally, we need to register the various artifacts with the Spring XML infrastructure +by modifying the `META-INF/spring.handlers` and `META-INF/spring.schemas` files, as follows: +==== [literal] [subs="verbatim,quotes"] ---- @@ -1369,3 +1489,4 @@ http\://www.foo.com/schema/jcache=com.foo.JCacheNamespaceHandler # in 'META-INF/spring.schemas' http\://www.foo.com/schema/jcache/jcache.xsd=com/foo/jcache.xsd ---- +==== diff --git a/src/docs/asciidoc/core/core-beans.adoc b/src/docs/asciidoc/core/core-beans.adoc index 934cd7a9b97..9c8f0650087 100644 --- a/src/docs/asciidoc/core/core-beans.adoc +++ b/src/docs/asciidoc/core/core-beans.adoc @@ -1,6 +1,7 @@ [[beans]] -= The IoC container += The IoC Container +This chapter covers Spring's Inversion of Control (IoC) container. @@ -143,7 +144,7 @@ The following example shows the basic structure of XML-based configuration metad xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - <1> <2> + <1> <2> @@ -2136,6 +2137,7 @@ modes: [[beans-factory-autowiring-modes-tbl]] .Autowiring modes +[cols="20%,80%"] |=== | Mode| Explanation @@ -2568,6 +2570,7 @@ The following table describes the supported scopes: [[beans-factory-scopes-tbl]] .Bean scopes +[cols="20%,80%"] |=== | Scope| Description @@ -2957,7 +2960,7 @@ understand the "`why`" as well as the "`how`" behind it: - <1> + <1> @@ -4565,7 +4568,7 @@ references and values even when you use the class outside of a container. [[beans-autowired-annotation]] -=== @Autowired +=== Using `@Autowired` NOTE: JSR 330's `@Inject` annotation can be used in place of Spring's `@Autowired` annotation in the examples included in this section. See <> for more details. @@ -5007,13 +5010,13 @@ The following example shows corresponding bean definitions. - <1> + <1> - <2> + <2> @@ -5201,7 +5204,7 @@ following example: public class MovieRecommender { @Autowired - @Offline <1> + @Offline <1> private MovieCatalog offlineCatalog; // ... @@ -5217,7 +5220,7 @@ Now the bean definition only needs a qualifier `type`, as shown in the following [subs="verbatim,quotes"] ---- - <1> + <1> ---- @@ -5459,7 +5462,7 @@ demonstrated in the following example: private MovieFinder movieFinder; - @Resource(name="myMovieFinder") <1> + @Resource(name="myMovieFinder") <1> public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } @@ -5516,7 +5519,7 @@ named customerPreferenceDao and then falls back to a primary type match for the private CustomerPreferenceDao customerPreferenceDao; @Resource - private ApplicationContext context; <1> + private ApplicationContext context; <1> public MovieRecommender() { } @@ -5630,7 +5633,7 @@ annotation. For example, the `@Service` annotation mentioned < + @Component <1> public @interface Service { // .... @@ -8181,7 +8184,7 @@ the following example shows: public class AppConfig { @Bean("dataSource") - @Profile("development") <1> + @Profile("development") <1> public DataSource standaloneDataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) @@ -8191,7 +8194,7 @@ the following example shows: } @Bean("dataSource") - **@Profile("production")** + @Profile("production") <2> public DataSource jndiDataSource() throws Exception { Context ctx = new InitialContext(); return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); @@ -8199,6 +8202,7 @@ the following example shows: } ---- <1> The `standaloneDataSource` method is available only in the `development` profile. +<2> The `jndiDataSource` method is available only in the `production` profile. ==== [NOTE] @@ -8895,6 +8899,7 @@ The following table describes the standard events that Spring provides: [[beans-ctx-events-tbl]] .Built-in Events +[cols="30%,70%"] |=== | Event| Explanation @@ -9460,6 +9465,7 @@ The following table lists features provided by the `BeanFactory` and [[context-introduction-ctx-vs-beanfactory-feature-matrix]] .Feature Matrix +[cols="50%,25%,25%"] |=== | Feature | `BeanFactory` | `ApplicationContext` diff --git a/src/docs/asciidoc/core/core-databuffer-codec.adoc b/src/docs/asciidoc/core/core-databuffer-codec.adoc index 1c965f24888..706c21abe87 100644 --- a/src/docs/asciidoc/core/core-databuffer-codec.adoc +++ b/src/docs/asciidoc/core/core-databuffer-codec.adoc @@ -1,69 +1,64 @@ [[databuffers]] = Data Buffers and Codecs - - - -== Introduction - The `DataBuffer` interface defines an abstraction over byte buffers. -The main reason for introducing it, and not use the standard `java.nio.ByteBuffer` instead, is Netty. -Netty does not use `ByteBuffer`, but instead offers `ByteBuf` as an alternative. +The main reason for introducing it (and not using the standard `java.nio.ByteBuffer` instead) is Netty. +Netty does not use `ByteBuffer` but instead offers `ByteBuf` as an alternative. Spring's `DataBuffer` is a simple abstraction over `ByteBuf` that can also be used on non-Netty -platforms (i.e. Servlet 3.1+). - +platforms (that is, Servlet 3.1+). == `DataBufferFactory` -The `DataBufferFactory` offers functionality to allocate new data buffers, as well as to wrap +The `DataBufferFactory` offers functionality to allocate new data buffers as well as to wrap existing data. -The `allocate` methods allocate a new data buffer, with a default or given capacity. -Though `DataBuffer` implementation grow and shrink on demand, it is more efficient to give the +The `allocateBuffer` methods allocate a new data buffer with a default or given capacity. +Though `DataBuffer` implementations grow and shrink on demand, it is more efficient to give the capacity upfront, if known. The `wrap` methods decorate an existing `ByteBuffer` or byte array. -Wrapping does not involve allocation: it simply decorates the given data with a `DataBuffer` +Wrapping does not involve allocation. It decorates the given data with a `DataBuffer` implementation. -There are two implementation of `DataBufferFactory`: the `NettyDataBufferFactory` which is meant -to be used on Netty platforms, such as Reactor Netty. -The other implementation, the `DefaultDataBufferFactory`, is used on other platforms, such as -Servlet 3.1+ servers. +There are two implementation of `DataBufferFactory`: the `NettyDataBufferFactory` +(for Netty platforms, such as Reactor Netty) and +`DefaultDataBufferFactory` (for other platforms, such as +Servlet 3.1+ servers). +== The `DataBuffer` Interface -== The `DataBuffer` interface - -The `DataBuffer` interface is similar to `ByteBuffer`, but offers a number of advantages. +The `DataBuffer` interface is similar to `ByteBuffer` but offers a number of advantages. Similar to Netty's `ByteBuf`, the `DataBuffer` abstraction offers independent read and write positions. -This is different from the JDK's `ByteBuffer`, which only exposes one position for both reading and -writing, and a separate `flip()` operation to switch between the two I/O operations. +This is different from the JDK's `ByteBuffer`, which exposes only one position for both reading and +writing and a separate `flip()` operation to switch between the two I/O operations. In general, the following invariant holds for the read position, write position, and the capacity: +==== [literal] [subs="verbatim,quotes"] -- 0 <= read position <= write position <= capacity -- +==== When reading bytes from the `DataBuffer`, the read position is automatically updated in accordance with the amount of data read from the buffer. Similarly, when writing bytes to the `DataBuffer`, the write position is updated with the amount of data written to the buffer. -Also, when writing data, the capacity of a `DataBuffer` is automatically expanded, just like `StringBuilder`, +Also, when writing data, the capacity of a `DataBuffer` is automatically expanded, in the same fashion as `StringBuilder`, `ArrayList`, and similar types. Besides the reading and writing functionality mentioned above, the `DataBuffer` also has methods to -view a (slice of a) buffer as `ByteBuffer`, `InputStream`, or `OutputStream`. +view a (slice of a) buffer as a `ByteBuffer`, an `InputStream`, or an `OutputStream`. Additionally, it offers methods to determine the index of a given byte. -There are two implementation of `DataBuffer`: the `NettyDataBuffer` which is meant to be used on -Netty platforms, such as Reactor Netty. -The other implementation, the `DefaultDataBuffer`, is used on other platforms, such as Servlet 3.1+ -servers. +As mentioned earlier, there are two implementation of `DataBufferFactory`: the `NettyDataBufferFactory` +(for Netty platforms, such as Reactor Netty) and +`DefaultDataBufferFactory` (for other platforms, such as +Servlet 3.1+ servers). @@ -71,41 +66,42 @@ servers. The `PooledDataBuffer` is an extension to `DataBuffer` that adds methods for reference counting. The `retain` method increases the reference count by one. -The `release` method decreases the count by one, and releases the buffer's memory when the count +The `release` method decreases the count by one and releases the buffer's memory when the count reaches 0. -Both of these methods are related to _reference counting_, a mechanism that is explained below. +Both of these methods are related to reference counting, a mechanism that we explain <>. Note that `DataBufferUtils` offers useful utility methods for releasing and retaining pooled data buffers. -These methods take a plain `DataBuffer` as parameter, but only call `retain` or `release` if the +These methods take a plain `DataBuffer` as a parameter but only call `retain` or `release` if the passed data buffer is an instance of `PooledDataBuffer`. [[databuffer-reference-counting]] ==== Reference Counting -Reference counting is not a common technique in Java; it is much more common in other programming -languages such as Object C and C++. -In and of itself, reference counting is not complex: it basically involves tracking the number of +Reference counting is not a common technique in Java. It is much more common in other programming +languages, such as Object C and C++. +In and of itself, reference counting is not complex. It basically involves tracking the number of references that apply to an object. The reference count of a `PooledDataBuffer` starts at 1, is incremented by calling `retain`, -and decremented by calling `release`. -As long as the buffer's reference count is larger than 0 the buffer will not be released. -When the number decreases to 0, the instance will be released. -In practice, this means that the reserved memory captured by the buffer will be returned back to +and is decremented by calling `release`. +As long as the buffer's reference count is larger than 0, the buffer is not released. +When the number decreases to 0, the instance is released. +In practice, this means that the reserved memory captured by the buffer is returned back to the memory pool, ready to be used for future allocations. -In general, _the last component to access a `DataBuffer` is responsible for releasing it_. +In general, the last component to access a `DataBuffer` is responsible for releasing it. Within Spring, there are two sorts of components that release buffers: decoders and transports. -Decoders are responsible for transforming a stream of buffers into other types (see <> below), - and transports are responsible for sending buffers across a network boundary, typically as an HTTP message. -This means that if you allocate data buffers for the purpose of putting them into an outbound HTTP -message (i.e. client-side request or server-side response), they do not have to be released. +Decoders are responsible for transforming a stream of buffers into other types (see <>), +and transports are responsible for sending buffers across a network boundary, typically as an HTTP message. +This means that, if you allocate data buffers for the purpose of putting them into an outbound HTTP +message (that is, a client-side request or server-side response), they do not have to be released. The other consequence of this rule is that if you allocate data buffers that do not end up in the -body, for instance because of a thrown exception, you will have to release them yourself. +body (for instance, because of a thrown exception), you have to release them yourself. The following snippet shows a typical `DataBuffer` usage scenario when dealing with methods that throw exceptions: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -130,46 +126,49 @@ throw exceptions: <1> A new buffer is allocated. <2> A boolean flag indicates whether the allocated buffer should be released. -<3> This example method loads data into the buffer. Note that the method can throw an `IOException`, -and therefore a `finally` block to release the buffer is required. -<4> If no exception occurred, we switch the `release` flag to `false` as the buffer will now be +<3> This example method loads data into the buffer. Note that the method can throw an `IOException`. +Therefore, a `finally` block to release the buffer is required. +<4> If no exception occurred, we switch the `release` flag to `false` as the buffer is now released as part of sending the HTTP body across the wire. -<5> If an exception did occur, the flag is still set to `true`, and the buffer will be released +<5> If an exception did occur, the flag is still set to `true`, and the buffer is released here. +==== -=== DataBufferUtils +=== `DataBufferUtils` -`DataBufferUtils` contains various utility methods that operate on data buffers. +The `DataBufferUtils` class contains various utility methods that operate on data buffers. It contains methods for reading a `Flux` of `DataBuffer` objects from an `InputStream` or NIO -`Channel`, and methods for writing a data buffer `Flux` to an `OutputStream` or `Channel`. +`Channel` and methods for writing a data buffer `Flux` to an `OutputStream` or `Channel`. `DataBufferUtils` also exposes `retain` and `release` methods that operate on plain `DataBuffer` instances (so that casting to a `PooledDataBuffer` is not required). Additionally, `DataBufferUtils` exposes `compose`, which merges a stream of data buffers into one. For instance, this method can be used to convert the entire HTTP body into a single buffer (and -from that, a `String`, or `InputStream`). +from that, a `String` or `InputStream`). This is particularly useful when dealing with older, blocking APIs. Note, however, that this puts the entire body in memory, and therefore uses more memory than a pure streaming solution would. -[codecs] + + +[[codecs]] == Codecs The `org.springframework.core.codec` package contains the two main abstractions for converting a -stream of bytes into a stream of objects, or vice-versa. +stream of bytes into a stream of objects or vice-versa. The `Encoder` is a strategy interface that encodes a stream of objects into an output stream of data buffers. -The `Decoder` does the reverse: it turns a stream of data buffers into a stream of objects. -Note that a decoder instance needs to consider <>. +The `Decoder` does the reverse: It turns a stream of data buffers into a stream of objects. +Note that a decoder instance needs to consider <>. -Spring comes with a wide array of default codecs, capable of converting from/to `String`, -`ByteBuffer`, byte arrays, and also codecs that support marshalling libraries such as JAXB and +Spring comes with a wide array of default codecs (to convert from and to `String`, +`ByteBuffer`, and byte arrays) and codecs that support marshalling libraries such as JAXB and Jackson (with https://github.com/FasterXML/jackson-core/issues/57[Jackson 2.9+ support for non-blocking parsing]). Within the context of Spring WebFlux, codecs are used to convert the request body into a -`@RequestMapping` parameter, or to convert the return type into the response body that is sent back +`@RequestMapping` parameter or to convert the return type into the response body that is sent back to the client. -The default codecs are configured in the `WebFluxConfigurationSupport` class, and can easily be -changed by overriding the `configureHttpMessageCodecs` when inheriting from that class. -For more information about using codecs in WebFlux, see <>. +The default codecs are configured in the `WebFluxConfigurationSupport` class. You can +change them by overriding the `configureHttpMessageCodecs` when you inherit from that class. +For more information about using codecs in WebFlux, see <>. diff --git a/src/docs/asciidoc/core/core-expressions.adoc b/src/docs/asciidoc/core/core-expressions.adoc index 45634324536..c4b0d609b95 100644 --- a/src/docs/asciidoc/core/core-expressions.adoc +++ b/src/docs/asciidoc/core/core-expressions.adoc @@ -1,13 +1,7 @@ [[expressions]] = Spring Expression Language (SpEL) - - - -[[expressions-intro]] -== Introduction - -The Spring Expression Language (_SpEL_ for short) is a powerful expression language that +The Spring Expression Language ("`SpEL`" for short) is a powerful expression language that supports querying and manipulating an object graph at runtime. The language syntax is similar to Unified EL but offers additional features, most notably method invocation and basic string templating functionality. @@ -17,22 +11,22 @@ EL, to name a few -- the Spring Expression Language was created to provide the S community with a single well supported expression language that can be used across all the products in the Spring portfolio. Its language features are driven by the requirements of the projects in the Spring portfolio, including tooling requirements for -code completion support within the Eclipse based Spring Tool Suite. That said, -SpEL is based on a technology agnostic API allowing other expression language -implementations to be integrated should the need arise. +code completion support within the Eclipse-based Spring Tool Suite. That said, +SpEL is based on a technology-agnostic API that lets other expression language +implementations be integrated, should the need arise. While SpEL serves as the foundation for expression evaluation within the Spring -portfolio, it is not directly tied to Spring and can be used independently. In order to +portfolio, it is not directly tied to Spring and can be used independently. To be self contained, many of the examples in this chapter use SpEL as if it were an independent expression language. This requires creating a few bootstrapping -infrastructure classes such as the parser. Most Spring users will not need to deal with -this infrastructure and will instead only author expression strings for evaluation. An -example of this typical use is the integration of SpEL into creating XML or annotated -based bean definitions as shown in the section <>. This chapter covers the features of the expression language, its API, and its language -syntax. In several places an `Inventor` and Inventor's `Society` classes are used as the +syntax. In several places, `Inventor` and `Society` classes are used as the target objects for expression evaluation. These class declarations and the data used to populate them are listed at the end of the chapter. @@ -42,7 +36,7 @@ The expression language supports the following functionality: * Boolean and relational operators * Regular expressions * Class expressions -* Accessing properties, arrays, lists, maps +* Accessing properties, arrays, lists, and maps * Method invocation * Relational operators * Assignment @@ -53,107 +47,117 @@ The expression language supports the following functionality: * Inline maps * Ternary operator * Variables -* User defined functions +* User-defined functions * Collection projection * Collection selection * Templated expressions - [[expressions-evaluation]] == Evaluation This section introduces the simple use of SpEL interfaces and its expression language. -The complete language reference can be found in the section +The complete language reference can be found in <>. -The following code introduces the SpEL API to evaluate the literal string expression -'Hello World'. +The following code introduces the SpEL API to evaluate the literal string expression, +`Hello World`. +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- ExpressionParser parser = new SpelExpressionParser(); - Expression exp = parser.parseExpression("**'Hello World'**"); + Expression exp = parser.parseExpression("'Hello World'"); <1> String message = (String) exp.getValue(); ---- +<1> The value of the message variable is `'Hello World'`. +==== -The value of the message variable is simply 'Hello World'. +The SpEL classes and interfaces you are most likely to use are located in the +`org.springframework.expression` package and its sub-packages, such as `spel.support`. -The SpEL classes and interfaces you are most likely to use are located in the packages -`org.springframework.expression` and its sub packages such as `spel.support`. - -The interface `ExpressionParser` is responsible for parsing an expression string. In -this example the expression string is a string literal denoted by the surrounding single -quotes. The interface `Expression` is responsible for evaluating the previously defined -expression string. There are two exceptions that can be thrown, `ParseException` and -`EvaluationException` when calling `parser.parseExpression` and `exp.getValue` +The `ExpressionParser` interface is responsible for parsing an expression string. In +the preceding example, the expression string is a string literal denoted by the surrounding single +quotation marks. The `Expression` interface is responsible for evaluating the previously defined +expression string. Two exceptions that can be thrown, `ParseException` and +`EvaluationException`, when calling `parser.parseExpression` and `exp.getValue`, respectively. SpEL supports a wide range of features, such as calling methods, accessing properties, and calling constructors. -As an example of method invocation, we call the `concat` method on the string literal. +In the following example of method invocation, we call the `concat` method on the string literal: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- ExpressionParser parser = new SpelExpressionParser(); - Expression exp = parser.parseExpression("**'Hello World'.concat('!')**"); + Expression exp = parser.parseExpression("'Hello World'.concat('!')"); <1> String message = (String) exp.getValue(); ---- +<1> The value of `message` is now 'Hello World!'. +==== -The value of message is now 'Hello World!'. - -As an example of calling a JavaBean property, the String property `Bytes` can be called -as shown below. +The following example of calling a JavaBean property calls the `String` property `Bytes`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- ExpressionParser parser = new SpelExpressionParser(); // invokes 'getBytes()' - Expression exp = parser.parseExpression("**'Hello World'.bytes**"); + Expression exp = parser.parseExpression("'Hello World'.bytes"); <1> byte[] bytes = (byte[]) exp.getValue(); ---- +<1> This line converts the literal to a byte array. +==== -SpEL also supports nested properties using standard _dot_ notation, i.e. -`prop1.prop2.prop3` and the setting of property values - -Public fields may also be accessed. +SpEL also supports nested properties by using standard dot notation (such as +`prop1.prop2.prop3`) and the setting of property values. Public fields may also be accessed. +The following example shows how to use dot notation to get the length of a literal: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- ExpressionParser parser = new SpelExpressionParser(); // invokes 'getBytes().length' - Expression exp = parser.parseExpression("**'Hello World'.bytes.length**"); + Expression exp = parser.parseExpression("'Hello World'.bytes.length"); <1> int length = (Integer) exp.getValue(); ---- +<1> `'Hello World'.bytes.length` gives the length of the literal. +==== -The String's constructor can be called instead of using a string literal. +The String's constructor can be called instead of using a string literal, as the following +example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- ExpressionParser parser = new SpelExpressionParser(); - Expression exp = parser.parseExpression("**new String('hello world').toUpperCase()**"); + Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); <1> String message = exp.getValue(String.class); ---- +<1> Construct a new `String` from the literal and make it be upper case. +==== -Note the use of the generic method `public T getValue(Class desiredResultType)`. +Note the use of the generic method: `public T getValue(Class desiredResultType)`. Using this method removes the need to cast the value of the expression to the desired -result type. An `EvaluationException` will be thrown if the value cannot be cast to the -type `T` or converted using the registered type converter. +result type. An `EvaluationException` is thrown if the value cannot be cast to the +type `T` or converted by using the registered type converter. The more common usage of SpEL is to provide an expression string that is evaluated -against a specific object instance (called the root object). The example shows +against a specific object instance (called the root object). The following example shows how to retrieve the `name` property from an instance of the `Inventor` class or create a boolean condition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -166,7 +170,7 @@ create a boolean condition: ExpressionParser parser = new SpelExpressionParser(); - Expression exp = parser.parseExpression("**name**"); + Expression exp = parser.parseExpression("name"); <1> String name = (String) exp.getValue(tesla); // name == "Nikola Tesla" @@ -174,53 +178,56 @@ create a boolean condition: boolean result = exp.getValue(tesla, Boolean.class); // result == true ---- +<1> Parse `name` as an expression. +==== [[expressions-evaluation-context]] -=== `EvaluationContext` +=== Understanding `EvaluationContext` -The interface `EvaluationContext` is used when evaluating an expression to resolve -properties, methods, or fields and to help perform type conversion. There are two -out-of-the-box implementations. +The `EvaluationContext` interface is used when evaluating an expression to resolve +properties, methods, or fields and to help perform type conversion. Spring provides two +implementations. -* `SimpleEvaluationContext` -- exposes a subset of essential SpEL language features and +* `SimpleEvaluationContext`: Exposes a subset of essential SpEL language features and configuration options, for categories of expressions that do not require the full extent of the SpEL language syntax and should be meaningfully restricted. Examples include but -are not limited to data binding expressions, property-based filters, and others. +are not limited to data binding expressions and property-based filters. -* `StandardEvaluationContext` -- exposes the full set of SpEL language features and -configuration options. You may use it to specify a default root object and to configure +* `StandardEvaluationContext`: Exposes the full set of SpEL language features and +configuration options. You can use it to specify a default root object and to configure every available evaluation-related strategy. `SimpleEvaluationContext` is designed to support only a subset of the SpEL language syntax. -It _excludes_ Java type references, constructors, and bean references. It also requires -that one explicitly choose the level of support for properties and methods in expressions. +It excludes Java type references, constructors, and bean references. It also requires +you to explicitly choose the level of support for properties and methods in expressions. By default, the `create()` static factory method enables only read access to properties. You can also obtain a builder to configure the exact level of support needed, targeting one or some combination of the following: -. Custom `PropertyAccessor` only (no reflection) -. Data binding properties for read-only access -. Data binding properties for read and write +* Custom `PropertyAccessor` only (no reflection) +* Data binding properties for read-only access +* Data binding properties for read and write [[expressions-type-conversion]] -==== Type conversion +==== Type Conversion -By default SpEL uses the conversion service available in Spring core +By default, SpEL uses the conversion service available in Spring core (`org.springframework.core.convert.ConversionService`). This conversion service comes -with many converters built in for common conversions but is also fully extensible so -custom conversions between types can be added. Additionally it has the key capability -that it is generics aware. This means that when working with generic types in -expressions, SpEL will attempt conversions to maintain type correctness for any objects +with many built-in converters for common conversions but is also fully extensible so that +you can add custom conversions between types. Additionally, it is +generics-aware. This means that, when you work with generic types in +expressions, SpEL attempts conversions to maintain type correctness for any objects it encounters. What does this mean in practice? Suppose assignment, using `setValue()`, is being used to set a `List` property. The type of the property is actually `List`. SpEL -will recognize that the elements of the list need to be converted to `Boolean` before -being placed in it. A simple example: +recognizes that the elements of the list need to be converted to `Boolean` before +being placed in it. The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -233,35 +240,38 @@ being placed in it. A simple example: EvaluationContext context = SimpleEvaluationContext().forReadOnlyDataBinding().build(); - // false is passed in here as a string. SpEL and the conversion service will + // false is passed in here as a string. SpEL and the conversion service // correctly recognize that it needs to be a Boolean and convert it parser.parseExpression("booleanList[0]").setValue(context, simple, "false"); - // b will be false + // b is false Boolean b = simple.booleanList.get(0); ---- +==== [[expressions-parser-configuration]] -=== Parser configuration +=== Parser Configuration -It is possible to configure the SpEL expression parser using a parser configuration object +It is possible to configure the SpEL expression parser by using a parser configuration object (`org.springframework.expression.spel.SpelParserConfiguration`). The configuration -object controls the behavior of some of the expression components. For example, if -indexing into an array or collection and the element at the specified index is `null` -it is possible to automatically create the element. This is useful when using expressions made up of a -chain of property references. If indexing into an array or list +object controls the behavior of some of the expression components. For example, if you +index into an array or collection and the element at the specified index is `null`, +you can automatically create the element. This is useful when using expressions made up of a +chain of property references. If you index into an array or list and specifying an index that is beyond the end of the current size of the array or -list it is possible to automatically grow the array or list to accommodate that index. +list, you can automatically grow the array or list to accommodate that index. The following +example demonstrates how to automatically grow the list: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- class Demo { public List list; } - + // Turn on: // - auto null reference initialization // - auto collection growing @@ -278,74 +288,80 @@ list it is possible to automatically grow the array or list to accommodate that // demo.list will now be a real collection of 4 entries // Each entry is a new empty String ---- - -It is also possible to configure the behaviour of the SpEL expression compiler. +==== [[expressions-spel-compilation]] -=== SpEL compilation +=== SpEL Compilation Spring Framework 4.1 includes a basic expression compiler. Expressions are usually -interpreted which provides a lot of dynamic flexibility during evaluation but -does not provide optimum performance. For occasional expression usage -this is fine, but when used by other components like Spring Integration, -performance can be very important and there is no real need for the dynamism. +interpreted, which provides a lot of dynamic flexibility during evaluation but +does not provide optimum performance. For occasional expression usage, +this is fine, but, when used by other components such as Spring Integration, +performance can be very important, and there is no real need for the dynamism. -The SpEL compiler is intended to address this need. The -compiler will generate a real Java class on the fly during evaluation that embodies the -expression behavior and use that to achieve much faster expression -evaluation. Due to the lack of typing around expressions the compiler +The SpEL compiler is intended to address this need. During evaluation, the +compiler generates a real Java class that embodies the +expression behavior and uses that to achieve much faster expression +evaluation. Due to the lack of typing around expressions, the compiler uses information gathered during the interpreted evaluations of an expression when performing compilation. For example, it does not know the type -of a property reference purely from the expression, but during the first -interpreted evaluation it will find out what it is. Of course, basing the -compilation on this information could cause trouble later if the types of -the various expression elements change over time. For this reason compilation +of a property reference purely from the expression, but, during the first +interpreted evaluation, it finds out what it is. Of course, basing the +compilation on this information can cause trouble later if the types of +the various expression elements change over time. For this reason, compilation is best suited to expressions whose type information is not going to change on repeated evaluations. -For a basic expression like this: +Consider the following basic expression: -`someArray[0].someProperty.someOtherProperty < 0.1` +==== +---- +someArray[0].someProperty.someOtherProperty < 0.1 +---- +==== -which involves array access, some property derefencing and numeric operations, the performance -gain can be very noticeable. In an example micro benchmark run of 50000 iterations, it was -taking 75ms to evaluate using only the interpreter and just 3ms using the compiled version +Because the preceding expression involves array access, some property de-referencing, and numeric operations, the performance +gain can be very noticeable. In an example micro benchmark run of 50000 iterations, it +took 75ms to evaluate by using the interpreter and only 3ms using the compiled version of the expression. -[[expressions-compiler-configuration]] -==== Compiler configuration -The compiler is not turned on by default, but there are two ways to turn -it on. It can be turned on using the parser configuration process discussed earlier or -via a system property when SpEL usage is embedded inside another component. This section +[[expressions-compiler-configuration]] +==== Compiler Configuration + +The compiler is not turned on by default, but you can turn it on in either of two different +ways. You can turn it on by using the parser configuration process (<>) or +by using a system property when SpEL usage is embedded inside another component. This section discusses both of these options. -It is important to understand that there are a few modes the compiler can operate in, captured -in an enum (`org.springframework.expression.spel.SpelCompilerMode`). The modes are as follows: +The compiler can operate in one of three modes, which are captured +in the `org.springframework.expression.spel.SpelCompilerMode` enum. The modes are as follows: -- `OFF` - The compiler is switched off; this is the default. -- `IMMEDIATE` - In immediate mode the expressions are compiled as soon as possible. This +* `OFF` (default): The compiler is switched off. +* `IMMEDIATE`: In immediate mode, the expressions are compiled as soon as possible. This is typically after the first interpreted evaluation. If the compiled expression fails -(typically due to a type changing, as described above) then the caller of the expression -evaluation will receive an exception. -- `MIXED` - In mixed mode the expressions silently switch between interpreted and compiled -mode over time. After some number of interpreted runs they will switch to compiled -form and if something goes wrong with the compiled form (like a type changing, as -described above) then the expression will automatically switch back to interpreted form -again. Sometime later it may generate another compiled form and switch to it. Basically +(typically due to a type changing, as described earlier), the caller of the expression +evaluation receives an exception. +* `MIXED`: In mixed mode, the expressions silently switch between interpreted and compiled +mode over time. After some number of interpreted runs, they switch to compiled +form and, if something goes wrong with the compiled form (such as a type changing, as +described earlier), the expression automatically switches back to interpreted form +again. Sometime later, it may generate another compiled form and switch to it. Basically, the exception that the user gets in `IMMEDIATE` mode is instead handled internally. `IMMEDIATE` mode exists because `MIXED` mode could cause issues for expressions that -have side effects. If a compiled expression blows up after partially succeeding it +have side effects. If a compiled expression blows up after partially succeeding, it may have already done something that has affected the state of the system. If this -has happened the caller may not want it to silently re-run in interpreted mode +has happened, the caller may not want it to silently re-run in interpreted mode, since part of the expression may be running twice. -After selecting a mode, use the `SpelParserConfiguration` to configure the parser: +After selecting a mode, use the `SpelParserConfiguration` to configure the parser. The +following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -360,53 +376,55 @@ After selecting a mode, use the `SpelParserConfiguration` to configure the parse Object payload = expr.getValue(message); ---- +==== -When specifying the compiler mode it is also possible to specify a classloader (passing null is allowed). -Compiled expressions will be defined in a child classloader created under any that is supplied. -It is important to ensure if a classloader is specified it can see all the types involved in +When you specify the compiler mode, you can also specify a classloader (passing null is allowed). +Compiled expressions are defined in a child classloader created under any that is supplied. +It is important to ensure that, if a classloader is specified, it can see all the types involved in the expression evaluation process. -If none is specified then a default classloader will be used (typically the context classloader for +If you do not specify a classloader, a default classloader is used (typically the context classloader for the thread that is running during expression evaluation). The second way to configure the compiler is for use when SpEL is embedded inside some other -component and it may not be possible to configure via a configuration object. -In these cases it is possible to use a system property. The property -`spring.expression.compiler.mode` can be set to one of the `SpelCompilerMode` +component and it may not be possible to configure it through a configuration object. +In these cases, it is possible to use a system property. You can set the +`spring.expression.compiler.mode` property to one of the `SpelCompilerMode` enum values (`off`, `immediate`, or `mixed`). [[expressions-compiler-limitations]] -==== Compiler limitations +==== Compiler Limitations -Since Spring Framework 4.1 the basic compilation framework is in place. However, the framework does not +Since Spring Framework 4.1, the basic compilation framework is in place. However, the framework does not yet support compiling every kind of expression. The initial focus has been on the common expressions that are -likely to be used in performance critical contexts. The following kinds of expression cannot be compiled +likely to be used in performance-critical contexts. The following kinds of expression cannot be compiled at the moment: -- expressions involving assignment -- expressions relying on the conversion service -- expressions using custom resolvers or accessors -- expressions using selection or projection - -More and more types of expression will be compilable in the future. +* Expressions involving assignment +* Expressions relying on the conversion service +* Expressions using custom resolvers or accessors +* Expressions using selection or projection +More types of expression will be compilable in the future. [[expressions-beandef]] -== Expressions in bean definitions +== Expressions in Bean Definitions -SpEL expressions can be used with XML or annotation-based configuration metadata for -defining ``BeanDefinition``s. In both cases the syntax to define the expression is of the +You can use SpEL expressions with XML-based or annotation-based configuration metadata for +defining `BeanDefinition` instances. In both cases, the syntax to define the expression is of the form `#{ }`. [[expressions-beandef-xml-based]] -=== XML configuration +=== XML Configuration -A property or constructor-arg value can be set using expressions as shown below. +A property or constructor argument value can be set by using expressions, as the following +example shows: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -416,11 +434,12 @@ A property or constructor-arg value can be set using expressions as shown below. ---- +==== -The variable `systemProperties` is predefined, so you can use it in your expressions as -shown below. Note that you do not have to prefix the predefined variable with the `#` -symbol in this context. +The `systemProperties` variable is predefined, so you can use it in your expressions, as +the following example shows: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -430,9 +449,14 @@ symbol in this context. ---- +==== -You can also refer to other bean properties by name, for example. +Note that you do not have to prefix the predefined variable with the `#` +symbol in this context. +You can also refer to other bean properties by name, as the following example shows: + +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -448,17 +472,19 @@ You can also refer to other bean properties by name, for example. ---- +==== [[expressions-beandef-annotation-based]] -=== Annotation config +=== Annotation Configuration -The `@Value` annotation can be placed on fields, methods and method/constructor -parameters to specify a default value. +To specify a default value, you can place the `@Value` annotation on fields, methods, and method or constructor +parameters. -Here is an example to set the default value of a field variable. +The following example sets the default value of a field variable: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -477,9 +503,11 @@ Here is an example to set the default value of a field variable. } ---- +==== -The equivalent but on a property setter method is shown below. +The following example shows the equivalent but on a property setter method: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -498,9 +526,12 @@ The equivalent but on a property setter method is shown below. } ---- +==== -Autowired methods and constructors can also use the `@Value` annotation. +Autowired methods and constructors can also use the `@Value` annotation, as the following +examples show: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -539,26 +570,44 @@ Autowired methods and constructors can also use the `@Value` annotation. // ... } ---- - +==== [[expressions-language-ref]] == Language Reference +This section describes how the Spring Expression Language works. It covers the following +topics: +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> [[expressions-ref-literal]] -=== Literal expressions +=== Literal Expressions The types of literal expressions supported are strings, numeric values (int, real, hex), -boolean and null. Strings are delimited by single quotes. To put a single quote itself -in a string, use two single quote characters. +boolean, and null. Strings are delimited by single quotation marks. To put a single quotation mark itself +in a string, use two single quotation mark characters. -The following listing shows simple usage of literals. Typically they would not be used -in isolation like this but rather as part of a more complex expression, for example +The following listing shows simple usage of literals. Typically, they are not used +in isolation like this but, rather, as part of a more complex expression -- for example, using a literal on one side of a logical comparison operator. +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -576,21 +625,23 @@ using a literal on one side of a logical comparison operator. Object nullValue = parser.parseExpression("null").getValue(); ---- +==== Numbers support the use of the negative sign, exponential notation, and decimal points. -By default real numbers are parsed using Double.parseDouble(). +By default, real numbers are parsed by using Double.parseDouble(). [[expressions-properties-arrays]] -=== Properties, Arrays, Lists, Maps, Indexers +=== Properties, Arrays, Lists, Maps, and Indexers -Navigating with property references is easy: just use a period to indicate a nested -property value. The instances of the `Inventor` class, pupin, and tesla, were populated with -data listed in the section <>. -To navigate "down" and get Tesla's year of birth and Pupin's city of birth the following -expressions are used. +Navigating with property references is easy. To do so, use a period to indicate a nested +property value. The instances of the `Inventor` class, `pupin` and `tesla`, were populated with +data listed in the <> section. +To navigate "`down`" and get Tesla's year of birth and Pupin's city of birth, we use the following +expressions: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -599,10 +650,13 @@ expressions are used. String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context); ---- +==== Case insensitivity is allowed for the first letter of property names. The contents of -arrays and lists are obtained using square bracket notation. +arrays and lists are obtained by using square bracket notation, as the following example +shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -626,11 +680,13 @@ arrays and lists are obtained using square bracket notation. String invention = parser.parseExpression("Members[0].Inventions[6]").getValue( context, ieee, String.class); ---- +==== The contents of maps are obtained by specifying the literal key value within the -brackets. In this case, because keys for the Officers map are strings, we can specify -string literals. +brackets. In the following example, because keys for the `Officers` map are strings, we can specify +string literals: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -647,14 +703,16 @@ string literals. parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue( societyContext, "Croatia"); ---- +==== [[expressions-inline-lists]] -=== Inline lists +=== Inline Lists -Lists can be expressed directly in an expression using `{}` notation. +You can directly express lists in an expression by using `{}` notation. +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -663,18 +721,21 @@ Lists can be expressed directly in an expression using `{}` notation. List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context); ---- +==== `{}` by itself means an empty list. For performance reasons, if the list is itself -entirely composed of fixed literals then a constant list is created to represent the -expression, rather than building a new list on each evaluation. +entirely composed of fixed literals, a constant list is created to represent the +expression (rather than building a new list on each evaluation). [[expressions-inline-maps]] === Inline Maps -Maps can also be expressed directly in an expression using `{key:value}` notation. +You can also directly express maps in an expression by using `{key:value}` notation. The +following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -683,19 +744,22 @@ Maps can also be expressed directly in an expression using `{key:value}` notatio Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context); ---- +==== + `{:}` by itself means an empty map. For performance reasons, if the map is itself composed -of fixed literals or other nested constant structures (lists or maps) then a constant map is created -to represent the expression, rather than building a new map on each evaluation. Quoting of the map keys -is optional, the examples above are not using quoted keys. +of fixed literals or other nested constant structures (lists or maps), a constant map is created +to represent the expression (rather than building a new map on each evaluation). Quoting of the map keys +is optional. The examples above do not use quoted keys. [[expressions-array-construction]] -=== Array construction +=== Array Construction -Arrays can be built using the familiar Java syntax, optionally supplying an initializer -to have the array populated at construction time. +You can build arrays by using the familiar Java syntax, optionally supplying an initializer +to have the array populated at construction time. The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -707,8 +771,9 @@ to have the array populated at construction time. // Multi dimensional array int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context); ---- +==== -It is not currently allowed to supply an initializer when constructing a +You cannot currently supply an initializer when you construct multi-dimensional array. @@ -716,9 +781,11 @@ multi-dimensional array. [[expressions-methods]] === Methods -Methods are invoked using typical Java programming syntax. You may also invoke methods -on literals. Varargs are also supported. +You can invoke methods by using typical Java programming syntax. You can also invoke methods +on literals. Variable arguments are also supported. The following examples show how to +invoke methods: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -729,19 +796,29 @@ on literals. Varargs are also supported. boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue( societyContext, Boolean.class); ---- +==== [[expressions-operators]] === Operators +The Spring Expression Language supports the following kinds of operators: + +* <> +* <> +* <> +* <> + [[expressions-operators-relational]] -==== Relational operators +==== Relational Operators -The relational operators; equal, not equal, less than, less than or equal, greater than, -and greater than or equal are supported using standard operator notation. +The relational operators (equal, not equal, less than, less than or equal, greater than, +and greater than or equal) are supported by using standard operator notation. The +following listing shows a few examples of operators: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -754,21 +831,23 @@ and greater than or equal are supported using standard operator notation. // evaluates to true boolean trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean.class); ---- +==== [NOTE] ==== -Greater/less-than comparisons against `null` follow a simple rule: `null` is treated as -nothing here (i.e. NOT as zero). As a consequence, any other value is always greater +Greater-than and less-than comparisons against `null` follow a simple rule: `null` is treated as +nothing (that is NOT as zero). As a consequence, any other value is always greater than `null` (`X > null` is always `true`) and no other value is ever less than nothing (`X < null` is always `false`). -If you prefer numeric comparisons instead, please avoid number-based `null` comparisons -in favor of comparisons against zero (e.g. `X > 0` or `X < 0`). +If you prefer numeric comparisons instead, avoid number-based `null` comparisons +in favor of comparisons against zero (for example, `X > 0` or `X < 0`). ==== -In addition to standard relational operators SpEL supports the `instanceof` and regular -expression based `matches` operator. +In addition to the standard relational operators, SpEL supports the `instanceof` and regular +expression-based `matches` operator. The following listing shows examples of both: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -784,27 +863,42 @@ expression based `matches` operator. boolean falseValue = parser.parseExpression( "'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class); ---- - -[NOTE] ==== -Be careful with primitive types as they are immediately boxed up to the wrapper type, + +CAUTION: Be careful with primitive types, as they are immediately boxed up to the wrapper type, so `1 instanceof T(int)` evaluates to `false` while `1 instanceof T(Integer)` evaluates to `true`, as expected. -==== Each symbolic operator can also be specified as a purely alphabetic equivalent. This avoids problems where the symbols used have special meaning for the document type in -which the expression is embedded (eg. an XML document). The textual equivalents are -shown here: `lt` (`<`), `gt` (`>`), `le` (`\<=`), `ge` (`>=`), `eq` (`==`), -`ne` (`!=`), `div` (`/`), `mod` (`%`), `not` (`!`). These are case insensitive. +which the expression is embedded (such as in an XML document). The textual equivalents are: + +* `lt` (`<`) +* `gt` (`>`) +* `le` (`\<=`) +* `ge` (`>=`) +* `eq` (`==`) +* `ne` (`!=`) +* `div` (`/`) +* `mod` (`%`) +* `not` (`!`). + +All of the textual operators are case-insensitive. + [[expressions-operators-logical]] -==== Logical operators +==== Logical Operators -The logical operators that are supported are and, or, and not. Their use is demonstrated -below. +SpEL supports the following logical operators: +* `and` +* `or` +* `not` + +The following example shows how to use the logical operators + +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -835,16 +929,19 @@ below. String expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')"; boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class); ---- +==== + [[expressions-operators-mathematical]] -==== Mathematical operators +==== Mathematical Operators -The addition operator can be used on both numbers and strings. Subtraction, multiplication -and division can be used only on numbers. Other mathematical operators supported are -modulus (%) and exponential power (^). Standard operator precedence is enforced. These -operators are demonstrated below. +You can use the addition operator on both numbers and strings. You can use the subtraction, multiplication, +and division operators only on numbers. You can also use +the modulus (%) and exponential power (^) operators. Standard operator precedence is enforced. The +following example shows the mathematical operators in use: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -877,15 +974,18 @@ operators are demonstrated below. // Operator precedence int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21 ---- +==== [[expressions-assignment]] -=== Assignment +==== The Assignment Operator -Setting of a property is done by using the assignment operator. This would typically be -done within a call to `setValue` but can also be done inside a call to `getValue`. +To setting a property, use the assignment operator (`=`). This is typically +done within a call to `setValue` but can also be done inside a call to `getValue`. The +following listing shows both ways to use the assignment operator: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -898,19 +998,22 @@ done within a call to `setValue` but can also be done inside a call to `getValue String aleks = parser.parseExpression( "Name = 'Aleksandar Seovic'").getValue(context, inventor, String.class); ---- +==== [[expressions-types]] === Types -The special `T` operator can be used to specify an instance of java.lang.Class (the -_type_). Static methods are invoked using this operator as well. The -`StandardEvaluationContext` uses a `TypeLocator` to find types and the +You can use the special `T` operator to specify an instance of `java.lang.Class` (the +type). Static methods are invoked by using this operator as well. The +`StandardEvaluationContext` uses a `TypeLocator` to find types, and the `StandardTypeLocator` (which can be replaced) is built with an understanding of the -java.lang package. This means T() references to types within java.lang do not need to be -fully qualified, but all other type references must be. +`java.lang` package. This means that `T()` references to types within `java.lang` do not need to be +fully qualified, but all other type references must be. The following example shows how +to use the `T` operator: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -922,16 +1025,18 @@ fully qualified, but all other type references must be. "T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR") .getValue(Boolean.class); ---- +==== [[expressions-constructors]] === Constructors -Constructors can be invoked using the new operator. The fully qualified class name -should be used for all but the primitive type and String (where int, float, etc, can be -used). +You can invoke constructors by using the `new` operator. You should use the fully qualified class name +for all but the primitive types (`int`, `float`, and so on) and String. The following +example shows how to use the `new` operator to invoke constructors: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -944,15 +1049,18 @@ used). "Members.add(new org.spring.samples.spel.inventor.Inventor( 'Albert Einstein', 'German'))").getValue(societyContext); ---- +==== [[expressions-ref-variables]] === Variables -Variables can be referenced in the expression using the syntax `#variableName`. Variables -are set using the method `setVariable` on `EvaluationContext` implementations. +You can reference variables in the expression by using the `#variableName` syntax. Variables +are set by using the `setVariable` method on `EvaluationContext` implementations. The +following example shows how to use variables: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -964,16 +1072,20 @@ are set using the method `setVariable` on `EvaluationContext` implementations. parser.parseExpression("Name = #newName").getValue(context, tesla); System.out.println(tesla.getName()) // "Mike Tesla" ---- +==== + [[expressions-this-root]] -==== The #this and #root variables +==== The `#this` and `#root` Variables -The variable `#this` is always defined and refers to the current evaluation object -(against which unqualified references are resolved). The variable `#root` is always +The `#this` variable is always defined and refers to the current evaluation object +(against which unqualified references are resolved). The `#root` variable is always defined and refers to the root context object. Although `#this` may vary as components of -an expression are evaluated, `#root` always refers to the root. +an expression are evaluated, `#root` always refers to the root. The followig examples +show how to use the `#this` and `#root` variables: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -991,15 +1103,18 @@ an expression are evaluated, `#root` always refers to the root. List primesGreaterThanTen = (List) parser.parseExpression( "#primes.?[#this>10]").getValue(context); ---- +==== [[expressions-ref-functions]] === Functions -You can extend SpEL by registering user defined functions that can be called within the -expression string. The function is registered through the `EvaluationContext`. +You can extend SpEL by registering user-defined functions that can be called within the +expression string. The function is registered through the `EvaluationContext`. The +following example shows how to register a user-defined function: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1008,9 +1123,11 @@ expression string. The function is registered through the `EvaluationContext`. EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); context.setVariable("myFunction", method); ---- +==== -For example, given a utility method to reverse a string is shown below: +For example, consider the following utility method that reverses a string: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1025,9 +1142,11 @@ For example, given a utility method to reverse a string is shown below: } } ---- +==== -The above method can then be registered and used as follows: +You can then register and use the preceding method, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1040,15 +1159,18 @@ The above method can then be registered and used as follows: String helloWorldReversed = parser.parseExpression( "#reverseString('hello')").getValue(context, String.class); ---- +==== [[expressions-bean-references]] -=== Bean references +=== Bean References -If the evaluation context has been configured with a bean resolver it is possible to -look up beans from an expression using the `@` symbol. +If the evaluation context has been configured with a bean resolver, you can +look up beans from an expression by using the `@` symbol. The following example shows how +to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1056,12 +1178,15 @@ look up beans from an expression using the `@` symbol. StandardEvaluationContext context = new StandardEvaluationContext(); context.setBeanResolver(new MyBeanResolver()); - // This will end up calling resolve(context,"foo") on MyBeanResolver during evaluation - Object bean = parser.parseExpression("@foo").getValue(context); + // This will end up calling resolve(context,"something") on MyBeanResolver during evaluation + Object bean = parser.parseExpression("@something").getValue(context); ---- +==== -To access a factory bean itself, the bean name should instead be prefixed with an `&` symbol. +To access a factory bean itself, you should instead prefix the bean name with an `&` symbol. +The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1072,24 +1197,29 @@ To access a factory bean itself, the bean name should instead be prefixed with a // This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation Object bean = parser.parseExpression("&foo").getValue(context); ---- +==== + [[expressions-operator-ternary]] === Ternary Operator (If-Then-Else) You can use the ternary operator for performing if-then-else conditional logic inside -the expression. A minimal example is: +the expression. The following listing shows a minimal example: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- String falseString = parser.parseExpression( "false ? 'trueExp' : 'falseExp'").getValue(String.class); ---- +==== -In this case, the boolean false results in returning the string value `'falseExp'`. A more -realistic example is shown below. +In this case, the boolean `false` results in returning the string value `'falseExp'`. A more +realistic example follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1103,8 +1233,9 @@ realistic example is shown below. .getValue(societyContext, String.class); // queryResultString = "Nikola Tesla is a member of the IEEE Society" ---- +==== -Also see the next section on the Elvis operator for an even shorter syntax for the +See the next section on the Elvis operator for an even shorter syntax for the ternary operator. @@ -1114,18 +1245,22 @@ ternary operator. The Elvis operator is a shortening of the ternary operator syntax and is used in the http://www.groovy-lang.org/operators.html#_elvis_operator[Groovy] language. -With the ternary operator syntax you usually have to repeat a variable twice, for -example: +With the ternary operator syntax, you usually have to repeat a variable twice, as the +following example shows: +==== [source,groovy,indent=0] [subs="verbatim,quotes"] ---- String name = "Elvis Presley"; String displayName = (name != null ? name : "Unknown"); ---- +==== -Instead you can use the Elvis operator, named for the resemblance to Elvis' hair style. +Instead, you can use the Elvis operator (named for the resemblance to Elvis' hair style). +The following example shows how to use the Elvis operator: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1134,9 +1269,11 @@ Instead you can use the Elvis operator, named for the resemblance to Elvis' hair String name = parser.parseExpression("name?:'Unknown'").getValue(String.class); System.out.println(name); // 'Unknown' ---- +==== -Here is a more complex example. +The following listing ahows A more complex example: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1151,18 +1288,37 @@ Here is a more complex example. name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, tesla, String.class); System.out.println(name); // Elvis Presley ---- +==== + +[NOTE] +===== +You can use the Elvis operator to apply default values in expressions. The folloiwng +example shows how to use the Elvis operator in a `@Value` expression: + +==== +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Value("#{systemProperties['pop3.port'] ?: 25}") +---- + +This will inject a system property `pop3.port` if it is defined or 25 if not. +==== +===== [[expressions-operator-safe-navigation]] -=== Safe Navigation operator +=== Safe Navigation Operator -The Safe Navigation operator is used to avoid a `NullPointerException` and comes from +The safe navigation operator is used to avoid a `NullPointerException` and comes from the http://www.groovy-lang.org/operators.html#_safe_navigation_operator[Groovy] -language. Typically when you have a reference to an object you might need to verify that +language. Typically, when you have a reference to an object, you might need to verify that it is not null before accessing methods or properties of the object. To avoid this, the -safe navigation operator will simply return null instead of throwing an exception. +safe navigation operator returns null instead of throwing an exception. The following +example shows how to use the safe navigation operator: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1179,19 +1335,6 @@ safe navigation operator will simply return null instead of throwing an exceptio city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class); System.out.println(city); // null - does not throw NullPointerException!!! ---- - -[NOTE] -==== -The Elvis operator can be used to apply default values in expressions, e.g. in an -`@Value` expression: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Value("#{systemProperties['pop3.port'] ?: 25}") ----- - -This will inject a system property `pop3.port` if it is defined or 25 if not. ==== @@ -1199,38 +1342,42 @@ This will inject a system property `pop3.port` if it is defined or 25 if not. [[expressions-collection-selection]] === Collection Selection -Selection is a powerful expression language feature that allows you to transform some -source collection into another by selecting from its entries. +Selection is a powerful expression language feature that lets you transform a +source collection into another collection by selecting from its entries. -Selection uses the syntax `.?[selectionExpression]`. This will filter the collection and -return a new collection containing a subset of the original elements. For example, -selection would allow us to easily get a list of Serbian inventors: +Selection uses a syntax of `.?[selectionExpression]`. It filters the collection and +returns a new collection that contain a subset of the original elements. For example, +selection lets us easily get a list of Serbian inventors, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- List list = (List) parser.parseExpression( "Members.?[Nationality == 'Serbian']").getValue(societyContext); ---- +==== -Selection is possible upon both lists and maps. In the former case the selection -criteria is evaluated against each individual list element whilst against a map the +Selection is possible upon both lists and maps. For a list, the selection +criteria is evaluated against each individual list element. Against a map, the selection criteria is evaluated against each map entry (objects of the Java type -`Map.Entry`). Map entries have their key and value accessible as properties for use in +`Map.Entry`). Each map entry has its key and value accessible as properties for use in the selection. -This expression will return a new map consisting of those elements of the original map -where the entry value is less than 27. +The following expression returns a new map that consists of those elements of the original map +where the entry value is less than 27: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- Map newMap = parser.parseExpression("map.?[value<27]").getValue(); ---- +==== -In addition to returning all the selected elements, it is possible to retrieve just the -first or the last value. To obtain the first entry matching the selection the syntax is -`.^[selectionExpression]` whilst to obtain the last matching selection the syntax is +In addition to returning all the selected elements, you can retrieve only the +first or the last value. To obtain the first entry matching the selection, the syntax is +`.^[selectionExpression]`. To obtain the last matching selection, the syntax is `.$[selectionExpression]`. @@ -1238,22 +1385,24 @@ first or the last value. To obtain the first entry matching the selection the sy [[expressions-collection-projection]] === Collection Projection -Projection allows a collection to drive the evaluation of a sub-expression and the -result is a new collection. The syntax for projection is `.![projectionExpression]`. Most -easily understood by example, suppose we have a list of inventors but want the list of -cities where they were born. Effectively we want to evaluate 'placeOfBirth.city' for -every entry in the inventor list. Using projection: +Projection lets a collection drive the evaluation of a sub-expression, and the +result is a new collection. The syntax for projection is `.![projectionExpression]`. For +example, suppose we have a list of inventors but want the list of +cities where they were born. Effectively, we want to evaluate 'placeOfBirth.city' for +every entry in the inventor list. The following example uses projection to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- // returns ['Smiljan', 'Idvor' ] List placesOfBirth = (List)parser.parseExpression("Members.![placeOfBirth.city]"); ---- +==== -A map can also be used to drive projection and in this case the projection expression is +You can also use a map to drive projection and, in this case, the projection expression is evaluated against each entry in the map (represented as a Java `Map.Entry`). The result -of a projection across a map is a list consisting of the evaluation of the projection +of a projection across a map is a list that consists of the evaluation of the projection expression against each map entry. @@ -1261,10 +1410,12 @@ expression against each map entry. [[expressions-templating]] === Expression templating -Expression templates allow a mixing of literal text with one or more evaluation blocks. +Expression templates allow mixing literal text with one or more evaluation blocks. Each evaluation block is delimited with prefix and suffix characters that you can -define, a common choice is to use `#{ }` as the delimiters. For example, +define. A common choice is to use `#{ }` as the delimiters, as the following example +shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1274,14 +1425,16 @@ define, a common choice is to use `#{ }` as the delimiters. For example, // evaluates to "random number is 0.7038186818312008" ---- +==== The string is evaluated by concatenating the literal text `'random number is '` with the -result of evaluating the expression inside the `#{ }` delimiter, in this case the result -of calling that `random()` method. The second argument to the method `parseExpression()` +result of evaluating the expression inside the `#{ }` delimiter (in this case, the result +of calling that `random()` method). The second argument to the `parseExpression()` method is of the type `ParserContext`. The `ParserContext` interface is used to influence how the expression is parsed in order to support the expression templating functionality. -The definition of `TemplateParserContext` is shown below. +The definition of `TemplateParserContext` follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1300,15 +1453,17 @@ The definition of `TemplateParserContext` is shown below. } } ---- - +==== [[expressions-example-classes]] -== Classes used in the examples +== Classes Used in the Examples -Inventor.java +This section lists the classes used in the examples throughout this chapter. +.Inventor.java +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1382,9 +1537,10 @@ Inventor.java } } ---- +==== -PlaceOfBirth.java - +.PlaceOfBirth.java +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1422,9 +1578,10 @@ PlaceOfBirth.java } ---- +==== -Society.java - +.Society.java +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1469,3 +1626,4 @@ Society.java } ---- +==== diff --git a/src/docs/asciidoc/core/core-null-safety.adoc b/src/docs/asciidoc/core/core-null-safety.adoc index 5ea8ccd2f9f..d3a78657dfb 100644 --- a/src/docs/asciidoc/core/core-null-safety.adoc +++ b/src/docs/asciidoc/core/core-null-safety.adoc @@ -1,19 +1,19 @@ [[null-safety]] = Null-safety -Although Java does not allow to express null-safety with its type system, Spring Framework -now provides following annotations in the `org.springframework.lang` package to declare +Although Java does not let you express null-safety with its type system, Spring Framework +now provides the following annotations in the `org.springframework.lang` package to let you declare nullability of APIs and fields: - * {api-spring-framework}/lang/NonNull.html[`@NonNull`] annotation where specific parameter, - return value or field cannot be `null` (not needed on parameter and return value - where `@NonNullApi` and `@NonNullFields` apply) . - * {api-spring-framework}/lang/Nullable.html[`@Nullable`] annotation where specific - parameter, return value or field can be `null`. - * {api-spring-framework}/lang/NonNullApi.html[`@NonNullApi`] annotation at package level - declares non-null as the default behavior for parameters and return values. - * {api-spring-framework}/lang/NonNullFields.html[`@NonNullFields`] annotation at package - level declares non-null as the default behavior for fields. +* {api-spring-framework}/lang/NonNull.html[`@NonNull`]: Annotation to indicate that a specific parameter, +return value, or field cannot be `null` (not needed on parameter and return value +where `@NonNullApi` and `@NonNullFields` apply) . +* {api-spring-framework}/lang/Nullable.html[`@Nullable`]: Annotation to indicate that a specific +parameter, return value, or field can be `null`. +* {api-spring-framework}/lang/NonNullApi.html[`@NonNullApi`]: Annotation at the package level +that declares non-null as the default behavior for parameters and return values. +* {api-spring-framework}/lang/NonNullFields.html[`@NonNullFields`]: Annotation at the package +level that declares non-null as the default behavior for fields. Spring Framework leverages itself these annotations, but they can also be used in any Spring based Java project to declare null-safe APIs and optionally null-safe fields. Generic type arguments, @@ -23,34 +23,30 @@ Nullability declaration are expected to be fine-tuned between Spring Framework r including minor ones. Nullability of types used inside method bodies is outside of the scope of this feature. -[NOTE] -==== -Libraries like Reactor or Spring Data provide null-safe APIs leveraging this feature. -==== - +NOTE: Libraries like Reactor or Spring Data provide null-safe APIs that use this feature. == Use cases In addition to providing an explicit declaration for Spring Framework API nullability, -these annotation can be used by IDE (such as IDEA or Eclipse) to provide useful -warnings to Java developers related to null-safety in order to avoid `NullPointerException` +these annotations can be used by an IDE (such as IDEA or Eclipse) to provide useful +warnings related to null-safety in order to avoid `NullPointerException` at runtime. -They are also used to make Spring API null-safe in Kotlin projects since Kotlin natively +They are also used to make Spring API null-safe in Kotlin projects, since Kotlin natively supports https://kotlinlang.org/docs/reference/null-safety.html[null-safety]. More details -are available in <>. +are available in the <>. == JSR 305 meta-annotations Spring annotations are meta-annotated with https://jcp.org/en/jsr/detail?id=305[JSR 305] -annotations (a dormant but widely spread JSR). JSR 305 meta-annotations allows tooling vendors -like IDEA or Kotlin to provide null-safety support in a generic way, without having to hard-code +annotations (a dormant but widely spread JSR). JSR 305 meta-annotations let tooling vendors +like IDEA or Kotlin provide null-safety support in a generic way, without having to hard-code support for Spring annotations. -It is not necessary nor recommended to add JSR 305 dependency in project classpath to -take advantage of Spring null-safe API. Only projects like -Spring-based libraries using null-safety annotations in their codebase should add +It is not necessary nor recommended to add JSR 305 dependency in the project classpath to +take advantage of Spring null-safe API. Only projects such as +Spring-based libraries that use null-safety annotations in their codebase should add `com.google.code.findbugs:jsr305:3.0.2` with `compileOnly` Gradle configuration or Maven `provided` scope to avoid compile warnings. diff --git a/src/docs/asciidoc/core/core-resources.adoc b/src/docs/asciidoc/core/core-resources.adoc index fb464937c25..634dd89548a 100644 --- a/src/docs/asciidoc/core/core-resources.adoc +++ b/src/docs/asciidoc/core/core-resources.adoc @@ -1,16 +1,26 @@ [[resources]] = Resources +This chapter covers how Spring handles resources and how you can work with resources in +Spring. It includes the following topics: + +* <> +* <> +* <> +* <> +* <> +* <> +* <> [[resources-introduction]] == Introduction -Java's standard `java.net.URL` class and standard handlers for various URL prefixes -unfortunately are not quite adequate enough for all access to low-level resources. For +Java's standard `java.net.URL` class and standard handlers for various URL prefixes, +unfortunately, are not quite adequate enough for all access to low-level resources. For example, there is no standardized `URL` implementation that may be used to access a -resource that needs to be obtained from the classpath, or relative to a +resource that needs to be obtained from the classpath or relative to a `ServletContext`. While it is possible to register new handlers for specialized `URL` prefixes (similar to existing handlers for prefixes such as `http:`), this is generally quite complicated, and the `URL` interface still lacks some desirable functionality, @@ -18,13 +28,14 @@ such as a method to check for the existence of the resource being pointed to. - [[resources-resource]] -== The Resource interface +== The Resource Interface Spring's `Resource` interface is meant to be a more capable interface for abstracting -access to low-level resources. +access to low-level resources. The following listing shows the `Resource` interface +definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -46,7 +57,13 @@ access to low-level resources. } ---- +==== +As the definition of the `Resource` interface shows, it extends the `InputStreamSource` +interface. The following listing shows the definition of the `InputStreamSource` +interface: + +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -56,151 +73,158 @@ access to low-level resources. } ---- +==== Some of the most important methods from the `Resource` interface are: -* `getInputStream()`: locates and opens the resource, returning an `InputStream` for +* `getInputStream()`: Locates and opens the resource, returning an `InputStream` for reading from the resource. It is expected that each invocation returns a fresh `InputStream`. It is the responsibility of the caller to close the stream. -* `exists()`: returns a `boolean` indicating whether this resource actually exists in +* `exists()`: Returns a `boolean` indicating whether this resource actually exists in physical form. -* `isOpen()`: returns a `boolean` indicating whether this resource represents a handle - with an open stream. If `true`, the `InputStream` cannot be read multiple times, and - must be read once only and then closed to avoid resource leaks. Will be `false` for +* `isOpen()`: Returns a `boolean` indicating whether this resource represents a handle + with an open stream. If `true`, the `InputStream` cannot be read multiple times and + must be read once only and then closed to avoid resource leaks. Returns `false` for all usual resource implementations, with the exception of `InputStreamResource`. -* `getDescription()`: returns a description for this resource, to be used for error +* `getDescription()`: Returns a description for this resource, to be used for error output when working with the resource. This is often the fully qualified file name or the actual URL of the resource. -Other methods allow you to obtain an actual `URL` or `File` object representing the -resource (if the underlying implementation is compatible, and supports that +Other methods let you obtain an actual `URL` or `File` object representing the +resource (if the underlying implementation is compatible and supports that functionality). -The `Resource` abstraction is used extensively in Spring itself, as an argument type in +Spring itself uses the `Resource` abstraction extensively, as an argument type in many method signatures when a resource is needed. Other methods in some Spring APIs -(such as the constructors to various `ApplicationContext` implementations), take a +(such as the constructors to various `ApplicationContext` implementations) take a `String` which in unadorned or simple form is used to create a `Resource` appropriate to -that context implementation, or via special prefixes on the `String` path, allow the -caller to specify that a specific `Resource` implementation must be created and used. +that context implementation or, via special prefixes on the `String` path, let the +caller specify that a specific `Resource` implementation must be created and used. -While the `Resource` interface is used a lot with Spring and by Spring, it's actually +While the `Resource` interface is used a lot with Spring and by Spring, it is actually very useful to use as a general utility class by itself in your own code, for access to -resources, even when your code doesn't know or care about any other parts of Spring. +resources, even when your code does not know or care about any other parts of Spring. While this couples your code to Spring, it really only couples it to this small set of -utility classes, which are serving as a more capable replacement for `URL`, and can be +utility classes, which serve as a more capable replacement for `URL` and can be considered equivalent to any other library you would use for this purpose. -It is important to note that the `Resource` abstraction does not replace functionality: -it wraps it where possible. For example, a `UrlResource` wraps a URL, and uses the +NOTE: The `Resource` abstraction does not replace functionality. +It wraps it where possible. For example, a `UrlResource` wraps a URL and uses the wrapped `URL` to do its work. - [[resources-implementations]] -== Built-in Resource implementations +== Built-in Resource Implementations -There are a number of `Resource` implementations that come supplied straight out of the -box in Spring: +Spring includes the following `Resource` implementations: + +* <> +* <> +* <> +* <> +* <> +* <> [[resources-implementations-urlresource]] -=== UrlResource +=== `UrlResource` -The `UrlResource` wraps a `java.net.URL`, and may be used to access any object that is -normally accessible via a URL, such as files, an HTTP target, an FTP target, etc. All +`UrlResource` wraps a `java.net.URL` and can be used to access any object that is +normally accessible with a URL, such as files, an HTTP target, an FTP target, and others. All URLs have a standardized `String` representation, such that appropriate standardized prefixes are used to indicate one URL type from another. This includes `file:` for -accessing filesystem paths, `http:` for accessing resources via the HTTP protocol, -`ftp:` for accessing resources via FTP, etc. +accessing filesystem paths, `http:` for accessing resources through the HTTP protocol, +`ftp:` for accessing resources through FTP, and others. -A `UrlResource` is created by Java code explicitly using the `UrlResource` constructor, -but will often be created implicitly when you call an API method which takes a `String` -argument which is meant to represent a path. For the latter case, a JavaBeans -`PropertyEditor` will ultimately decide which type of `Resource` to create. If the path -string contains a few well-known (to it, that is) prefixes such as `classpath:`, it will -create an appropriate specialized `Resource` for that prefix. However, if it doesn't -recognize the prefix, it will assume the this is just a standard URL string, and will -create a `UrlResource`. +A `UrlResource` is created by Java code by explicitly using the `UrlResource` constructor +but is often created implicitly when you call an API method that takes a `String` +argument meant to represent a path. For the latter case, a JavaBeans +`PropertyEditor` ultimately decides which type of `Resource` to create. If the path +string contains well-known (to it, that is) prefix (such as `classpath:`), it +creates an appropriate specialized `Resource` for that prefix. However, if it does not +recognize the prefix, it assume the string is a standard URL string and +creates a `UrlResource`. [[resources-implementations-classpathresource]] -=== ClassPathResource +=== `ClassPathResource` -This class represents a resource which should be obtained from the classpath. This uses +This class represents a resource that should be obtained from the classpath. It uses either the thread context class loader, a given class loader, or a given class for loading resources. This `Resource` implementation supports resolution as `java.io.File` if the class path -resource resides in the file system, but not for classpath resources which reside in a -jar and have not been expanded (by the servlet engine, or whatever the environment is) -to the filesystem. To address this the various `Resource` implementations always support +resource resides in the file system but not for classpath resources that reside in a +jar and have not been expanded (by the servlet engine or whatever the environment is) +to the filesystem. To address this, the various `Resource` implementations always support resolution as a `java.net.URL`. -A `ClassPathResource` is created by Java code explicitly using the `ClassPathResource` -constructor, but will often be created implicitly when you call an API method which -takes a `String` argument which is meant to represent a path. For the latter case, a -JavaBeans `PropertyEditor` will recognize the special prefix `classpath:` on the string -path, and create a `ClassPathResource` in that case. +A `ClassPathResource` is created by Java code by explicitly using the `ClassPathResource` +constructor but is often created implicitly when you call an API method that +takes a `String` argument meant to represent a path. For the latter case, a +JavaBeans `PropertyEditor` recognizes the special prefix, `classpath:`, on the string +path and creates a `ClassPathResource` in that case. [[resources-implementations-filesystemresource]] -=== FileSystemResource +=== `FileSystemResource` -This is a `Resource` implementation for `java.io.File` handles. It obviously supports -resolution as a `File`, and as a `URL`. +This is a `Resource` implementation for `java.io.File` handles. It supports +resolution as a `File` and as a `URL`. [[resources-implementations-servletcontextresource]] -=== ServletContextResource +=== `ServletContextResource` -This is a `Resource` implementation for `ServletContext` resources, interpreting +This is a `Resource` implementation for `ServletContext` resources that interprets relative paths within the relevant web application's root directory. -This always supports stream access and URL access, but only allows `java.io.File` access +It always supports stream access and URL access but allows `java.io.File` access only when the web application archive is expanded and the resource is physically on the -filesystem. Whether or not it's expanded and on the filesystem like this, or accessed -directly from the JAR or somewhere else like a DB (it's conceivable) is actually +filesystem. Whether or not it is expanded and on the filesystem or accessed +directly from the JAR or somewhere else like a database (which is conceivable) is actually dependent on the Servlet container. [[resources-implementations-inputstreamresource]] -=== InputStreamResource +=== `InputStreamResource` -A `Resource` implementation for a given `InputStream`. This should only be used if no +An `InputStreamResource` is a `Resource` implementation for a given `InputStream`. It should be used only if no specific `Resource` implementation is applicable. In particular, prefer `ByteArrayResource` or any of the file-based `Resource` implementations where possible. -In contrast to other `Resource` implementations, this is a descriptor for an __already__ -opened resource - therefore returning `true` from `isOpen()`. Do not use it if you need -to keep the resource descriptor somewhere, or if you need to read a stream multiple +In contrast to other `Resource` implementations, this is a descriptor for an already-opened +resource. Therefore, it returns `true` from `isOpen()`. Do not use it if you need +to keep the resource descriptor somewhere or if you need to read a stream multiple times. [[resources-implementations-bytearrayresource]] -=== ByteArrayResource +=== `ByteArrayResource` This is a `Resource` implementation for a given byte array. It creates a `ByteArrayInputStream` for the given byte array. -It's useful for loading content from any given byte array, without having to resort to a +It is useful for loading content from any given byte array without having to resort to a single-use `InputStreamResource`. - [[resources-resourceloader]] -== The ResourceLoader +== The `ResourceLoader` The `ResourceLoader` interface is meant to be implemented by objects that can return -(i.e. load) `Resource` instances. +(that is, load) `Resource` instances. The following listing shows the `ResourceLoader` +interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -210,41 +234,49 @@ The `ResourceLoader` interface is meant to be implemented by objects that can re } ---- +==== -All application contexts implement the `ResourceLoader` interface, and therefore all +All application contexts implement the `ResourceLoader` interface. Therefore, all application contexts may be used to obtain `Resource` instances. When you call `getResource()` on a specific application context, and the location path -specified doesn't have a specific prefix, you will get back a `Resource` type that is +specified doesn't have a specific prefix, you get back a `Resource` type that is appropriate to that particular application context. For example, assume the following snippet of code was executed against a `ClassPathXmlApplicationContext` instance: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- Resource template = ctx.getResource("some/resource/path/myTemplate.txt"); ---- +==== -What would be returned would be a `ClassPathResource`; if the same method was executed -against a `FileSystemXmlApplicationContext` instance, you'd get back a -`FileSystemResource`. For a `WebApplicationContext`, you'd get back a -`ServletContextResource`, and so on. +Against a `ClassPathXmlApplicationContext`, that code returns a `ClassPathResource`. If the same method were executed +against a `FileSystemXmlApplicationContext` instance, it would return a +`FileSystemResource`. For a `WebApplicationContext`, it would return a +`ServletContextResource`. It would similarly return appropriate objects for each context. -As such, you can load resources in a fashion appropriate to the particular application +As a result, you can load resources in a fashion appropriate to the particular application context. On the other hand, you may also force `ClassPathResource` to be used, regardless of the -application context type, by specifying the special `classpath:` prefix: +application context type, by specifying the special `classpath:` prefix, as the following +example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt"); ---- +==== -Similarly, one can force a `UrlResource` to be used by specifying any of the standard -`java.net.URL` prefixes: +Similarly, you can force a `UrlResource` to be used by specifying any of the standard +`java.net.URL` prefixes. The following pair of examples use the `file` and `http` +prefixes: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -256,8 +288,9 @@ Similarly, one can force a `UrlResource` to be used by specifying any of the sta ---- Resource template = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt"); ---- +==== -The following table summarizes the strategy for converting ``String``s to ``Resource``s: +The following table summarizes the strategy for converting `String` objects to `Resource` objects: [[resources-resource-strings]] .Resource strings @@ -270,8 +303,7 @@ The following table summarizes the strategy for converting ``String``s to ``Reso | file: | `file:///data/config.xml` -| Loaded as a `URL`, from the filesystem. footnote:[But see also - pass:specialcharacters,macros[<>].] +| Loaded as a `URL` from the filesystem. See also <>. | http: | `http://myserver/logo.png` @@ -284,13 +316,14 @@ The following table summarizes the strategy for converting ``String``s to ``Reso - [[resources-resourceloaderaware]] -== The ResourceLoaderAware interface +== The `ResourceLoaderAware` interface -The `ResourceLoaderAware` interface is a special marker interface, identifying objects -that expect to be provided with a `ResourceLoader` reference. +The `ResourceLoaderAware` interface is a special marker interface that identifies objects +that expect to be provided with a `ResourceLoader` reference. The following listing shows +the definition of the `ResourceLoaderAware` interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -299,50 +332,51 @@ that expect to be provided with a `ResourceLoader` reference. void setResourceLoader(ResourceLoader resourceLoader); } ---- +==== When a class implements `ResourceLoaderAware` and is deployed into an application context (as a Spring-managed bean), it is recognized as `ResourceLoaderAware` by the -application context. The application context will then invoke the +application context. The application context then invokes `setResourceLoader(ResourceLoader)`, supplying itself as the argument (remember, all application contexts in Spring implement the `ResourceLoader` interface). -Of course, since an `ApplicationContext` is a `ResourceLoader`, the bean could also +Since an `ApplicationContext` is a `ResourceLoader`, the bean could also implement the `ApplicationContextAware` interface and use the supplied application -context directly to load resources, but in general, it's better to use the specialized -`ResourceLoader` interface if that's all that's needed. The code would just be coupled -to the resource loading interface, which can be considered a utility interface, and not +context directly to load resources. However, in general, it is better to use the specialized +`ResourceLoader` interface if that is all you need. The code would be coupled only +to the resource loading interface (which can be considered a utility interface) and not to the whole Spring `ApplicationContext` interface. As of Spring 2.5, you can rely upon autowiring of the `ResourceLoader` as an alternative -to implementing the `ResourceLoaderAware` interface. The "traditional" `constructor` and +to implementing the `ResourceLoaderAware` interface. The "`traditional`" `constructor` and `byType` autowiring modes (as described in <>) are now capable -of providing a dependency of type `ResourceLoader` for either a constructor argument or -setter method parameter respectively. For more flexibility (including the ability to -autowire fields and multiple parameter methods), consider using the new annotation-based -autowiring features. In that case, the `ResourceLoader` will be autowired into a field, -constructor argument, or method parameter that is expecting the `ResourceLoader` type as +of providing a dependency of type `ResourceLoader` for either a constructor argument or a +setter method parameter, respectively. For more flexibility (including the ability to +autowire fields and multiple parameter methods), consider using the annotation-based +autowiring features. In that case, the `ResourceLoader` is autowired into a field, +constructor argument, or method parameter that expects the `ResourceLoader` type as long as the field, constructor, or method in question carries the `@Autowired` annotation. For more information, see <>. - [[resources-as-dependencies]] -== Resources as dependencies +== Resources as Dependencies If the bean itself is going to determine and supply the resource path through some sort of dynamic process, it probably makes sense for the bean to use the `ResourceLoader` -interface to load resources. Consider as an example the loading of a template of some +interface to load resources. For example, consider the loading of a template of some sort, where the specific resource that is needed depends on the role of the user. If the resources are static, it makes sense to eliminate the use of the `ResourceLoader` -interface completely, and just have the bean expose the `Resource` properties it needs, -and expect that they will be injected into it. +interface completely, have the bean expose the `Resource` properties it needs, +and expect them to be injected into it. -What makes it trivial to then inject these properties, is that all application contexts -register and use a special JavaBeans `PropertyEditor` which can convert `String` paths -to `Resource` objects. So if `myBean` has a template property of type `Resource`, it can -be configured with a simple string for that resource, as follows: +What makes it trivial to then inject these properties is that all application contexts +register and use a special JavaBeans `PropertyEditor`, which can convert `String` paths +to `Resource` objects. So, if `myBean` has a template property of type `Resource`, it can +be configured with a simple string for that resource, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -350,16 +384,18 @@ be configured with a simple string for that resource, as follows: ---- +==== -Note that the resource path has no prefix, so because the application context itself is -going to be used as the `ResourceLoader`, the resource itself will be loaded via a -`ClassPathResource`, `FileSystemResource`, or `ServletContextResource` (as appropriate) +Note that the resource path has no prefix. Consequetly, because the application context itself is +going to be used as the `ResourceLoader`, the resource itself is loaded through a +`ClassPathResource`, a `FileSystemResource`, or a `ServletContextResource`, depending on the exact type of the context. -If there is a need to force a specific `Resource` type to be used, then a prefix may be -used. The following two examples show how to force a `ClassPathResource` and a -`UrlResource` (the latter being used to access a filesystem file). +If you need to force a specific `Resource` type to be used, you can use a prefix. +The following two examples show how to force a `ClassPathResource` and a +`UrlResource` (the latter being used to access a filesystem file): +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -371,49 +407,56 @@ used. The following two examples show how to force a `ClassPathResource` and a ---- ---- - +==== [[resources-app-ctx]] -== Application contexts and Resource paths +== Application Contexts and Resource Paths + +This section covers how to create application contexts with resources, including shortcuts +that work with XML, how to use wildcards, and other details. [[resources-app-ctx-construction]] -=== Constructing application contexts +=== Constructing Application Contexts An application context constructor (for a specific application context type) generally -takes a string or array of strings as the location path(s) of the resource(s) such as +takes a string or array of strings as the location paths of the resources, such as XML files that make up the definition of the context. -When such a location path doesn't have a prefix, the specific `Resource` type built from -that path and used to load the bean definitions, depends on and is appropriate to the -specific application context. For example, if you create a -`ClassPathXmlApplicationContext` as follows: +When such a location path does not have a prefix, the specific `Resource` type built from +that path and used to load the bean definitions depends on and is appropriate to the +specific application context. For example, consider the following example, which creates a +`ClassPathXmlApplicationContext`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml"); ---- +==== -The bean definitions will be loaded from the classpath, as a `ClassPathResource` will be -used. But if you create a `FileSystemXmlApplicationContext` as follows: +The bean definitions are loaded from the classpath, because a `ClassPathResource` is +used. However, consider the following example, which creates a `FileSystemXmlApplicationContext`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/appContext.xml"); ---- +==== -The bean definition will be loaded from a filesystem location, in this case relative to -the current working directory. +Now the bean definition is loaded from a filesystem location (in this case, relative to +the current working directory). Note that the use of the special classpath prefix or a standard URL prefix on the -location path will override the default type of `Resource` created to load the -definition. So this `FileSystemXmlApplicationContext`... +location path overrides the default type of `Resource` created to load the +definition. Consider the folowing example: [source,java,indent=0] [subs="verbatim,quotes"] @@ -422,23 +465,24 @@ definition. So this `FileSystemXmlApplicationContext`... new FileSystemXmlApplicationContext("classpath:conf/appContext.xml"); ---- -... will actually load its bean definitions from the classpath. However, it is still a +Using `FileSystemXmlApplicationContext` loads the bean definitions from the classpath. However, it is still a `FileSystemXmlApplicationContext`. If it is subsequently used as a `ResourceLoader`, any -unprefixed paths will still be treated as filesystem paths. +unprefixed paths are still treated as filesystem paths. + [[resources-app-ctx-classpathxml]] -==== Constructing ClassPathXmlApplicationContext instances - shortcuts +==== Constructing `ClassPathXmlApplicationContext` Instances -- Shortcuts The `ClassPathXmlApplicationContext` exposes a number of constructors to enable -convenient instantiation. The basic idea is that one supplies merely a string array -containing just the filenames of the XML files themselves (without the leading path -information), and one __also__ supplies a `Class`; the `ClassPathXmlApplicationContext` -will derive the path information from the supplied class. +convenient instantiation. The basic idea is that you can supply merely a string array +that contains only the filenames of the XML files themselves (without the leading path +information) and also supplies a `Class`. The `ClassPathXmlApplicationContext` +then derives the path information from the supplied class. -An example will hopefully make this clear. Consider a directory layout that looks like -this: +Consider the following directory layout: +==== [literal] [subs="verbatim,quotes"] ---- @@ -448,48 +492,53 @@ com/ daos.xml MessengerService.class ---- +==== -A `ClassPathXmlApplicationContext` instance composed of the beans defined in the -`'services.xml'` and `'daos.xml'` could be instantiated like so... +The following example shows how a `ClassPathXmlApplicationContext` instance composed of the beans defined in +files named `services.xml` and `daos.xml` (which are on the classpath) can be instantiated: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- ApplicationContext ctx = new ClassPathXmlApplicationContext( new String[] {"services.xml", "daos.xml"}, MessengerService.class); ---- +==== -Please do consult the `ClassPathXmlApplicationContext` javadocs for details +See the {api-spring-framework}/jca/context/SpringContextResourceAdapter.html[`ClassPathXmlApplicationContext` Javadoc] for details on the various constructors. [[resources-app-ctx-wildcards-in-resource-paths]] -=== Wildcards in application context constructor resource paths +=== Wildcards in Application Context Constructor Resource Paths -The resource paths in application context constructor values may be a simple path (as -shown above) which has a one-to-one mapping to a target Resource, or alternately may -contain the special "classpath*:" prefix and/or internal Ant-style regular expressions -(matched using Spring's `PathMatcher` utility). Both of the latter are effectively -wildcards +The resource paths in application context constructor values may be simple paths (as +shown earlier), each of which has a one-to-one mapping to a target `Resource` or, alternately, may +contain the special "classpath*:" prefix or internal Ant-style regular expressions +(matched by using Spring's `PathMatcher` utility). Both of the latter are effectively +wildcards. -One use for this mechanism is when doing component-style application assembly. All -components can 'publish' context definition fragments to a well-known location path, and -when the final application context is created using the same path prefixed via -`classpath*:`, all component fragments will be picked up automatically. +One use for this mechanism is when you need to do component-style application assembly. All +components can 'publish' context definition fragments to a well-known location path, and, +when the final application context is created using the same path prefixed with +`classpath*:`, all component fragments are automatically picked up. -Note that this wildcarding is specific to use of resource paths in application context -constructors (or when using the `PathMatcher` utility class hierarchy directly), and is +Note that this wildcarding is specific to the use of resource paths in application context +constructors (or when you use the `PathMatcher` utility class hierarchy directly) and is resolved at construction time. It has nothing to do with the `Resource` type itself. -It's not possible to use the `classpath*:` prefix to construct an actual `Resource`, as +You cannot use the `classpath*:` prefix to construct an actual `Resource`, as a resource points to just one resource at a time. + [[resources-app-ctx-ant-patterns-in-paths]] ==== Ant-style Patterns -When the path location contains an Ant-style pattern, for example: +Path locations can contain Ant-style patterns, as the following example shows: +==== [literal] [subs="verbatim"] ---- @@ -498,101 +547,103 @@ com/mycompany/**/applicationContext.xml file:C:/some/path/*-context.xml classpath:com/mycompany/**/applicationContext.xml ---- +==== -The resolver follows a more complex but defined procedure to try to resolve the -wildcard. It produces a Resource for the path up to the last non-wildcard segment and +When the path location contains an Ant-style pattern, the resolver follows a more complex procedure to try to resolve the +wildcard. It produces a `Resource` for the path up to the last non-wildcard segment and obtains a URL from it. If this URL is not a `jar:` URL or container-specific variant -(e.g. `zip:` in WebLogic, `wsjar` in WebSphere, etc.), then a `java.io.File` is +(such as `zip:` in WebLogic, `wsjar` in WebSphere, and so on), a `java.io.File` is obtained from it and used to resolve the wildcard by traversing the filesystem. In the case of a jar URL, the resolver either gets a `java.net.JarURLConnection` from it or manually parses the jar URL and then traverses the contents of the jar file to resolve the wildcards. [[resources-app-ctx-portability]] -===== Implications on portability +===== Implications on Portability -If the specified path is already a file URL (either explicitly, or implicitly because -the base `ResourceLoader` is a filesystem one), then wildcarding is guaranteed to work in +If the specified path is already a file URL (either implicitly because +the base `ResourceLoader` is a filesystem one or explicitly), wildcarding is guaranteed to work in a completely portable fashion. -If the specified path is a classpath location, then the resolver must obtain the last -non-wildcard path segment URL via a `Classloader.getResource()` call. Since this is just -a node of the path (not the file at the end) it is actually undefined (in the -`ClassLoader` javadocs) exactly what sort of a URL is returned in this case. In -practice, it is always a `java.io.File` representing the directory, where the classpath -resource resolves to a filesystem location, or a jar URL of some sort, where the -classpath resource resolves to a jar location. Still, there is a portability concern on +If the specified path is a classpath location, the resolver must obtain the last +non-wildcard path segment URL by making a `Classloader.getResource()` call. Since this is just +a node of the path (not the file at the end), it is actually undefined (in the +`ClassLoader` Javadoc) exactly what sort of a URL is returned in this case. In +practice, it is always a `java.io.File` representing the directory (where the classpath +resource resolves to a filesystem location) or a jar URL of some sort w(here the +classpath resource resolves to a jar location). Still, there is a portability concern on this operation. If a jar URL is obtained for the last non-wildcard segment, the resolver must be able to -get a `java.net.JarURLConnection` from it, or manually parse the jar URL, to be able to -walk the contents of the jar, and resolve the wildcard. This will work in most -environments, but will fail in others, and it is strongly recommended that the wildcard +get a `java.net.JarURLConnection` from it or manually parse the jar URL, to be able to +walk the contents of the jar and resolve the wildcard. This does work in most +environments but fails in others, and we strongly recommend that the wildcard resolution of resources coming from jars be thoroughly tested in your specific environment before you rely on it. + [[resources-classpath-wildcards]] -==== The classpath*: prefix +==== The `classpath*:` Prefix When constructing an XML-based application context, a location string may use the -special `classpath*:` prefix: +special `classpath*:` prefix, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml"); ---- +==== This special prefix specifies that all classpath resources that match the given name -must be obtained (internally, this essentially happens via a -`ClassLoader.getResources(...)` call), and then merged to form the final application +must be obtained (internally, this essentially happens through a call to +`ClassLoader.getResources(...)`) and then merged to form the final application context definition. -[NOTE] -==== -The wildcard classpath relies on the `getResources()` method of the underlying +NOTE: The wildcard classpath relies on the `getResources()` method of the underlying classloader. As most application servers nowadays supply their own classloader -implementation, the behavior might differ especially when dealing with jar files. A +implementation, the behavior might differ, especially when dealing with jar files. A simple test to check if `classpath*` works is to use the classloader to load a file from within a jar on the classpath: `getClass().getClassLoader().getResources("")`. Try this test with files that have the same name but are placed inside two different locations. In case an inappropriate result is returned, check the application server documentation for settings that might affect the classloader behavior. -==== -The `classpath*:` prefix can also be combined with a `PathMatcher` pattern in the -rest of the location path, for example `classpath*:META-INF/*-beans.xml`. In this -case, the resolution strategy is fairly simple: a `ClassLoader.getResources()` call is +You can also combine the `classpath*:` prefix with a `PathMatcher` pattern in the +rest of the location path (for example, `classpath*:META-INF/*-beans.xml`). In this +case, the resolution strategy is fairly simple: A `ClassLoader.getResources()` call is used on the last non-wildcard path segment to get all the matching resources in the -class loader hierarchy, and then off each resource the same PathMatcher resolution -strategy described above is used for the wildcard subpath. +class loader hierarchy and then, off each resource, the same `PathMatcher` resolution +strategy described earlier is used for the wildcard subpath. + [[resources-wildcards-in-path-other-stuff]] -==== Other notes relating to wildcards +==== Other Notes Relating to Wildcards -Please note that `classpath*:` when combined with Ant-style patterns will only work +Note that `classpath*:`, when combined with Ant-style patterns, only works reliably with at least one root directory before the pattern starts, unless the actual -target files reside in the file system. This means that a pattern like +target files reside in the file system. This means that a pattern such as `classpath*:*.xml` might not retrieve files from the root of jar files but rather only from the root of expanded directories. Spring's ability to retrieve classpath entries originates from the JDK's -`ClassLoader.getResources()` method which only returns file system locations for a -passed-in empty string (indicating potential roots to search). Spring evaluates -`URLClassLoader` runtime configuration and the "java.class.path" manifest in jar files -as well but this is not guaranteed to lead to portable behavior. +`ClassLoader.getResources()` method, which only returns file system locations for an +empty string (indicating potential roots to search). Spring evaluates +`URLClassLoader` runtime configuration and the `java.class.path` manifest in jar files +as well, but this is not guaranteed to lead to portable behavior. [NOTE] ==== The scanning of classpath packages requires the presence of corresponding directory -entries in the classpath. When you build JARs with Ant, make sure that you do __not__ +entries in the classpath. When you build JARs with Ant, do not activate the files-only switch of the JAR task. Also, classpath directories may not -get exposed based on security policies in some environments, e.g. standalone apps on -JDK 1.7.0_45 and higher (which requires 'Trusted-Library' setup in your manifests; see +get exposed based on security policies in some environments -- for example, stand-alone applications on +JDK 1.7.0_45 and higher (which requires 'Trusted-Library' to be set up in your manifests. See http://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources). On JDK 9's module path (Jigsaw), Spring's classpath scanning generally works as expected. @@ -602,15 +653,17 @@ avoiding the aforementioned portability problems with searching the jar file roo Ant-style patterns with `classpath:` resources are not guaranteed to find matching resources if the root package to search is available in multiple class path locations. -This is because a resource such as +Consider the following example of a resource location: +==== [literal] [subs="verbatim,quotes"] ---- com/mycompany/package1/service-context.xml ---- +==== -may be in only one location, but when a path such as +Now consider an Ant-style path that someone might use to try to find that file: [literal] [subs="verbatim,quotes"] @@ -618,29 +671,31 @@ may be in only one location, but when a path such as classpath:com/mycompany/**/service-context.xml ---- -is used to try to resolve it, the resolver will work off the (first) URL returned by -`getResource("com/mycompany")`;. If this base package node exists in multiple -classloader locations, the actual end resource may not be underneath. Therefore, -preferably, use " `classpath*:`" with the same Ant-style pattern in such a case, which -will search all class path locations that contain the root package. +Such a resource may be in only one location, but when a path such as the preceding example +is used to try to resolve it, the resolver works off the (first) URL returned by +`getResource("com/mycompany");`. If this base package node exists in multiple +classloader locations, the actual end resource may not be there. Therefore, in such a case +you should prefer using `classpath*:` with the same Ant-style pattern, which +searches all class path locations that contain the root package. [[resources-filesystemresource-caveats]] -=== FileSystemResource caveats +=== `FileSystemResource` Caveats A `FileSystemResource` that is not attached to a `FileSystemApplicationContext` (that -is, a `FileSystemApplicationContext` is not the actual `ResourceLoader`) will treat -absolute vs. relative paths as you would expect. Relative paths are relative to the +is, when a `FileSystemApplicationContext` is not the actual `ResourceLoader`) treats +absolute and relative paths as you would expect. Relative paths are relative to the current working directory, while absolute paths are relative to the root of the filesystem. For backwards compatibility (historical) reasons however, this changes when the `FileSystemApplicationContext` is the `ResourceLoader`. The -`FileSystemApplicationContext` simply forces all attached `FileSystemResource` instances +`FileSystemApplicationContext` forces all attached `FileSystemResource` instances to treat all location paths as relative, whether they start with a leading slash or not. -In practice, this means the following are equivalent: +In practice, this means the following examples are equivalent: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -654,10 +709,12 @@ In practice, this means the following are equivalent: ApplicationContext ctx = new FileSystemXmlApplicationContext("/conf/context.xml"); ---- +==== -As are the following: (Even though it would make sense for them to be different, as one -case is relative and the other absolute.) +The following exmaples are also equivalent (even though it would make sense for them to be different, as one +case is relative and the other absolute): +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -671,11 +728,14 @@ case is relative and the other absolute.) FileSystemXmlApplicationContext ctx = ...; ctx.getResource("/some/resource/path/myTemplate.txt"); ---- +==== -In practice, if true absolute filesystem paths are needed, it is better to forgo the use -of absolute paths with `FileSystemResource` / `FileSystemXmlApplicationContext`, and -just force the use of a `UrlResource`, by using the `file:` URL prefix. +In practice, if you need true absolute filesystem paths, you should avoid using +absolute paths with `FileSystemResource` or `FileSystemXmlApplicationContext` and +force the use of a `UrlResource` by using the `file:` URL prefix. The following examples +show how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -690,3 +750,4 @@ just force the use of a `UrlResource`, by using the `file:` URL prefix. ApplicationContext ctx = new FileSystemXmlApplicationContext("file:///conf/context.xml"); ---- +==== diff --git a/src/docs/asciidoc/core/core-validation.adoc b/src/docs/asciidoc/core/core-validation.adoc index 46a14c40e0b..2ad222cbe94 100644 --- a/src/docs/asciidoc/core/core-validation.adoc +++ b/src/docs/asciidoc/core/core-validation.adoc @@ -3,62 +3,58 @@ - -[[validation-introduction]] -== Introduction - -.JSR-303/JSR-349 Bean Validation -**** -Spring Framework 4.0 supports Bean Validation 1.0 (JSR-303) and Bean Validation 1.1 -(JSR-349) in terms of setup support, also adapting it to Spring's `Validator` interface. - -An application can choose to enable Bean Validation once globally, as described in -<>, and use it exclusively for all validation needs. - -An application can also register additional Spring `Validator` instances per -`DataBinder` instance, as described in <>. This may be useful for -plugging in validation logic without the use of annotations. -**** - There are pros and cons for considering validation as business logic, and Spring offers a design for validation (and data binding) that does not exclude either one of them. -Specifically validation should not be tied to the web tier, should be easy to localize -and it should be possible to plug in any validator available. Considering the above, +Specifically, validation should not be tied to the web tier and should be easy to localize, +and it should be possible to plug in any available validator. Considering these concerns, Spring has come up with a `Validator` interface that is both basic and eminently usable in every layer of an application. -Data binding is useful for allowing user input to be dynamically bound to the domain +Data binding is useful for letting user input be dynamically bound to the domain model of an application (or whatever objects you use to process user input). Spring -provides the so-called `DataBinder` to do exactly that. The `Validator` and the +provides the aptly named `DataBinder` to do exactly that. The `Validator` and the `DataBinder` make up the `validation` package, which is primarily used in but not limited to the MVC framework. The `BeanWrapper` is a fundamental concept in the Spring Framework and is used in a lot -of places. However, you probably will not have the need to use the `BeanWrapper` -directly. Because this is reference documentation however, we felt that some explanation -might be in order. We will explain the `BeanWrapper` in this chapter since, if you were -going to use it at all, you would most likely do so when trying to bind data to objects. +of places. However, you probably do not need to use the `BeanWrapper` +directly. Because this is reference documentation, however, we felt that some explanation +might be in order. We explain the `BeanWrapper` in this chapter, since, if you are +going to use it at all, you are most likely do so when trying to bind data to objects. -Spring's DataBinder and the lower-level BeanWrapper both use PropertyEditors to parse -and format property values. The `PropertyEditor` concept is part of the JavaBeans -specification, and is also explained in this chapter. Spring 3 introduces a -"core.convert" package that provides a general type conversion facility, as well as a -higher-level "format" package for formatting UI field values. These new packages may be -used as simpler alternatives to PropertyEditors, and will also be discussed in this +Spring's `DataBinder` and the lower-level `BeanWrapper` both use `PropertyEditorSupport` implementations to parse +and format property values. The `PropertyEditor` and `PropertyEditorSupport` interfaces are part of the JavaBeans +specification and are also explained in this chapter. Spring 3 introduced a +`core.convert` package that provides a general type conversion facility, as well as a +higher-level "`format`" package for formatting UI field values. You can use these packages +as simpler alternatives to `PropertyEditorSupport` implementations. They are also discussed in this chapter. +.JSR-303/JSR-349 Bean Validation +**** +As of version 4.0, Spring Frameworksupports Bean Validation 1.0 (JSR-303) and Bean Validation 1.1 +(JSR-349) for setup support and adapting them to Spring's `Validator` interface. + +An application can choose to enable Bean Validation once globally, as described in +<>, and use it exclusively for all validation needs. + +An application can also register additional Spring `Validator` instances for each +`DataBinder` instance, as described in <>. This may be useful for +plugging in validation logic without the use of annotations. +**** [[validator]] -== Validation using Spring's Validator interface +== Validation by Using Spring's Validator Interface Spring features a `Validator` interface that you can use to validate objects. The -`Validator` interface works using an `Errors` object so that while validating, +`Validator` interface works by using an `Errors` object so that, while validating, validators can report validation failures to the `Errors` object. -Let's consider a small data object: +Consider the following example of a small data object: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -70,24 +66,27 @@ Let's consider a small data object: // the usual getters and setters... } ---- +==== -We're going to provide validation behavior for the `Person` class by implementing the +The next example provides validation behavior for the `Person` class by implementing the following two methods of the `org.springframework.validation.Validator` interface: -* `supports(Class)` - Can this `Validator` validate instances of the supplied `Class`? -* `validate(Object, org.springframework.validation.Errors)` - validates the given object - and in case of validation errors, registers those with the given `Errors` object +* `supports(Class)`: Can this `Validator` validate instances of the supplied `Class`? +* `validate(Object, org.springframework.validation.Errors)`: Validates the given object + and, in case of validation errors, registers those with the given `Errors` object. Implementing a `Validator` is fairly straightforward, especially when you know of the -`ValidationUtils` helper class that the Spring Framework also provides. +`ValidationUtils` helper class that the Spring Framework also provides. The following +example implements `Validator` for `Person` instances: +==== [source,java,indent=0] [subs="verbatim"] ---- public class PersonValidator implements Validator { /** - * This Validator validates *just* Person instances + * This Validator validates *only* Person instances */ public boolean supports(Class clazz) { return Person.class.equals(clazz); @@ -104,23 +103,25 @@ Implementing a `Validator` is fairly straightforward, especially when you know o } } ---- +==== -As you can see, the `static` `rejectIfEmpty(..)` method on the `ValidationUtils` class -is used to reject the `'name'` property if it is `null` or the empty string. Have a look -at the `ValidationUtils` javadocs to see what functionality it provides besides the +The `static` `rejectIfEmpty(..)` method on the `ValidationUtils` class +is used to reject the `name` property if it is `null` or the empty string. See +at the {api-spring-framework}/validation/ValidationUtils.html[`ValidationUtils` Javadoc] to see what functionality it provides besides the example shown previously. While it is certainly possible to implement a single `Validator` class to validate each of the nested objects in a rich object, it may be better to encapsulate the validation logic for each nested class of object in its own `Validator` implementation. A simple -example of a __'rich'__ object would be a `Customer` that is composed of two `String` -properties (a first and second name) and a complex `Address` object. `Address` objects -may be used independently of `Customer` objects, and so a distinct `AddressValidator` +example of a "`rich`" object would be a `Customer` that is composed of two `String` +properties (a first and a second name) and a complex `Address` object. `Address` objects +may be used independently of `Customer` objects, so a distinct `AddressValidator` has been implemented. If you want your `CustomerValidator` to reuse the logic contained within the `AddressValidator` class without resorting to copy-and-paste, you can dependency-inject or instantiate an `AddressValidator` within your `CustomerValidator`, -and use it like so: +as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -160,37 +161,37 @@ and use it like so: } } ---- +==== -Validation errors are reported to the `Errors` object passed to the validator. In case -of Spring Web MVC you can use `` tag to inspect the error messages, but of -course you can also inspect the errors object yourself. More information about the -methods it offers can be found in the javadocs. - +Validation errors are reported to the `Errors` object passed to the validator. In the case +of Spring Web MVC, you can use the `` tag to inspect the error messages, but +you can also inspect the `Errors` object yourself. More information about the +methods it offers can be found in the {api-spring-framework}validation/Errors.html[Javadoc]. [[validation-conversion]] -== Resolving codes to error messages +== Resolving Codes to Error Messages -We've talked about databinding and validation. Outputting messages corresponding to -validation errors is the last thing we need to discuss. In the example we've shown -above, we rejected the `name` and the `age` field. If we're going to output the error -messages by using a `MessageSource`, we will do so using the error code we've given when +We covered databinding and validation. This section covers outputting messages that correspond to +validation errors. In the example shown in the <>, +we rejected the `name` and `age` fields. If we want to output the error +messages by using a `MessageSource`, we can do so using the error code we provide when rejecting the field ('name' and 'age' in this case). When you call (either directly, or -indirectly, using for example the `ValidationUtils` class) `rejectValue` or one of the -other `reject` methods from the `Errors` interface, the underlying implementation will -not only register the code you've passed in, but also a number of additional error -codes. What error codes it registers is determined by the `MessageCodesResolver` that is -used. By default, the `DefaultMessageCodesResolver` is used, which for example not only -registers a message with the code you gave, but also messages that include the field -name you passed to the reject method. So in case you reject a field using -`rejectValue("age", "too.darn.old")`, apart from the `too.darn.old` code, Spring will -also register `too.darn.old.age` and `too.darn.old.age.int` (so the first will include -the field name and the second will include the type of the field); this is done as a -convenience to aid developers in targeting error messages and suchlike. +indirectly, by using, for example, the `ValidationUtils` class) `rejectValue` or one of the +other `reject` methods from the `Errors` interface, the underlying implementation +not only registers the code you passed in but also registers a number of additional error +codes. The `MessageCodesResolver` determines which error codes the `Errors` interface registers. +By default, the `DefaultMessageCodesResolver` is used, which (for example) not only +registers a message with the code you gave but also registers messages that include the field +name you passed to the reject method. So, if you reject a field by using +`rejectValue("age", "too.darn.old")`, apart from the `too.darn.old` code, Spring +also registers `too.darn.old.age` and `too.darn.old.age.int` (the first includes +the field name and the second includes the type of the field). This is done as a +convenience to aid developers when targeting error messages. More information on the `MessageCodesResolver` and the default strategy can be found -online in the javadocs of +in the Javadoc of {api-spring-framework}/validation/MessageCodesResolver.html[`MessageCodesResolver`] and {api-spring-framework}/validation/DefaultMessageCodesResolver.html[`DefaultMessageCodesResolver`], @@ -198,42 +199,41 @@ respectively. - [[beans-beans]] -== Bean manipulation and the BeanWrapper +== Bean Manipulation and the `BeanWrapper` -The `org.springframework.beans` package adheres to the JavaBeans standard provided by -Oracle. A JavaBean is simply a class with a default no-argument constructor, which follows -a naming convention where (by way of an example) a property named `bingoMadness` would +The `org.springframework.beans` package adheres to the JavaBeans standard. +A JavaBean is a class with a default no-argument constructor and that follows +a naming convention where (for example) a property named `bingoMadness` would have a setter method `setBingoMadness(..)` and a getter method `getBingoMadness()`. For -more information about JavaBeans and the specification, please refer to Oracle's website ( -http://docs.oracle.com/javase/6/docs/api/java/beans/package-summary.html[javabeans]). +more information about JavaBeans and the specification, see +http://docs.oracle.com/javase/8/docs/api/java/beans/package-summary.html[javabeans]. One quite important class in the beans package is the `BeanWrapper` interface and its -corresponding implementation ( `BeanWrapperImpl`). As quoted from the javadocs, the +corresponding implementation (`BeanWrapperImpl`). As quoted from the Javadoc, the `BeanWrapper` offers functionality to set and get property values (individually or in -bulk), get property descriptors, and to query properties to determine if they are +bulk), get property descriptors, and query properties to determine if they are readable or writable. Also, the `BeanWrapper` offers support for nested properties, -enabling the setting of properties on sub-properties to an unlimited depth. Then, the -`BeanWrapper` supports the ability to add standard JavaBeans `PropertyChangeListeners` +enabling the setting of properties on sub-properties to an unlimited depth. The +`BeanWrapper` also supports the ability to add standard JavaBeans `PropertyChangeListeners` and `VetoableChangeListeners`, without the need for supporting code in the target class. -Last but not least, the `BeanWrapper` provides support for the setting of indexed -properties. The `BeanWrapper` usually isn't used by application code directly, but by +Last but not least, the `BeanWrapper` provides support for setting indexed +properties. The `BeanWrapper` usually is not used by application code directly but is used by the `DataBinder` and the `BeanFactory`. -The way the `BeanWrapper` works is partly indicated by its name: __it wraps a bean__ to -perform actions on that bean, like setting and retrieving properties. +The way the `BeanWrapper` works is partly indicated by its name: it wraps a bean to +perform actions on that bean, such as setting and retrieving properties. [[beans-beans-conventions]] -=== Setting and getting basic and nested properties +=== Setting and Getting Basic and Nested Properties -Setting and getting properties is done using the `setPropertyValue(s)` and -`getPropertyValue(s)` methods that both come with a couple of overloaded variants. -They're all described in more detail in the javadocs Spring comes with. What's important -to know is that there are a couple of conventions for indicating properties of an -object. A couple of examples: +Setting and getting properties is done by using the `setPropertyValue`, `setPropertyValues`, +`getPropertyValue`, and `getPropertyValues` methods that both come with a couple of overloaded variants. +Springs Javadoc describes them all in more detail. +The JavaBeans specification has conventions for indicating properties of an +object. The following table shows some examples of these conventions: [[beans-beans-conventions-properties-tbl]] .Examples of properties @@ -241,32 +241,31 @@ object. A couple of examples: | Expression| Explanation | `name` -| Indicates the property `name` corresponding to the methods `getName()` or `isName()` - and `setName(..)` +| Indicates the property `name` that corresponds to the `getName()` or `isName()` + and `setName(..)` methods. | `account.name` -| Indicates the nested property `name` of the property `account` corresponding e.g. to - the methods `getAccount().setName()` or `getAccount().getName()` +| Indicates the nested property `name` of the property `account` that corresponds to + (for example) the `getAccount().setName()` or `getAccount().getName()` methods. | `account[2]` -| Indicates the __third__ element of the indexed property `account`. Indexed properties - can be of type `array`, `list` or other __naturally ordered__ collection +| Indicates the _third_ element of the indexed property `account`. Indexed properties + can be of type `array`, `list`, or other naturally ordered collection. | `account[COMPANYNAME]` -| Indicates the value of the map entry indexed by the key __COMPANYNAME__ of the Map - property `account` +| Indicates the value of the map entry indexed by the `COMPANYNAME` key of the `account` `Map` + property. |=== -Below you'll find some examples of working with the `BeanWrapper` to get and set -properties. +(This next section is not vitally important to you if you do not plan to work with +the `BeanWrapper` directly. If you use only the `DataBinder` and the `BeanFactory` +and their default implementations, you should skip ahead to the <>.) -__(This next section is not vitally important to you if you're not planning to work with -the `BeanWrapper` directly. If you're just using the `DataBinder` and the `BeanFactory` -and their out-of-the-box implementation, you should skip ahead to the section about -`PropertyEditors`.)__ - -Consider the following two classes: +The following two example classess use the `BeanWrapper` to get and set +properties: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -319,10 +318,12 @@ Consider the following two classes: } } ---- +==== The following code snippets show some examples of how to retrieve and manipulate some of the properties of instantiated `Companies` and `Employees`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -341,154 +342,162 @@ the properties of instantiated `Companies` and `Employees`: // retrieving the salary of the managingDirector through the company Float salary = (Float) company.getPropertyValue("managingDirector.salary"); ---- +==== [[beans-beans-conversion]] -=== Built-in PropertyEditor implementations +=== Built-in `PropertyEditor` Implementations -Spring uses the concept of `PropertyEditors` to effect the conversion between an -`Object` and a `String`. If you think about it, it sometimes might be handy to be able +Spring uses the concept of a `PropertyEditor` to effect the conversion between an +`Object` and a `String`. It can be handy to represent properties in a different way than the object itself. For example, a `Date` -can be represented in a human readable way (as the `String` `'2007-14-09'`), while -we're still able to convert the human readable form back to the original date (or even -better: convert any date entered in a human readable form, back to `Date` objects). This -behavior can be achieved by __registering custom editors__, of type -`java.beans.PropertyEditor`. Registering custom editors on a `BeanWrapper` or -alternately in a specific IoC container as mentioned in the previous chapter, gives it -the knowledge of how to convert properties to the desired type. Read more about -`PropertyEditors` in the javadocs of the `java.beans` package provided by Oracle. +can be represented in a human readable way (as the `String`: `'2007-14-09'`), while +we can still convert the human readable form back to the original date (or, even +better, convert any date entered in a human readable form back to `Date` objects). This +behavior can be achieved by registering custom editors of type +`java.beans.PropertyEditor`. Registering custom editors on a `BeanWrapper` or, +alternatively, in a specific IoC container (as mentioned in the previous chapter), gives it +the knowledge of how to convert properties to the desired type. For more about +`PropertyEditor`, see https://docs.oracle.com/javase/8/docs/api/java/beans/package-summary.html[the Javadoc of the `java.beans` package from Oracle]. A couple of examples where property editing is used in Spring: -* __setting properties on beans__ is done using `PropertyEditors`. When mentioning - `java.lang.String` as the value of a property of some bean you're declaring in XML - file, Spring will (if the setter of the corresponding property has a - `Class`-parameter) use the `ClassEditor` to try to resolve the parameter to a `Class` +* Setting properties on beans is done by using `PropertyEditor` implementations. When you use + `java.lang.String` as the value of a property of some bean that you declare in an XML + file, Spring (if the setter of the corresponding property has a + `Class` parameter) uses `ClassEditor` to try to resolve the parameter to a `Class` object. -* __parsing HTTP request parameters__ in Spring's MVC framework is done using all kinds - of `PropertyEditors` that you can manually bind in all subclasses of the +* Parsing HTTP request parameters in Spring's MVC framework is done by using all kinds + of `PropertyEditor` implementations that you can manually bind in all subclasses of the `CommandController`. -Spring has a number of built-in `PropertyEditors` to make life easy. Each of those is -listed below and they are all located in the `org.springframework.beans.propertyeditors` -package. Most, but not all (as indicated below), are registered by default by -`BeanWrapperImpl`. Where the property editor is configurable in some fashion, you can of -course still register your own variant to override the default one: +Spring has a number of built-in `PropertyEditor` implementations to make life easy. +They are all located in the `org.springframework.beans.propertyeditors` +package. Most, (but not all, as indicated in the following table) are, by default, registered by +`BeanWrapperImpl`. Where the property editor is configurable in some fashion, you can +still register your own variant to override the default one. The following table describes +the various `PropertyEditor` implementations that Spring provides: [[beans-beans-property-editors-tbl]] -.Built-in PropertyEditors +.Built-in `PropertyEditor` Implementations +[cols="30%,70%"] |=== | Class| Explanation | `ByteArrayPropertyEditor` -| Editor for byte arrays. Strings will simply be converted to their corresponding byte +| Editor for byte arrays. Converts strings to their corresponding byte representations. Registered by default by `BeanWrapperImpl`. | `ClassEditor` -| Parses Strings representing classes to actual classes and the other way around. When a - class is not found, an `IllegalArgumentException` is thrown. Registered by default by +| Parses Strings that represent classes to actual classes and vice-versa. When a + class is not found, an `IllegalArgumentException` is thrown. By default, registered by `BeanWrapperImpl`. | `CustomBooleanEditor` -| Customizable property editor for `Boolean` properties. Registered by default by - `BeanWrapperImpl`, but, can be overridden by registering custom instance of it as +| Customizable property editor for `Boolean` properties. By default, registered by + `BeanWrapperImpl` but can be overridden by registering a custom instance of it as a custom editor. | `CustomCollectionEditor` -| Property editor for Collections, converting any source `Collection` to a given target +| Property editor for collections, converting any source `Collection` to a given target `Collection` type. | `CustomDateEditor` -| Customizable property editor for java.util.Date, supporting a custom DateFormat. NOT - registered by default. Must be user registered as needed with appropriate format. +| Customizable property editor for `java.util.Date`, supporting a custom `DateFormat`. NOT + registered by default. Must be user-registered with the appropriate format as needed. | `CustomNumberEditor` -| Customizable property editor for any Number subclass like `Integer`, `Long`, `Float`, - `Double`. Registered by default by `BeanWrapperImpl`, but can be overridden by - registering custom instance of it as a custom editor. +| Customizable property editor for any `Number` subclass, such as `Integer`, `Long`, `Float`, or + `Double`. By default, registered by `BeanWrapperImpl` but can be overridden by + registering a custom instance of it as a custom editor. | `FileEditor` -| Capable of resolving Strings to `java.io.File` objects. Registered by default by +| Resolves strings to `java.io.File` objects. By default, registered by `BeanWrapperImpl`. | `InputStreamEditor` -| One-way property editor, capable of taking a text string and producing (via an - intermediate `ResourceEditor` and `Resource`) an `InputStream`, so `InputStream` - properties may be directly set as Strings. Note that the default usage will not close - the `InputStream` for you! Registered by default by `BeanWrapperImpl`. +| One-way property editor that can take a string and produce (through an + intermediate `ResourceEditor` and `Resource`) an `InputStream` so that `InputStream` + properties may be directly set as strings. Note that the default usage does not close + the `InputStream` for you. By default, registered by `BeanWrapperImpl`. | `LocaleEditor` -| Capable of resolving Strings to `Locale` objects and vice versa (the String format is - [language]_[country]_[variant], which is the same thing the toString() method of - Locale provides). Registered by default by `BeanWrapperImpl`. +| Can resolve strings to `Locale` objects and vice-versa (the string format is + `[language]_[country]_[variant]`, same as the `toString()` method of + `Locale`). By default, registered by `BeanWrapperImpl`. | `PatternEditor` -| Capable of resolving Strings to `java.util.regex.Pattern` objects and vice versa. +| Can resolve strings to `java.util.regex.Pattern` objects and vice-versa. | `PropertiesEditor` -| Capable of converting Strings (formatted using the format as defined in the javadocs - of the `java.util.Properties` class) to `Properties` objects. Registered by default +| Can convert strings (formatted with the format defined in the Javadoc + of the `java.util.Properties` class) to `Properties` objects. By default, registered by `BeanWrapperImpl`. | `StringTrimmerEditor` -| Property editor that trims Strings. Optionally allows transforming an empty string - into a `null` value. NOT registered by default; must be user registered as needed. +| Property editor that trims strings. Optionally allows transforming an empty string + into a `null` value. NOT registered by default -- must be user-registered. | `URLEditor` -| Capable of resolving a String representation of a URL to an actual `URL` object. - Registered by default by `BeanWrapperImpl`. +| Can resolve a string representation of a URL to an actual `URL` object. + By default, registered by `BeanWrapperImpl`. |=== Spring uses the `java.beans.PropertyEditorManager` to set the search path for property editors that might be needed. The search path also includes `sun.bean.editors`, which includes `PropertyEditor` implementations for types such as `Font`, `Color`, and most of -the primitive types. Note also that the standard JavaBeans infrastructure will -automatically discover `PropertyEditor` classes (without you having to register them -explicitly) if they are in the same package as the class they handle, and have the same -name as that class, with `'Editor'` appended; for example, one could have the following -class and package structure, which would be sufficient for the `FooEditor` class to be -recognized and used as the `PropertyEditor` for `Foo`-typed properties. +the primitive types. Note also that the standard JavaBeans infrastructure +automatically discovers `PropertyEditor` classes (without you having to register them +explicitly) if they are in the same package as the class they handle and have the same +name as that class, with `Editor` appended. For example, one could have the following +class and package structure, which would be sufficient for the `SomethingEditor` class to be +recognized and used as the `PropertyEditor` for `Something`-typed properties. +==== [literal] [subs="verbatim,quotes"] ---- com chank pop - Foo - FooEditor // the PropertyEditor for the Foo class + Something + SomethingEditor // the PropertyEditor for the Something class ---- +==== Note that you can also use the standard `BeanInfo` JavaBeans mechanism here as well -(described -http://docs.oracle.com/javase/tutorial/javabeans/advanced/customization.html[in -not-amazing-detail here]). Find below an example of using the `BeanInfo` mechanism for -explicitly registering one or more `PropertyEditor` instances with the properties of an -associated class. +(described to some extent +http://docs.oracle.com/javase/tutorial/javabeans/advanced/customization.html[ +here]). The following example use the `BeanInfo` mechanism to +explicitly register one or more `PropertyEditor` instances with the properties of an +associated class: +==== [literal] [subs="verbatim,quotes"] ---- com chank pop - Foo - FooBeanInfo // the BeanInfo for the Foo class + Something + SomethingBeanInfo // the BeanInfo for the Something class ---- +==== -Here is the Java source code for the referenced `FooBeanInfo` class. This would -associate a `CustomNumberEditor` with the `age` property of the `Foo` class. +The following Java source code for the referenced `SomethingBeanInfo` class +associates a `CustomNumberEditor` with the `age` property of the `Something` class: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- - public class FooBeanInfo extends SimpleBeanInfo { + public class SomethingBeanInfo extends SimpleBeanInfo { public PropertyDescriptor[] getPropertyDescriptors() { try { final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true); - PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) { + PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Something.class) { public PropertyEditor createPropertyEditor(Object bean) { return numberPE; }; @@ -501,45 +510,47 @@ associate a `CustomNumberEditor` with the `age` property of the `Foo` class. } } ---- +==== [[beans-beans-conversion-customeditor-registration]] -==== Registering additional custom PropertyEditors +==== Registering Additional Custom `PropertyEditor` Implementations -When setting bean properties as a string value, a Spring IoC container ultimately uses -standard JavaBeans `PropertyEditors` to convert these Strings to the complex type of the -property. Spring pre-registers a number of custom `PropertyEditors` (for example, to -convert a classname expressed as a string into a real `Class` object). Additionally, -Java's standard JavaBeans `PropertyEditor` lookup mechanism allows a `PropertyEditor` -for a class simply to be named appropriately and placed in the same package as the class -it provides support for, to be found automatically. +When setting bean properties as string values, a Spring IoC container ultimately uses +standard JavaBeans `PropertyEditor` implementations to convert these strings to the complex type of the +property. Spring pre-registers a number of custom `PropertyEditor` implementations (for example, to +convert a class name expressed as a string into a `Class` object). Additionally, +Java's standard JavaBeans `PropertyEditor` lookup mechanism lets a `PropertyEditor` +for a class be named appropriately and placed in the same package as the class +for which it provides support, so that it can be found automatically. -If there is a need to register other custom `PropertyEditors`, there are several -mechanisms available. The most manual approach, which is not normally convenient or -recommended, is to simply use the `registerCustomEditor()` method of the +If there is a need to register other custom `PropertyEditors`, several mechanisms are +available. The most manual approach, which is not normally convenient or +recommended, is to use the `registerCustomEditor()` method of the `ConfigurableBeanFactory` interface, assuming you have a `BeanFactory` reference. -Another, slightly more convenient, mechanism is to use a special bean factory -post-processor called `CustomEditorConfigurer`. Although bean factory post-processors -can be used with `BeanFactory` implementations, the `CustomEditorConfigurer` has a -nested property setup, so it is strongly recommended that it is used with the -`ApplicationContext`, where it may be deployed in similar fashion to any other bean, and -automatically detected and applied. +Another (slightly more convenient) mechanism is to use a special bean factory +post-processor called `CustomEditorConfigurer`. Although you can use bean factory post-processors +with `BeanFactory` implementations, the `CustomEditorConfigurer` has a +nested property setup, so we strongly recommend that you use it with the +`ApplicationContext`, where you can deploy it in similar fashion to any other bean and +where it can be automatically detected and applied. Note that all bean factories and application contexts automatically use a number of -built-in property editors, through their use of something called a `BeanWrapper` to +built-in property editors, through their use a `BeanWrapper` to handle property conversions. The standard property editors that the `BeanWrapper` registers are listed in <>. Additionally, -`ApplicationContexts` also override or add an additional number of editors to handle +`ApplicationContexts` also override or add additional editors to handle resource lookups in a manner appropriate to the specific application context type. Standard JavaBeans `PropertyEditor` instances are used to convert property values expressed as strings to the actual complex type of the property. -`CustomEditorConfigurer`, a bean factory post-processor, may be used to conveniently add +You can use `CustomEditorConfigurer`, a bean factory post-processor, to conveniently add support for additional `PropertyEditor` instances to an `ApplicationContext`. -Consider a user class `ExoticType`, and another class `DependsOnExoticType` which needs +Consider the following example, which defines a user class called `ExoticType` and another class called `DependsOnExoticType`, which needs `ExoticType` set as a property: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -563,11 +574,13 @@ Consider a user class `ExoticType`, and another class `DependsOnExoticType` whic } } ---- +==== When things are properly set up, we want to be able to assign the type property as a -string, which a `PropertyEditor` will behind the scenes convert into an actual -`ExoticType` instance: +string, which a `PropertyEditor` converts into an actual +`ExoticType` instance. The following bean definition shows how to set up this relationship: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -575,9 +588,11 @@ string, which a `PropertyEditor` will behind the scenes convert into an actual ---- +==== -The `PropertyEditor` implementation could look similar to this: +The `PropertyEditor` implementation could look similar to the following: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -591,10 +606,12 @@ The `PropertyEditor` implementation could look similar to this: } } ---- +==== -Finally, we use `CustomEditorConfigurer` to register the new `PropertyEditor` with the +Finally, the following example shows how to use `CustomEditorConfigurer` to register the new `PropertyEditor` with the `ApplicationContext`, which will then be able to use it as needed: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -606,27 +623,30 @@ Finally, we use `CustomEditorConfigurer` to register the new `PropertyEditor` wi ---- +==== + + [[beans-beans-conversion-customeditor-registration-per]] -===== Using PropertyEditorRegistrars +===== Using `PropertyEditorRegistrar` Another mechanism for registering property editors with the Spring container is to create and use a `PropertyEditorRegistrar`. This interface is particularly useful when -you need to use the same set of property editors in several different situations: write -a corresponding registrar and reuse that in each case. `PropertyEditorRegistrars` work +you need to use the same set of property editors in several different situations. You can write +a corresponding registrar and reuse it in each case. `PropertyEditorRegistrar` instances work in conjunction with an interface called `PropertyEditorRegistry`, an interface that is -implemented by the Spring `BeanWrapper` (and `DataBinder`). `PropertyEditorRegistrars` -are particularly convenient when used in conjunction with the `CustomEditorConfigurer` -(introduced <>), which exposes a -property called `setPropertyEditorRegistrars(..)`: `PropertyEditorRegistrars` added to a +implemented by the Spring `BeanWrapper` (and `DataBinder`). `PropertyEditorRegistrar` instances +are particularly convenient when used in conjunction with `CustomEditorConfigurer` +(described <>), which exposes a +property called `setPropertyEditorRegistrars(..)`. `PropertyEditorRegistrar` instances added to a `CustomEditorConfigurer` in this fashion can easily be shared with `DataBinder` and -Spring MVC `Controllers`. Furthermore, it avoids the need for synchronization on custom -editors: a `PropertyEditorRegistrar` is expected to create fresh `PropertyEditor` +Spring MVC controllers. Furthermore, it avoids the need for synchronization on custom +editors: A `PropertyEditorRegistrar` is expected to create fresh `PropertyEditor` instances for each bean creation attempt. -Using a `PropertyEditorRegistrar` is perhaps best illustrated with an example. First -off, you need to create your own `PropertyEditorRegistrar` implementation: +The following example shows how to create your own `PropertyEditorRegistrar` implementation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -643,14 +663,16 @@ off, you need to create your own `PropertyEditorRegistrar` implementation: } } ---- +==== See also the `org.springframework.beans.support.ResourceEditorRegistrar` for an example `PropertyEditorRegistrar` implementation. Notice how in its implementation of the -`registerCustomEditors(..)` method it creates new instances of each property editor. +`registerCustomEditors(..)` method ,it creates new instances of each property editor. -Next we configure a `CustomEditorConfigurer` and inject an instance of our +The next example shows how to configure a `CustomEditorConfigurer` and inject an instance of our `CustomPropertyEditorRegistrar` into it: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -665,13 +687,15 @@ Next we configure a `CustomEditorConfigurer` and inject an instance of our ---- +==== -Finally, and in a bit of a departure from the focus of this chapter, for those of you -using <>, using `PropertyEditorRegistrars` in +Finally (and in a bit of a departure from the focus of this chapter for those of you +using <>), using `PropertyEditorRegistrars` in conjunction with data-binding `Controllers` (such as `SimpleFormController`) can be very -convenient. Find below an example of using a `PropertyEditorRegistrar` in the +convenient. The following example uses a `PropertyEditorRegistrar` in the implementation of an `initBinder(..)` method: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -691,23 +715,23 @@ implementation of an `initBinder(..)` method: // other methods to do with registering a User } ---- +==== This style of `PropertyEditor` registration can lead to concise code (the implementation -of `initBinder(..)` is just one line long!), and allows common `PropertyEditor` -registration code to be encapsulated in a class and then shared amongst as many +of `initBinder(..)` is only one line long) and lets common `PropertyEditor` +registration code be encapsulated in a class and then shared amongst as many `Controllers` as needed. - [[core-convert]] == Spring Type Conversion -Spring 3 introduces a `core.convert` package that provides a general type conversion -system. The system defines an SPI to implement type conversion logic, as well as an API -to execute type conversions at runtime. Within a Spring container, this system can be -used as an alternative to PropertyEditors to convert externalized bean property value -strings to required property types. The public API may also be used anywhere in your +Spring 3 introduced a `core.convert` package that provides a general type conversion +system. The system defines an SPI to implement type conversion logic and an API +to perform type conversions at runtime. Within a Spring container, you can use this system +as an alternative to `PropertyEditor` implementations to convert externalized bean property value +strings to the required property types. You can also use the public API anywhere in your application where type conversion is needed. @@ -715,8 +739,10 @@ application where type conversion is needed. [[core-convert-Converter-API]] === Converter SPI -The SPI to implement type conversion logic is simple and strongly typed: +The SPI to implement type conversion logic is simple and strongly typed, as the following +interface definition shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -727,22 +753,24 @@ The SPI to implement type conversion logic is simple and strongly typed: T convert(S source); } ---- +==== -To create your own converter, simply implement the interface above. Parameterize `S` -as the type you are converting from, and `T` as the type you are converting to. Such a -converter can also be applied transparently if a collection or array of `S` needs to be -converted to an array or collection of `T`, provided that a delegating array/collection +To create your own converter, implement the `Converter` interface and parameterize `S` +as the type you are converting from and `T` as the type you are converting to. You can also transparently apply such a +converter if a collection or array of `S` needs to be +converted to an array or collection of `T`, provided that a delegating array or collection converter has been registered as well (which `DefaultConversionService` does by default). -For each call to `convert(S)`, the source argument is guaranteed to be NOT null. Your -Converter may throw any unchecked exception if conversion fails; specifically, an -`IllegalArgumentException` should be thrown to report an invalid source value. +For each call to `convert(S)`, the source argument is guaranteed to not be null. Your +`Converter` may throw any unchecked exception if conversion fails. Specifically, it should throw an +`IllegalArgumentException` to report an invalid source value. Take care to ensure that your `Converter` implementation is thread-safe. Several converter implementations are provided in the `core.convert.support` package as -a convenience. These include converters from Strings to Numbers and other common types. -Consider `StringToInteger` as an example for a typical `Converter` implementation: +a convenience. These include converters from strings to numbers and other common types. +The following listing shows the `StringToInteger` class, which is a typical `Converter` implementation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -755,16 +783,18 @@ Consider `StringToInteger` as an example for a typical `Converter` implementatio } } ---- +==== [[core-convert-ConverterFactory-SPI]] -=== ConverterFactory +=== Using `ConverterFactory` -When you need to centralize the conversion logic for an entire class hierarchy, for -example, when converting from String to java.lang.Enum objects, implement -`ConverterFactory`: +When you need to centralize the conversion logic for an entire class hierarchy (for +example, when converting from String to java.lang.Enum objects), you can implement +`ConverterFactory`, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -775,13 +805,15 @@ example, when converting from String to java.lang.Enum objects, implement Converter getConverter(Class targetType); } ---- +==== Parameterize S to be the type you are converting from and R to be the base type defining the __range__ of classes you can convert to. Then implement getConverter(Class), where T is a subclass of R. -Consider the `StringToEnum` ConverterFactory as an example: +Consider the `StringToEnum` `ConverterFactory` as an example: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -807,19 +839,22 @@ Consider the `StringToEnum` ConverterFactory as an example: } } ---- +==== [[core-convert-GenericConverter-SPI]] -=== GenericConverter +=== Using `GenericConverter` -When you require a sophisticated Converter implementation, consider the GenericConverter -interface. With a more flexible but less strongly typed signature, a GenericConverter +When you require a sophisticated `Converter` implementation, consider using the `GenericConverter` +interface. With a more flexible but less strongly typed signature than `Converter`, a `GenericConverter` supports converting between multiple source and target types. In addition, a -GenericConverter makes available source and target field context you can use when -implementing your conversion logic. Such context allows a type conversion to be driven -by a field annotation, or generic information declared on a field signature. +`GenericConverter` makes available source and target field context that you can use when +you implement your conversion logic. Such context lets a type conversion be driven +by a field annotation or by generic information declared on a field signature. The +following listing shows the interface definition of `GenericConverter`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -832,36 +867,36 @@ by a field annotation, or generic information declared on a field signature. Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType); } ---- - -To implement a GenericConverter, have getConvertibleTypes() return the supported -source->target type pairs. Then implement convert(Object, TypeDescriptor, -TypeDescriptor) to implement your conversion logic. The source TypeDescriptor provides -access to the source field holding the value being converted. The target TypeDescriptor -provides access to the target field where the converted value will be set. - -A good example of a GenericConverter is a converter that converts between a Java Array -and a Collection. Such an ArrayToCollectionConverter introspects the field that declares -the target Collection type to resolve the Collection's element type. This allows each -element in the source array to be converted to the Collection element type before the -Collection is set on the target field. - -[NOTE] -==== -Because GenericConverter is a more complex SPI interface, only use it when you need it. -Favor Converter or ConverterFactory for basic type conversion needs. ==== +To implement a `GenericConverter`, have `getConvertibleTypes()` return the supported +source->target type pairs. Then implement `convert(Object, TypeDescriptor, +TypeDescriptor)` to contain your conversion logic. The source `TypeDescriptor` provides +access to the source field that holds the value being converted. The target `TypeDescriptor` +provides access to the target field where the converted value is to be set. + +A good example of a `GenericConverter` is a converter that converts between a Java array +and a collection. Such an `ArrayToCollectionConverter` introspects the field that declares +the target collection type to resolve the collection's element type. This lets each +element in the source array be converted to the collection element type before the +collection is set on the target field. + +NOTE: Because `GenericConverter` is a more complex SPI interface, you should use it only when you need it. +Favor `Converter` or `ConverterFactory` for basic type conversion needs. + + [[core-convert-ConditionalGenericConverter-SPI]] -==== ConditionalGenericConverter +==== Using `ConditionalGenericConverter` -Sometimes you only want a `Converter` to execute if a specific condition holds true. For -example, you might only want to execute a `Converter` if a specific annotation is present -on the target field. Or you might only want to execute a `Converter` if a specific method, -such as a `static valueOf` method, is defined on the target class. +Sometimes, you want a `Converter` to run only if a specific condition holds true. For +example, you might want to run a `Converter` only if a specific annotation is present +on the target field, or you might want to run a `Converter` only if a specific method +(such as a `static valueOf` method) is defined on the target class. `ConditionalGenericConverter` is the union of the `GenericConverter` and -`ConditionalConverter` interfaces that allows you to define such custom matching criteria: +`ConditionalConverter` interfaces that lets you define such custom matching criteria: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -873,21 +908,23 @@ such as a `static valueOf` method, is defined on the target class. public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter { } ---- +==== -A good example of a `ConditionalGenericConverter` is an EntityConverter that converts -between an persistent entity identifier and an entity reference. Such a EntityConverter -might only match if the target entity type declares a static finder method e.g. -`findAccount(Long)`. You would perform such a finder method check in the implementation of +A good example of a `ConditionalGenericConverter` is an `EntityConverter` that converts +between a persistent entity identifier and an entity reference. Such an `EntityConverter` +might match only if the target entity type declares a static finder method (for example, +`findAccount(Long)`). You might perform such a finder method check in the implementation of `matches(TypeDescriptor, TypeDescriptor)`. [[core-convert-ConversionService-API]] -=== ConversionService API +=== The `ConversionService` API -The ConversionService defines a unified API for executing type conversion logic at -runtime. Converters are often executed behind this facade interface: +`ConversionService` defines a unified API for executing type conversion logic at +runtime. Converters are often executed behind the following facade interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -905,49 +942,50 @@ runtime. Converters are often executed behind this facade interface: } ---- +==== -Most ConversionService implementations also implement `ConverterRegistry`, which -provides an SPI for registering converters. Internally, a ConversionService +Most `ConversionService` implementations also implement `ConverterRegistry`, which +provides an SPI for registering converters. Internally, a `ConversionService` implementation delegates to its registered converters to carry out type conversion logic. -A robust ConversionService implementation is provided in the `core.convert.support` +A robust `ConversionService` implementation is provided in the `core.convert.support` package. `GenericConversionService` is the general-purpose implementation suitable for use in most environments. `ConversionServiceFactory` provides a convenient factory for -creating common ConversionService configurations. +creating common `ConversionService` configurations. [[core-convert-Spring-config]] -=== Configuring a ConversionService +=== Configuring a `ConversionService` -A ConversionService is a stateless object designed to be instantiated at application -startup, then shared between multiple threads. In a Spring application, you typically -configure a ConversionService instance per Spring container (or ApplicationContext). -That ConversionService will be picked up by Spring and then used whenever a type -conversion needs to be performed by the framework. You may also inject this -ConversionService into any of your beans and invoke it directly. +A `ConversionService` is a stateless object designed to be instantiated at application +startup and then shared between multiple threads. In a Spring application, you typically +configure a `ConversionService` instance for each Spring container (or `ApplicationContext`). +Spring picks up that `ConversionService` and uses it whenever a type +conversion needs to be performed by the framework. You can also inject this +`ConversionService` into any of your beans and invoke it directly. -[NOTE] -==== -If no ConversionService is registered with Spring, the original PropertyEditor-based +NOTE: If no `ConversionService` is registered with Spring, the original `PropertyEditor`-based system is used. + +To register a default `ConversionService` with Spring, add the following bean definition +with an `id` of `conversionService`: + ==== - -To register a default ConversionService with Spring, add the following bean definition -with id `conversionService`: - [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -A default ConversionService can convert between strings, numbers, enums, collections, +A default `ConversionService` can convert between strings, numbers, enums, collections, maps, and other common types. To supplement or override the default converters with your -own custom converter(s), set the `converters` property. Property values may implement -either of the Converter, ConverterFactory, or GenericConverter interfaces. +own custom converters, set the `converters` property. Property values can implement +any of the `Converter`, `ConverterFactory`, or `GenericConverter` interfaces. +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -960,22 +998,24 @@ either of the Converter, ConverterFactory, or GenericConverter interfaces. ---- +==== -It is also common to use a ConversionService within a Spring MVC application. See +It is also common to use a `ConversionService` within a Spring MVC application. See <> in the Spring MVC chapter. -In certain situations you may wish to apply formatting during conversion. See +In certain situations, you may wish to apply formatting during conversion. See <> for details on using `FormattingConversionServiceFactoryBean`. [[core-convert-programmatic-usage]] -=== Using a ConversionService programmatically +=== Using a `ConversionService` Programmatically -To work with a ConversionService instance programmatically, simply inject a reference to -it like you would for any other bean: +To work with a `ConversionService` instance programmatically, you can inject a reference to +it like you would for any other bean. The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -992,14 +1032,17 @@ it like you would for any other bean: } } ---- +==== -For most use cases, the `convert` method specifying the _targetType_ can be used but it -will not work with more complex types such as a collection of a parameterized element. -If you want to convert a `List` of `Integer` to a `List` of `String` programmatically, -for instance, you need to provide a formal definition of the source and target types. +For most use cases, you can use the `convert` method that specifies the `targetType`, but it +does not work with more complex types, such as a collection of a parameterized element. +For example, if you want to convert a `List` of `Integer` to a `List` of `String` programmatically, +you need to provide a formal definition of the source and target types. -Fortunately, `TypeDescriptor` provides various options to make that straightforward: +Fortunately, `TypeDescriptor` provides various options to make doing so straightforward, +as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1010,53 +1053,55 @@ Fortunately, `TypeDescriptor` provides various options to make that straightforw TypeDescriptor.forObject(input), // List type descriptor TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class))); ---- +==== -Note that `DefaultConversionService` registers converters automatically which are +Note that `DefaultConversionService` automatically registers converters that are appropriate for most environments. This includes collection converters, scalar -converters, and also basic `Object` to `String` converters. The same converters can -be registered with any `ConverterRegistry` using the _static_ `addDefaultConverters` +converters, and basic `Object`-to-`String` converters. You can register the same converters +with any `ConverterRegistry` by using the static `addDefaultConverters` method on the `DefaultConversionService` class. -Converters for value types will be reused for arrays and collections, so there is +Converters for value types are reused for arrays and collections, so there is no need to create a specific converter to convert from a `Collection` of `S` to a `Collection` of `T`, assuming that standard collection handling is appropriate. - [[format]] == Spring Field Formatting As discussed in the previous section, <> is a -general-purpose type conversion system. It provides a unified ConversionService API as -well as a strongly-typed Converter SPI for implementing conversion logic from one type -to another. A Spring Container uses this system to bind bean property values. In -addition, both the Spring Expression Language (SpEL) and DataBinder use this system to +general-purpose type conversion system. It provides a unified `ConversionService` API as +well as a strongly typed `Converter` SPI for implementing conversion logic from one type +to another. A Spring container uses this system to bind bean property values. In +addition, both the Spring Expression Language (SpEL) and `DataBinder` use this system to bind field values. For example, when SpEL needs to coerce a `Short` to a `Long` to -complete an `expression.setValue(Object bean, Object value)` attempt, the core.convert +complete an `expression.setValue(Object bean, Object value)` attempt, the `core.convert` system performs the coercion. -Now consider the type conversion requirements of a typical client environment such as a -web or desktop application. In such environments, you typically convert __from String__ -to support the client postback process, as well as back __to String__ to support the -view rendering process. In addition, you often need to localize String values. The more -general __core.convert__ Converter SPI does not address such __formatting__ requirements -directly. To directly address them, Spring 3 introduces a convenient Formatter SPI that -provides a simple and robust alternative to PropertyEditors for client environments. +Now consider the type conversion requirements of a typical client environment, such as a +web or desktop application. In such environments, you typically convert from `String` +to support the client postback process, as well as back to `String` to support the +view rendering process. In addition, you often need to localize `String` values. The more +general `core.convert` `Converter` SPI does not address such formatting requirements +directly. To directly address them, Spring 3 introduced a convenient `Formatter` SPI that +provides a simple and robust alternative to `PropertyEditor` implementations for client environments. -In general, use the Converter SPI when you need to implement general-purpose type -conversion logic; for example, for converting between a java.util.Date and and -java.lang.Long. Use the Formatter SPI when you're working in a client environment, such -as a web application, and need to parse and print localized field values. The -ConversionService provides a unified type conversion API for both SPIs. +In general, you can use the `Converter` SPI when you need to implement general-purpose type +conversion logic -- for example, for converting between a `java.util.Date` and a +`java.lang.Long`. You can use the `Formatter` SPI when you work in a client environment (such +as a web application) and need to parse and print localized field values. The +`ConversionService` provides a unified type conversion API for both SPIs. [[format-Formatter-SPI]] -=== Formatter SPI +=== The `Formatter` SPI -The Formatter SPI to implement field formatting logic is simple and strongly typed: +The `Formatter` SPI to implement field formatting logic is simple and strongly typed. The +following listing shows the `Formatter` interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1065,9 +1110,12 @@ The Formatter SPI to implement field formatting logic is simple and strongly typ public interface Formatter extends Printer, Parser { } ---- +==== -Where Formatter extends from the Printer and Parser building-block interfaces: +`Formatter` extends from the `Printer` and `Parser` building-block interfaces. The +following listing shows the definitions of those two interfaces: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1087,24 +1135,26 @@ Where Formatter extends from the Printer and Parser building-block interfaces: T parse(String clientValue, Locale locale) throws ParseException; } ---- +==== -To create your own Formatter, simply implement the Formatter interface above. -Parameterize T to be the type of object you wish to format, for example, -`java.util.Date`. Implement the `print()` operation to print an instance of T for +To create your own `Formatter`, implement the `Formatter` interface shown earlier. +Parameterize `T` to be the type of object you wish to format -- for example, +`java.util.Date`. Implement the `print()` operation to print an instance of `T` for display in the client locale. Implement the `parse()` operation to parse an instance of -T from the formatted representation returned from the client locale. Your Formatter -should throw a ParseException or IllegalArgumentException if a parse attempt fails. Take -care to ensure your Formatter implementation is thread-safe. +`T` from the formatted representation returned from the client locale. Your `Formatter` +should throw a `ParseException` or an `IllegalArgumentException` if a parse attempt fails. Take +care to ensure that your `Formatter` implementation is thread-safe. -Several Formatter implementations are provided in `format` subpackages as a convenience. -The `number` package provides a `NumberStyleFormatter`, `CurrencyStyleFormatter`, and -`PercentStyleFormatter` to format `java.lang.Number` objects using a `java.text.NumberFormat`. +The `format` subpackages provide several `Formatter` implementations as a convenience. +The `number` package provides `NumberStyleFormatter`, `CurrencyStyleFormatter`, and +`PercentStyleFormatter` to format `java.lang.Number` objects that use a `java.text.NumberFormat`. The `datetime` package provides a `DateFormatter` to format `java.util.Date` objects with a `java.text.DateFormat`. The `datetime.joda` package provides comprehensive datetime formatting support based on the http://joda-time.sourceforge.net[Joda-Time library]. -Consider `DateFormatter` as an example `Formatter` implementation: +The following `DateFormatter` is an example `Formatter` implementation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1139,8 +1189,9 @@ Consider `DateFormatter` as an example `Formatter` implementation: } } ---- +==== -The Spring team welcomes community-driven `Formatter` contributions; see +The Spring team welcomes community-driven `Formatter` contributionsSee https://jira.spring.io/browse/SPR[jira.spring.io] to contribute. @@ -1148,9 +1199,11 @@ https://jira.spring.io/browse/SPR[jira.spring.io] to contribute. [[format-CustomFormatAnnotations]] === Annotation-driven Formatting -As you will see, field formatting can be configured by field type or annotation. To bind -an Annotation to a formatter, implement AnnotationFormatterFactory: +Field formatting can be configured by field type or annotation. To bind +an annotation to a `Formatter`, implement `AnnotationFormatterFactory`. The following +listing shows the definition of the `AnnotationFormatterFactory` interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1165,17 +1218,20 @@ an Annotation to a formatter, implement AnnotationFormatterFactory: Parser getParser(A annotation, Class fieldType); } ---- +==== -Parameterize A to be the field annotationType you wish to associate formatting logic -with, for example `org.springframework.format.annotation.DateTimeFormat`. Have -`getFieldTypes()` return the types of fields the annotation may be used on. Have -`getPrinter()` return a Printer to print the value of an annotated field. Have -`getParser()` return a Parser to parse a clientValue for an annotated field. +To create an implementation: +. Parameterize A to be the field `annotationType` with which you wish to associate +formatting logic -- for example `org.springframework.format.annotation.DateTimeFormat`. +. Have `getFieldTypes()` return the types of fields on which the annotation can be used. +. Have `getPrinter()` return a `Printer` to print the value of an annotated field. +. Have `getParser()` return a `Parser` to parse a `clientValue` for an annotated field. -The example AnnotationFormatterFactory implementation below binds the @NumberFormat -Annotation to a formatter. This annotation allows either a number style or pattern to be +The following example `AnnotationFormatterFactory` implementation binds the `@NumberFormat` +annotation to a formatter to let a number style or pattern be specified: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1212,9 +1268,12 @@ specified: } } ---- +==== -To trigger formatting, simply annotate fields with @NumberFormat: +To trigger formatting, you can annotate fields with @NumberFormat, as the following +example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1224,18 +1283,21 @@ To trigger formatting, simply annotate fields with @NumberFormat: private BigDecimal decimal; } ---- +==== + [[format-annotations-api]] ==== Format Annotation API A portable format annotation API exists in the `org.springframework.format.annotation` -package. Use @NumberFormat to format java.lang.Number fields. Use @DateTimeFormat to -format java.util.Date, java.util.Calendar, java.util.Long, or Joda-Time fields. +package. You can use `@NumberFormat` to format java.lang.Number fields and `@DateTimeFormat` to +format `java.util.Date`, `java.util.Calendar`, `java.util.Long`, or Joda-Time fields. -The example below uses @DateTimeFormat to format a java.util.Date as a ISO Date +The following example uses `@DateTimeFormat` to format a `java.util.Date` as an ISO Date (yyyy-MM-dd): +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1245,21 +1307,23 @@ The example below uses @DateTimeFormat to format a java.util.Date as a ISO Date private Date date; } ---- +==== [[format-FormatterRegistry-SPI]] -=== FormatterRegistry SPI +=== The `FormatterRegistry` SPI -The FormatterRegistry is an SPI for registering formatters and converters. -`FormattingConversionService` is an implementation of FormatterRegistry suitable for -most environments. This implementation may be configured programmatically or -declaratively as a Spring bean using `FormattingConversionServiceFactoryBean`. Because -this implementation also implements `ConversionService`, it can be directly configured -for use with Spring's DataBinder and the Spring Expression Language (SpEL). +The `FormatterRegistry` is an SPI for registering formatters and converters. +`FormattingConversionService` is an implementation of `FormatterRegistry` suitable for +most environments. You can programmatically or declaratively configure this implementation +as a Spring bean by using `FormattingConversionServiceFactoryBean`. Because +this implementation also implements `ConversionService`, you can directly configure it +for use with Spring's `DataBinder` and the Spring Expression Language (SpEL). -Review the FormatterRegistry SPI below: +The following listing shows the `FormatterRegistry` SPI: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1276,23 +1340,25 @@ Review the FormatterRegistry SPI below: void addFormatterForAnnotation(AnnotationFormatterFactory factory); } ---- +==== -As shown above, Formatters can be registered by fieldType or annotation. +As shown in the preceding listing, you can register formatters by field type or by annotation. -The FormatterRegistry SPI allows you to configure Formatting rules centrally, instead of -duplicating such configuration across your Controllers. For example, you might want to -enforce that all Date fields are formatted a certain way, or fields with a specific -annotation are formatted in a certain way. With a shared FormatterRegistry, you define -these rules once and they are applied whenever formatting is needed. +The `FormatterRegistry` SPI lets you configure formatting rules centrally, instead of +duplicating such configuration across your controllers. For example, you might want to +enforce that all date fields are formatted a certain way or that fields with a specific +annotation are formatted in a certain way. With a shared `FormatterRegistry`, you define +these rules once, and they are applied whenever formatting is needed. [[format-FormatterRegistrar-SPI]] -=== FormatterRegistrar SPI +=== The `FormatterRegistrar` SPI -The FormatterRegistrar is an SPI for registering formatters and converters through the -FormatterRegistry: +`FormatterRegistrar` is an SPI for registering formatters and converters through the +FormatterRegistry. The following listing shows its interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1303,12 +1369,13 @@ FormatterRegistry: void registerFormatters(FormatterRegistry registry); } ---- +==== -A FormatterRegistrar is useful when registering multiple related converters and -formatters for a given formatting category, such as Date formatting. It can also be -useful where declarative registration is insufficient. For example when a formatter -needs to be indexed under a specific field type different from its own or when -registering a Printer/Parser pair. The next section provides more information on +A `FormatterRegistrar` is useful when registering multiple related converters and +formatters for a given formatting category, such as date formatting. It can also be +useful where declarative registration is insufficient -- for example, when a formatter +needs to be indexed under a specific field type different from its own `` or when +registering a `Printer`/`Parser` pair. The next section provides more information on converter and formatter registration. @@ -1320,23 +1387,23 @@ See <> in the Spring - [[format-configuring-formatting-globaldatetimeformat]] -== Configuring a global date & time format +== Configuring a Global Date and Time Format By default, date and time fields that are not annotated with `@DateTimeFormat` are -converted from strings using the `DateFormat.SHORT` style. If you prefer, you can +converted from strings by using the `DateFormat.SHORT` style. If you prefer, you can change this by defining your own global format. -You will need to ensure that Spring does not register default formatters, and instead +To do so, you need to ensure that Spring does not register default formatters. Instead, you should register all formatters manually. Use the `org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar` or -`org.springframework.format.datetime.DateFormatterRegistrar` class depending on whether +`org.springframework.format.datetime.DateFormatterRegistrar` class, depending on whether you use the Joda-Time library. -For example, the following Java configuration will register a global ' `yyyyMMdd`' -format. This example does not depend on the Joda-Time library: +For example, the following Java configuration registers a global `yyyyMMdd` +format (this example does not depend on the Joda-Time library): +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1361,11 +1428,13 @@ format. This example does not depend on the Joda-Time library: } } ---- +==== -If you prefer XML based configuration you can use a -`FormattingConversionServiceFactoryBean`. Here is the same example, this time using Joda -Time: +If you prefer XML-based configuration, you can use a +`FormattingConversionServiceFactoryBean`. The following example shows how to do so (this time using Joda +Time): +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1397,19 +1466,17 @@ Time: ---- - -[NOTE] ==== -Joda-Time provides separate distinct types to represent `date`, `time` and `date-time` -values. The `dateFormatter`, `timeFormatter` and `dateTimeFormatter` properties of the + +NOTE: Joda-Time provides separate distinct types to represent `date`, `time`, and `date-time` +values. The `dateFormatter`, `timeFormatter`, and `dateTimeFormatter` properties of the `JodaTimeFormatterRegistrar` should be used to configure the different formats for each type. The `DateTimeFormatterFactoryBean` provides a convenient way to create formatters. -==== -If you are using Spring MVC remember to explicitly configure the conversion service that -is used. For Java based `@Configuration` this means extending the +NOTE: If you use Spring MVC, remember to explicitly configure the conversion service that +is used. For Java-based `@Configuration`, this means extending the `WebMvcConfigurationSupport` class and overriding the `mvcConversionService()` method. -For XML you should use the `'conversion-service'` attribute of the +For XML, you should use the `conversion-service` attribute of the `mvc:annotation-driven` element. See <> for details. @@ -1419,9 +1486,9 @@ See <> for details. [[validation-beanvalidation]] == Spring Validation -Spring 3 introduces several enhancements to its validation support. First, the JSR-303 -Bean Validation API is now fully supported. Second, when used programmatically, Spring's -DataBinder can now validate objects as well as bind to them. Third, Spring MVC now has +Spring 3 introduced several enhancements to its validation support. First, the JSR-303 +Bean Validation API is fully supported. Second, when used programmatically, Spring's +`DataBinder` can validate objects as well as bind to them. Third, Spring MVC has support for declaratively validating `@Controller` inputs. @@ -1430,12 +1497,13 @@ support for declaratively validating `@Controller` inputs. === Overview of the JSR-303 Bean Validation API JSR-303 standardizes validation constraint declaration and metadata for the Java -platform. Using this API, you annotate domain model properties with declarative -validation constraints and the runtime enforces them. There are a number of built-in -constraints you can take advantage of. You may also define your own custom constraints. +platform. By using this API, you annotate domain model properties with declarative +validation constraints and the runtime enforces them. You can use a number of built-in +constraints. You can also define your own custom constraints. -To illustrate, consider a simple PersonForm model with two properties: +Consider the following example, which shows a simple `PersonForm` model with two properties: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1444,9 +1512,12 @@ To illustrate, consider a simple PersonForm model with two properties: private int age; } ---- +==== -JSR-303 allows you to define declarative validation constraints against such properties: +JSR-303 lets you define declarative validation constraints against such properties, as the +following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1460,14 +1531,15 @@ JSR-303 allows you to define declarative validation constraints against such pro private int age; } ---- +==== -When an instance of this class is validated by a JSR-303 Validator, these constraints -will be enforced. +When a JSR-303 Validator validates an instance of this class, these constraints +are enforced. -For general information on JSR-303/JSR-349, see the http://beanvalidation.org/[Bean +For general information on JSR-303 and JSR-349, see the http://beanvalidation.org/[Bean Validation website]. For information on the specific capabilities of the default reference implementation, see the https://www.hibernate.org/412.html[Hibernate -Validator] documentation. To learn how to setup a Bean Validation provider as a Spring +Validator] documentation. To learn how to set up a bean validation provider as a Spring bean, keep reading. @@ -1476,22 +1548,25 @@ bean, keep reading. === Configuring a Bean Validation Provider Spring provides full support for the Bean Validation API. This includes convenient -support for bootstrapping a JSR-303/JSR-349 Bean Validation provider as a Spring bean. -This allows for a `javax.validation.ValidatorFactory` or `javax.validation.Validator` to -be injected wherever validation is needed in your application. +support for bootstrapping a JSR-303 or JSR-349 Bean Validation provider as a Spring bean. +This lets you inject a `javax.validation.ValidatorFactory` or `javax.validation.Validator` +wherever validation is needed in your application. -Use the `LocalValidatorFactoryBean` to configure a default Validator as a Spring bean: +You can use the `LocalValidatorFactoryBean` to configure a default Validator as a Spring bean, +as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -The basic configuration above will trigger Bean Validation to initialize using its -default bootstrap mechanism. A JSR-303/JSR-349 provider, such as Hibernate Validator, -is expected to be present in the classpath and will be detected automatically. +The basic configuration in the preceding example triggers bean validation to initialize by using its +default bootstrap mechanism. A JSR-303 or JSR-349 provider, such as the Hibernate Validator, +is expected to be present in the classpath and is automatically detected. [[validation-beanvalidation-spring-inject]] @@ -1499,12 +1574,13 @@ is expected to be present in the classpath and will be detected automatically. `LocalValidatorFactoryBean` implements both `javax.validation.ValidatorFactory` and `javax.validation.Validator`, as well as Spring's -`org.springframework.validation.Validator`. You may inject a reference to either of +`org.springframework.validation.Validator`. You can inject a reference to either of these interfaces into beans that need to invoke validation logic. -Inject a reference to `javax.validation.Validator` if you prefer to work with the Bean -Validation API directly: +You can inject a reference to `javax.validation.Validator` if you prefer to work with the Bean +Validation API directly, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1516,10 +1592,12 @@ Validation API directly: @Autowired private Validator validator; ---- +==== -Inject a reference to `org.springframework.validation.Validator` if your bean requires -the Spring Validation API: +You can inject a reference to `org.springframework.validation.Validator` if your bean requires +the Spring Validation API, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1532,26 +1610,33 @@ the Spring Validation API: private Validator validator; } ---- +==== + [[validation-beanvalidation-spring-constraints]] ==== Configuring Custom Constraints -Each Bean Validation constraint consists of two parts. First, a `@Constraint` annotation -that declares the constraint and its configurable properties. Second, an implementation +Each bean validation constraint consists of two parts: +* A `@Constraint` annotation +that declares the constraint and its configurable properties. +* An implementation of the `javax.validation.ConstraintValidator` interface that implements the constraint's -behavior. To associate a declaration with an implementation, each `@Constraint` annotation +behavior. + +To associate a declaration with an implementation, each `@Constraint` annotation references a corresponding `ConstraintValidator` implementation class. At runtime, a `ConstraintValidatorFactory` instantiates the referenced implementation when the constraint annotation is encountered in your domain model. By default, the `LocalValidatorFactoryBean` configures a `SpringConstraintValidatorFactory` -that uses Spring to create ConstraintValidator instances. This allows your custom -ConstraintValidators to benefit from dependency injection like any other Spring bean. +that uses Spring to create `ConstraintValidator` instances. This lets your custom +`ConstraintValidators` benefit from dependency injection like any other Spring bean. -Shown below is an example of a custom `@Constraint` declaration, followed by an associated +The following example shows a custom `@Constraint` declaration followed by an associated `ConstraintValidator` implementation that uses Spring for dependency injection: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1575,50 +1660,54 @@ Shown below is an example of a custom `@Constraint` declaration, followed by an ... } ---- +==== -As you can see, a ConstraintValidator implementation may have its dependencies -@Autowired like any other Spring bean. +As the preceding example shows, a `ConstraintValidator` implementation can have its dependencies +`@Autowired` as any other Spring bean. [[validation-beanvalidation-spring-method]] ==== Spring-driven Method Validation -The method validation feature supported by Bean Validation 1.1, and as a custom -extension also by Hibernate Validator 4.3, can be integrated into a Spring context -through a `MethodValidationPostProcessor` bean definition: +You can integrate the method validation feature supported by Bean Validation 1.1 (and, as a custom +extension, also by Hibernate Validator 4.3) into a Spring context +through a `MethodValidationPostProcessor` bean definition, as follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -In order to be eligible for Spring-driven method validation, all target classes need -to be annotated with Spring's `@Validated` annotation, optionally declaring the -validation groups to use. Check out the `MethodValidationPostProcessor` javadocs -for setup details with Hibernate Validator and Bean Validation 1.1 providers. +To be eligible for Spring-driven method validation, all target classes need +to be annotated with Spring's `@Validated` annotation. (Optionally, you can also declare the +validation groups to use.) See the {api-spring-framework}/validation/beanvalidation/MethodValidationPostProcessor.html[`MethodValidationPostProcessor` Javadoc] +for setup details with the Hibernate Validator and Bean Validation 1.1 providers. [[validation-beanvalidation-spring-other]] ==== Additional Configuration Options -The default `LocalValidatorFactoryBean` configuration should prove sufficient for most +The default `LocalValidatorFactoryBean` configuration suffices for most cases. There are a number of configuration options for various Bean Validation constructs, from message interpolation to traversal resolution. See the -`LocalValidatorFactoryBean` javadocs for more information on these options. +{api-spring-framework}/validation/beanvalidation/LocalValidatorFactoryBean.html[`LocalValidatorFactoryBean` Javadoc] for more information on these options. [[validation-binder]] -=== Configuring a DataBinder +=== Configuring a `DataBinder` -Since Spring 3, a DataBinder instance can be configured with a Validator. Once -configured, the Validator may be invoked by calling `binder.validate()`. Any validation -Errors are automatically added to the binder's BindingResult. +Since Spring 3, you can configure a `DataBinder` instance with a `Validator`. Once +configured, you can invoke the `Validator` by calling `binder.validate()`. Any validation +`Errors` are automatically added to the binder's `BindingResult`. -When working with the DataBinder programmatically, this can be used to invoke validation +The following example shows how to use a `DataBinder` programmatically to invoke validation logic after binding to a target object: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1635,10 +1724,11 @@ logic after binding to a target object: // get BindingResult that includes any validation errors BindingResult results = binder.getBindingResult(); ---- +==== -A DataBinder can also be configured with multiple `Validator` instances via +You can also configure a `DataBinder` with multiple `Validator` instances through `dataBinder.addValidators` and `dataBinder.replaceValidators`. This is useful when -combining globally configured Bean Validation with a Spring `Validator` configured +combining globally configured bean validation with a Spring `Validator` configured locally on a DataBinder instance. See <>.