diff --git a/src/docs/asciidoc/appendix.adoc b/src/docs/asciidoc/appendix.adoc deleted file mode 100644 index 5c9e4551117..00000000000 --- a/src/docs/asciidoc/appendix.adoc +++ /dev/null @@ -1,3974 +0,0 @@ -[[spring-appendices]] -= Appendices -:doc-root: https://docs.spring.io -:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework -:wiki-spring-framework: https://github.com/spring-projects/spring-framework/wiki -:toc: left -:toclevels: 2 -:docinfo1: - -[[annotation-programming-model]] -== Spring Annotation Programming Model -Spring's annotation programming model is documented in the -{wiki-spring-framework}/Spring-Annotation-Programming-Model[Spring Framework Wiki]. - - -[[classic-spring]] -== Classic Spring Usage -This appendix discusses some classic Spring usage patterns as a reference for developers -maintaining legacy Spring applications. These usage patterns no longer reflect the -recommended way of using these features, and the current recommended usage is covered in -the respective sections of the reference manual. - - - -[[classic-spring-orm]] -=== Classic ORM usage -This section documents the classic usage patterns that you might encounter in a legacy -Spring application. For the currently recommended usage patterns, please refer to the -<> chapter. - - - -[[classic-spring-hibernate]] -==== Hibernate -For the currently recommended usage patterns for Hibernate see -<>. - - -[[orm-hibernate-template]] -===== The HibernateTemplate - -The basic programming model for templating looks as follows, for methods that can be -part of any custom data access object or business service. There are no restrictions on -the implementation of the surrounding object at all, it just needs to provide a -Hibernate `SessionFactory`. It can get the latter from anywhere, but preferably as bean -reference from a Spring IoC container - via a simple `setSessionFactory(..)` bean -property setter. The following snippets show a DAO definition in a Spring container, -referencing the above defined `SessionFactory`, and an example for a DAO method -implementation. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - ----- - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class ProductDaoImpl implements ProductDao { - - private HibernateTemplate hibernateTemplate; - - public void setSessionFactory(SessionFactory sessionFactory) { - this.hibernateTemplate = new HibernateTemplate(sessionFactory); - } - - public Collection loadProductsByCategory(String category) throws DataAccessException { - return this.hibernateTemplate.find("from test.Product product where product.category=?", category); - } - } ----- - -The `HibernateTemplate` class provides many methods that mirror the methods exposed on -the Hibernate `Session` interface, in addition to a number of convenience methods such -as the one shown above. If you need access to the `Session` to invoke methods that are -not exposed on the `HibernateTemplate`, you can always drop down to a callback-based -approach like so. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class ProductDaoImpl implements ProductDao { - - private HibernateTemplate hibernateTemplate; - - public void setSessionFactory(SessionFactory sessionFactory) { - this.hibernateTemplate = new HibernateTemplate(sessionFactory); - } - - public Collection loadProductsByCategory(final String category) throws DataAccessException { - return this.hibernateTemplate.execute(new HibernateCallback() { - public Object doInHibernate(Session session) { - Criteria criteria = session.createCriteria(Product.class); - criteria.add(Expression.eq("category", category)); - criteria.setMaxResults(6); - return criteria.list(); - } - }; - } - - } ----- - -A callback implementation effectively can be used for any Hibernate data access. -`HibernateTemplate` will ensure that `Session` instances are properly opened and closed, -and automatically participate in transactions. The template instances are thread-safe -and reusable, they can thus be kept as instance variables of the surrounding class. For -simple single step actions like a single find, load, saveOrUpdate, or delete call, -`HibernateTemplate` offers alternative convenience methods that can replace such one -line callback implementations. Furthermore, Spring provides a convenient -`HibernateDaoSupport` base class that provides a `setSessionFactory(..)` method for -receiving a `SessionFactory`, and `getSessionFactory()` and `getHibernateTemplate()` for -use by subclasses. In combination, this allows for very simple DAO implementations for -typical requirements: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao { - - public Collection loadProductsByCategory(String category) throws DataAccessException { - return this.getHibernateTemplate().find( - "from test.Product product where product.category=?", category); - } - - } ----- - - -[[orm-hibernate-daos]] -===== Implementing Spring-based DAOs without callbacks -As alternative to using Spring's `HibernateTemplate` to implement DAOs, data access code -can also be written in a more traditional fashion, without wrapping the Hibernate access -code in a callback, while still respecting and participating in Spring's generic -`DataAccessException` hierarchy. The `HibernateDaoSupport` base class offers methods to -access the current transactional `Session` and to convert exceptions in such a scenario; -similar methods are also available as static helpers on the `SessionFactoryUtils` class. -Note that such code will usually pass `false` as the value of the `getSession(..)` -methods `allowCreate` argument, to enforce running within a transaction (which avoids -the need to close the returned `Session`, as its lifecycle is managed by the -transaction). - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class HibernateProductDao extends HibernateDaoSupport implements ProductDao { - - public Collection loadProductsByCategory(String category) throws DataAccessException, MyException { - Session session = getSession(false); - try { - Query query = session.createQuery("from test.Product product where product.category=?"); - query.setString(0, category); - List result = query.list(); - if (result == null) { - throw new MyException("No search results."); - } - return result; - } - catch (HibernateException ex) { - throw convertHibernateAccessException(ex); - } - } - } ----- - -The advantage of such direct Hibernate access code is that it allows __any__ checked -application exception to be thrown within the data access code; contrast this to the -`HibernateTemplate` class which is restricted to throwing only unchecked exceptions -within the callback. Note that you can often defer the corresponding checks and the -throwing of application exceptions to after the callback, which still allows working -with `HibernateTemplate`. In general, the `HibernateTemplate` class' convenience methods -are simpler and more convenient for many scenarios. - - - - -[[classic-spring-jms]] -=== JMS Usage - -One of the benefits of Spring's JMS support is to shield the user from differences -between the JMS 1.0.2 and 1.1 APIs. (For a description of the differences between the -two APIs see sidebar on Domain Unification). Since it is now common to encounter only -the JMS 1.1 API the use of classes that are based on the JMS 1.0.2 API has been -deprecated in Spring 3.0. This section describes Spring JMS support for the JMS 1.0.2 -deprecated classes. - -.Domain Unification -**** -There are two major releases of the JMS specification, 1.0.2 and 1.1. - -JMS 1.0.2 defined two types of messaging domains, point-to-point (Queues) and -publish/subscribe (Topics). The 1.0.2 API reflected these two messaging domains by -providing a parallel class hierarchy for each domain. As a result, a client application -became domain specific in its use of the JMS API. JMS 1.1 introduced the concept of -domain unification that minimized both the functional differences and client API -differences between the two domains. As an example of a functional difference that was -removed, if you use a JMS 1.1 provider you can transactionally consume a message from -one domain and produce a message on the other using the same `Session`. - -[NOTE] -==== -The JMS 1.1 specification was released in April 2002 and incorporated as part of J2EE -1.4 in November 2003. As a result, common J2EE 1.3 application servers which are still -in widespread use (such as BEA WebLogic 8.1 and IBM WebSphere 5.1) are based on JMS -1.0.2. -==== -**** - - - -[[classic-spring-jms-template]] -==== JmsTemplate -Located in the package `org.springframework.jms.core` the class `JmsTemplate102` -provides all of the features of the `JmsTemplate` described the JMS chapter, but is -based on the JMS 1.0.2 API instead of the JMS 1.1 API. As a consequence, if you are -using JmsTemplate102 you need to set the boolean property `pubSubDomain` to configure -the `JmsTemplate` with knowledge of what JMS domain is being used. By default the value -of this property is false, indicating that the point-to-point domain, Queues, will be -used. - - - -[[classic-spring-aysnc-messages]] -==== Asynchronous Message Reception -<> are used in -conjunction with Spring's <> to support -asynchronous message reception by exposing almost any class as a Message-driven POJO. If -you are using the JMS 1.0.2 API, you will want to use the 1.0.2 specific classes such as -`MessageListenerAdapter102`, `SimpleMessageListenerContainer102`, and -`DefaultMessageListenerContainer102`. These classes provide the same functionality as -the JMS 1.1 based counterparts but rely only on the JMS 1.0.2 API. - - - -[[classic-spring-jms-connections]] -==== Connections -The `ConnectionFactory` interface is part of the JMS specification and serves as the -entry point for working with JMS. Spring provides an implementation of the -`ConnectionFactory` interface, `SingleConnectionFactory102`, based on the JMS 1.0.2 API -that will return the same `Connection` on all `createConnection()` calls and ignore -calls to `close()`. You will need to set the boolean property `pubSubDomain` to indicate -which messaging domain is used as `SingleConnectionFactory102` will always explicitly -differentiate between a `javax.jms.QueueConnection` and a `javax.jmsTopicConnection`. - - - -[[classic-spring-jms-tx-management]] -==== Transaction Management -In a JMS 1.0.2 environment the class `JmsTransactionManager102` provides support for -managing JMS transactions for a single Connection Factory. Please refer to the reference -documentation on <> for more information on this -functionality. - - - -[[classic-aop-spring]] -== Classic Spring AOP Usage -In this appendix we discuss the lower-level Spring AOP APIs and the AOP support used in -Spring 1.2 applications. For new applications, we recommend the use of the Spring 2.0 -AOP support described in the <> chapter, but when working with existing -applications, or when reading books and articles, you may come across Spring 1.2 style -examples. Spring 2.0 is fully backwards compatible with Spring 1.2 and everything -described in this appendix is fully supported in Spring 2.0. - - - - -[[classic-aop-api-pointcuts]] -=== Pointcut API in Spring -Let's look at how Spring handles the crucial pointcut concept. - - - -[[classic-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. - -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: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface Pointcut { - - ClassFilter getClassFilter(); - - MethodMatcher getMethodMatcher(); - - } ----- - -Splitting the `Pointcut` interface into two parts allows reuse of class and method -matching parts, and fine-grained composition operations (such as performing a "union" -with another method matcher). - -The `ClassFilter` interface is used to restrict the pointcut to a given set of target -classes. If the `matches()` method always returns true, all target classes will be -matched: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface ClassFilter { - - boolean matches(Class clazz); - - } ----- - -The `MethodMatcher` interface is normally more important. The complete interface is -shown below: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface MethodMatcher { - - boolean matches(Method m, Class targetClass); - - boolean isRuntime(); - - 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 -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. - -[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. -==== - - - -[[classic-aop-api-pointcut-ops]] -==== Operations on pointcuts -Spring supports operations on pointcuts: notably, __union__ and __intersection__. - -* Union means the methods that either pointcut matches. -* Intersection means the methods that both pointcuts match. -* Union is usually more useful. -* Pointcuts can be composed using the static methods in the - __org.springframework.aop.support.Pointcuts__ class, or using the - __ComposablePointcut__ class in the same package. However, using AspectJ pointcut - expressions is usually a simpler approach. - - - -[[classic-aop-api-pointcuts-aspectj]] -==== AspectJ expression pointcuts -Since 2.0, the most important type of pointcut used by Spring is -`org.springframework.aop.aspectj.AspectJExpressionPointcut`. This is a pointcut that -uses an AspectJ supplied library to parse an AspectJ pointcut expression string. - -See the previous chapter for a discussion of supported AspectJ pointcut primitives. - - - -[[classic-aop-api-pointcuts-impls]] -==== Convenience pointcut implementations -Spring provides several convenient pointcut implementations. Some can be used out of the -box; others are intended to be subclassed in application-specific pointcuts. - - -[[classic-aop-api-pointcuts-static]] -===== Static pointcuts -Static pointcuts are based on method and target class, and cannot take into account the -method's arguments. Static pointcuts are sufficient - __and best__ - for most usages. -It's possible for Spring to evaluate a static pointcut only once, when a method is first -invoked: after that, there is no need to evaluate the pointcut again with each method -invocation. - -Let's consider some static pointcut implementations included with Spring. - -[[classic-aop-api-pointcuts-regex]] -====== Regular expression pointcuts -One obvious way to specify static pointcuts is regular expressions. Several AOP -frameworks besides Spring make this possible. -`org.springframework.aop.support.Perl5RegexpMethodPointcut` is a generic regular -expression pointcut, using Perl 5 regular expression syntax. The -`Perl5RegexpMethodPointcut` class depends on Jakarta ORO for regular expression -matching. Spring also provides the `JdkRegexpMethodPointcut` class that uses the regular -expression support in JDK 1.4+. - -Using the `Perl5RegexpMethodPointcut` class, you can provide a list of pattern Strings. -If any of these is a match, the pointcut will evaluate to true. (So the result is -effectively the union of these pointcuts.) - -The usage is shown below: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - .*set.* - .*absquatulate - - - ----- - -Spring provides a convenience class, `RegexpMethodPointcutAdvisor`, that allows us to -also reference an Advice (remember that an Advice can be an interceptor, before advice, -throws advice etc.). Behind the scenes, Spring will use a `JdkRegexpMethodPointcut`. -Using `RegexpMethodPointcutAdvisor` simplifies wiring, as the one bean encapsulates both -pointcut and advice, as shown below: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - .*set.* - .*absquatulate - - - ----- - -__RegexpMethodPointcutAdvisor__ can be used with any Advice type. - -[[classic-aop-api-pointcuts-attribute-driven]] -====== 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. - - -[[classic-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 -vary. - -The main example is the `control flow` pointcut. - -[[classic-aop-api-pointcuts-cflow]] -====== Control flow pointcuts -Spring control flow pointcuts are conceptually similar to AspectJ __cflow__ pointcuts, -although less powerful. (There is currently no way to specify that a pointcut executes -below a join point matched by another pointcut.) A control flow pointcut matches the -current call stack. For example, it might fire if the join point was invoked by a method -in the `com.mycompany.web` package, or by the `SomeCaller` class. Control flow pointcuts -are specified using the `org.springframework.aop.support.ControlFlowPointcut` class. -[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 -pointcuts. -==== - - - -[[classic-aop-api-pointcuts-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): - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - class TestStaticPointcut extends StaticMethodMatcherPointcut { - - public boolean matches(Method m, Class targetClass) { - // return true if custom criteria match - } - - } ----- - -There are also superclasses for dynamic pointcuts. - -You can use custom pointcuts with any advice type in Spring 1.0 RC2 and above. - - - -[[classic-aop-api-pointcuts-custom]] -==== 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." -==== - - - - -[[classic-aop-api-advice]] -=== Advice API in Spring -Let's now look at how Spring AOP handles advice. - - - -[[classic-aop-api-advice-lifecycle]] -==== Advice lifecycles -Each advice is a Spring bean. An advice instance can be shared across all advised -objects, or unique to each advised object. This corresponds to __per-class__ or -__per-instance__ advice. - -Per-class advice is used most often. It is appropriate for generic advice such as -transaction advisors. These do not depend on the state of the proxied object or add new -state; they merely act on the method and arguments. - -Per-instance advice is appropriate for introductions, to support mixins. In this case, -the advice adds state to the proxied object. - -It's possible to use a mix of shared and per-instance advice in the same AOP proxy. - - - -[[classic-aop-api-advice-types]] -==== 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. - - -[[classic-aop-api-advice-around]] -===== Interception around advice -The most fundamental advice type in Spring is __interception around advice__. - -Spring is compliant with the AOP Alliance interface for around advice using method -interception. MethodInterceptors implementing around advice should implement the -following interface: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface MethodInterceptor extends Interceptor { - - Object invoke(MethodInvocation invocation) throws Throwable; - - } ----- - -The `MethodInvocation` argument to the `invoke()` method exposes the method being -invoked; the target join point; the AOP proxy; and the arguments to the method. The -`invoke()` method should return the invocation's result: the return value of the join -point. - -A simple `MethodInterceptor` implementation looks as follows: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class DebugInterceptor implements MethodInterceptor { - - public Object invoke(MethodInvocation invocation) throws Throwable { - System.out.println("Before: invocation=[" + invocation + "]"); - Object rval = invocation.proceed(); - System.out.println("Invocation returned"); - return rval; - } - - } ----- - -Note the call to the MethodInvocation's `proceed()` method. This proceeds down the -interceptor chain towards the join point. Most interceptors will invoke this method, and -return its return value. However, a MethodInterceptor, like any around advice, can -return a different value or throw an exception rather than invoke the proceed method. -However, you don't want to do this without good reason! - -[NOTE] -==== -MethodInterceptors offer interoperability with other AOP Alliance-compliant AOP -implementations. The other advice types discussed in the remainder of this section -implement common AOP concepts, but in a Spring-specific way. While there is an advantage -in using the most specific advice type, stick with MethodInterceptor around advice if -you are likely to want to run the aspect in another AOP framework. Note that pointcuts -are not currently interoperable between frameworks, and the AOP Alliance does not -currently define pointcut interfaces. -==== - - -[[classic-aop-api-advice-before]] -===== Before advice -A simpler advice type is a __before advice__. This does not need a `MethodInvocation` -object, since it will only be called before entering the method. - -The main advantage of a before advice is that there is no need to invoke the `proceed()` -method, and therefore no possibility of inadvertently failing to proceed down the -interceptor chain. - -The `MethodBeforeAdvice` interface is shown below. (Spring's API design would allow for -field before advice, although the usual objects apply to field interception and it's -unlikely that Spring will ever implement it). - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface MethodBeforeAdvice extends BeforeAdvice { - - void before(Method m, Object[] args, Object target) throws Throwable; - - } ----- - -Note the return type is `void`. Before advice can insert custom behavior before the join -point executes, but cannot change the return value. If a before advice throws an -exception, this will abort further execution of the interceptor chain. The exception -will propagate back up the interceptor chain. If it is unchecked, or on the signature of -the invoked method, it will be passed directly to the client; otherwise it will be -wrapped in an unchecked exception by the AOP proxy. - -An example of a before advice in Spring, which counts all method invocations: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class CountingBeforeAdvice implements MethodBeforeAdvice { - - private int count; - - public void before(Method m, Object[] args, Object target) throws Throwable { - ++count; - } - - public int getCount() { - return count; - } - } ----- - -[TIP] -==== - -Before advice can be used with any pointcut. -==== - - -[[classic-aop-api-advice-throws]] -===== Throws advice -__Throws advice__ is invoked after the return of the join point if the join point threw -an exception. Spring offers typed throws advice. Note that this means that the -`org.springframework.aop.ThrowsAdvice` interface does not contain any methods: It is a -tag interface identifying that the given object implements one or more typed throws -advice methods. These should be in the form of: - -[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. - -The advice below is invoked if a `RemoteException` is thrown (including subclasses): - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class RemoteThrowsAdvice implements ThrowsAdvice { - - public void afterThrowing(RemoteException ex) throws Throwable { - // Do something with remote exception - } - - } ----- - -The following advice is invoked if a `ServletException` is thrown. Unlike the above -advice, it declares 4 arguments, so that it has access to the invoked method, method -arguments and target object: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class ServletThrowsAdviceWithArguments implements ThrowsAdvice { - - public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) { - // Do something with all arguments - } - - } ----- - -The final example illustrates how these two methods could be used in a single class, -which handles both `RemoteException` and `ServletException`. Any number of throws advice -methods can be combined in a single class. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public static class CombinedThrowsAdvice implements ThrowsAdvice { - - public void afterThrowing(RemoteException ex) throws Throwable { - // Do something with remote exception - } - - public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) { - // Do something with all arguments - } - } ----- - -__Note:__ If a throws-advice method throws an exception itself, it will override the -original exception (i.e. change the exception thrown to the user). The overriding -exception will typically be a RuntimeException; this is compatible with any method -signature. However, if a throws-advice method throws a checked exception, it will have -to match the declared exceptions of the target method and is hence to some degree -coupled to specific target method signatures. __Do not throw an undeclared checked -exception that is incompatible with the target method's signature!__ - -[TIP] -==== - -Throws advice can be used with any pointcut. -==== - - -[[classic-aop-api-advice-after-returning]] -===== After Returning advice -An after returning advice in Spring must implement the -__org.springframework.aop.AfterReturningAdvice__ interface, shown below: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface AfterReturningAdvice extends Advice { - - void afterReturning(Object returnValue, Method m, Object[] args, - Object target) throws Throwable; - - } ----- - -An after returning advice has access to the return value (which it cannot modify), -invoked method, methods arguments and target. - -The following after returning advice counts all successful method invocations that have -not thrown exceptions: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class CountingAfterReturningAdvice implements AfterReturningAdvice { - - private int count; - - public void afterReturning(Object returnValue, Method m, Object[] args, - Object target) throws Throwable { - ++count; - } - - public int getCount() { - return count; - } - - } ----- - -This advice doesn't change the execution path. If it throws an exception, this will be -thrown up the interceptor chain instead of the return value. - -[TIP] -==== - -After returning advice can be used with any pointcut. -==== - - -[[classic-aop-api-advice-introduction]] -===== Introduction advice -Spring treats introduction advice as a special kind of interception advice. - -Introduction requires an `IntroductionAdvisor`, and an `IntroductionInterceptor`, -implementing the following interface: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface IntroductionInterceptor extends MethodInterceptor { - - boolean implementsInterface(Class intf); - - } ----- - -The `invoke()` method inherited from the AOP Alliance `MethodInterceptor` interface must -implement the introduction: that is, if the invoked method is on an introduced -interface, the introduction interceptor is responsible for handling the method call - it -cannot invoke `proceed()`. - -Introduction advice cannot be used with any pointcut, as it applies only at class, -rather than method, level. You can only use introduction advice with the -`IntroductionAdvisor`, which has the following methods: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface IntroductionAdvisor extends Advisor, IntroductionInfo { - - ClassFilter getClassFilter(); - - void validateInterfaces() throws IllegalArgumentException; - - } - - public interface IntroductionInfo { - - Class[] getInterfaces(); - - } ----- - -There is no `MethodMatcher`, and hence no `Pointcut`, associated with introduction -advice. Only class filtering is logical. - -The `getInterfaces()` method returns the interfaces introduced by this advisor. - -The `validateInterfaces()` method is used internally to see whether or not the -introduced interfaces can be implemented by the configured `IntroductionInterceptor`. - -Let's look at a simple example from the Spring test suite. Let's suppose we want to -introduce the following interface to one or more objects: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface Lockable { - - void lock(); - - void unlock(); - - boolean locked(); - - } ----- - -This illustrates a __mixin__. We want to be able to cast advised objects to Lockable, -whatever their type, and call lock and unlock methods. If we call the lock() method, we -want all setter methods to throw a `LockedException`. Thus we can add an aspect that -provides the ability to make objects immutable, without them having any knowledge of it: -a good example of AOP. - -Firstly, we'll need an `IntroductionInterceptor` that does the heavy lifting. In this -case, we extend the `org.springframework.aop.support.DelegatingIntroductionInterceptor` -convenience class. We could implement IntroductionInterceptor directly, but using -`DelegatingIntroductionInterceptor` is best for most cases. - -The `DelegatingIntroductionInterceptor` is designed to delegate an introduction to an -actual implementation of the introduced interface(s), concealing the use of interception -to do so. The delegate can be set to any object using a constructor argument; the -default delegate (when the no-arg constructor is used) is this. Thus in the example -below, the delegate is the `LockMixin` subclass of `DelegatingIntroductionInterceptor`. -Given a delegate (by default itself), a `DelegatingIntroductionInterceptor` instance -looks for all interfaces implemented by the delegate (other than -IntroductionInterceptor), and will support introductions against any of them. It's -possible for subclasses such as `LockMixin` to call the `suppressInterface(Class intf)` -method to suppress interfaces that should not be exposed. However, no matter how many -interfaces an `IntroductionInterceptor` is prepared to support, the -`IntroductionAdvisor` used will control which interfaces are actually exposed. An -introduced interface will conceal any implementation of the same interface by the target. - -Thus LockMixin subclasses `DelegatingIntroductionInterceptor` and implements Lockable -itself. The superclass automatically picks up that Lockable can be supported for -introduction, so we don't need to specify that. We could introduce any number of -interfaces in this way. - -Note the use of the `locked` instance variable. This effectively adds additional state -to that held in the target object. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable { - - private boolean locked; - - public void lock() { - this.locked = true; - } - - public void unlock() { - this.locked = false; - } - - public boolean locked() { - return this.locked; - } - - public Object invoke(MethodInvocation invocation) throws Throwable { - if (locked() && invocation.getMethod().getName().indexOf("set") == 0) { - throw new LockedException(); - } - return super.invoke(invocation); - } - - } ----- - -Often it isn't necessary to override the `invoke()` method: the -`DelegatingIntroductionInterceptor` implementation - which calls the delegate method if -the method is introduced, otherwise proceeds towards the join point - is usually -sufficient. In the present case, we need to add a check: no setter method can be invoked -if in locked mode. - -The introduction advisor required is simple. All it needs to do is hold a distinct -`LockMixin` instance, and specify the introduced interfaces - in this case, just -`Lockable`. A more complex example might take a reference to the introduction -interceptor (which would be defined as a prototype): in this case, there's no -configuration relevant for a `LockMixin`, so we simply create it using `new`. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class LockMixinAdvisor extends DefaultIntroductionAdvisor { - - public LockMixinAdvisor() { - super(new LockMixin(), Lockable.class); - } - - } ----- - -We can apply this advisor very simply: it requires no configuration. (However, it __is__ -necessary: It's impossible to use an `IntroductionInterceptor` without an -__IntroductionAdvisor__.) As usual with introductions, the advisor must be per-instance, -as it is stateful. We need a different instance of `LockMixinAdvisor`, and hence -`LockMixin`, for each advised object. The advisor comprises part of the advised object's -state. - -We can apply this advisor programmatically, using the `Advised.addAdvisor()` method, or -(the recommended way) in XML configuration, like any other advisor. All proxy creation -choices discussed below, including "auto proxy creators," correctly handle introductions -and stateful mixins. - - - - -[[classic-aop-api-advisor]] -=== Advisor API in Spring -In Spring, an Advisor is an aspect that contains just a single advice object associated -with a pointcut expression. - -Apart from the special case of introductions, any advisor can be used with any advice. -`org.springframework.aop.support.DefaultPointcutAdvisor` is the most commonly used -advisor class. For example, it can be used with a `MethodInterceptor`, `BeforeAdvice` or -`ThrowsAdvice`. - -It is possible to mix advisor and advice types in Spring in the same AOP proxy. For -example, you could use a interception around advice, throws advice and before advice in -one proxy configuration: Spring will automatically create the necessary interceptor -chain. - - - - -[[classic-aop-pfb]] -=== 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.) - -[NOTE] -==== -The Spring 2.0 AOP support also uses factory beans under the covers. -==== - -The basic way to create an AOP proxy in Spring is to use the -__org.springframework.aop.framework.ProxyFactoryBean__. This gives complete control over -the pointcuts and advice that will apply, and their ordering. However, there are simpler -options that are preferable if you don't need such control. - - - -[[classic-aop-pfb-1]] -==== Basics -The `ProxyFactoryBean`, like other Spring `FactoryBean` implementations, introduces a -level of indirection. If you define a `ProxyFactoryBean` with name `foo`, what objects -referencing `foo` see is not the `ProxyFactoryBean` instance itself, but an object -created by the `ProxyFactoryBean`'s implementation of the `getObject()` method. This -method will create an AOP proxy wrapping a target object. - -One of the most important benefits of using a `ProxyFactoryBean` or another IoC-aware -class to create AOP proxies, is that it means that advices and pointcuts can also be -managed by IoC. This is a powerful feature, enabling certain approaches that are hard to -achieve with other AOP frameworks. For example, an advice may itself reference -application objects (besides the target, which should be available in any AOP -framework), benefiting from all the pluggability provided by Dependency Injection. - - - -[[classic-aop-pfb-2]] -==== 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 <>). - -Some key properties are inherited from `org.springframework.aop.framework.ProxyConfig` -(the superclass for all AOP proxy factories in Spring). These key properties include: - -* `proxyTargetClass`: `true` if the target class is to be proxied, rather than the - target class' interfaces. If this property value is set to `true`, then CGLIB proxies - will be created (but see also below - <>). -* `optimize`: controls whether or not aggressive optimizations are applied to proxies - __created via CGLIB__. One should not blithely use this setting unless one fully - understands how the relevant AOP proxy handles optimization. This is currently used - only for CGLIB proxies; it has no effect with JDK dynamic proxies. -* `frozen`: if a proxy configuration is `frozen`, then changes to the configuration are - no longer allowed. This is useful both as a slight optimization and for those cases - when you don't want callers to be able to manipulate the proxy (via the `Advised` - interface) after the proxy has been created. The default value of this property is - `false`, so changes such as adding additional advice are allowed. -* `exposeProxy`: determines whether or not the current proxy should be exposed in a - `ThreadLocal` so that it can be accessed by the target. If a target needs to obtain - the proxy and the `exposeProxy` property is set to `true`, the target can use the - `AopContext.currentProxy()` method. -* `aopProxyFactory`: the implementation of `AopProxyFactory` to use. Offers a way of - customizing whether to use dynamic proxies, CGLIB or any other proxy strategy. The - default implementation will choose dynamic proxies or CGLIB appropriately. There - should be no need to use this property; it is intended to allow the addition of new - proxy types in Spring 1.1. - -Other properties specific to `ProxyFactoryBean` include: - -* `proxyInterfaces`: array of String interface names. If this isn't supplied, a CGLIB - proxy for the target class will be used (but see also below - <>). -* `interceptorNames`: String array of `Advisor`, interceptor or other advice names to - apply. Ordering is significant, on a first come-first served basis. That is to say - that the first interceptor in the list will be the first to be able to intercept the - invocation. - -The names are bean names in the current factory, including bean names from ancestor -factories. You can't mention bean references here since doing so would result in the -`ProxyFactoryBean` ignoring the singleton setting of the advice. - -You can append an interceptor name with an asterisk ( `*`). This will result in the -application of all advisor beans with names starting with the part before the asterisk -to be applied. An example of using this feature can be found in -<>. - -* singleton: whether or not the factory should return a single object, no matter how - often the `getObject()` method is called. Several `FactoryBean` implementations offer - such a method. The default value is `true`. If you want to use stateful advice - for - example, for stateful mixins - use prototype advices along with a singleton value of - `false`. - - - -[[classic-aop-pfb-proxy-types]] -==== JDK- and CGLIB-based proxies -This section serves as the definitive documentation on how the `ProxyFactoryBean` -chooses to create one of either a JDK- and CGLIB-based proxy for a particular target -object (that is to be proxied). - -[NOTE] -==== -The behavior of the `ProxyFactoryBean` with regard to creating JDK- or CGLIB-based -proxies changed between versions 1.2.x and 2.0 of Spring. The `ProxyFactoryBean` now -exhibits similar semantics with regard to auto-detecting interfaces as those of the -`TransactionProxyFactoryBean` class. -==== - -If the class of a target object that is to be proxied (hereafter simply referred to as -the target class) doesn't implement any interfaces, then a CGLIB-based proxy will be -created. This is the easiest scenario, because JDK proxies are interface based, and no -interfaces means JDK proxying isn't even possible. One simply plugs in the target bean, -and specifies the list of interceptors via the `interceptorNames` property. Note that a -CGLIB-based proxy will be created even if the `proxyTargetClass` property of the -`ProxyFactoryBean` has been set to `false`. (Obviously this makes no sense, and is best -removed from the bean definition because it is at best redundant, and at worst -confusing.) - -If the target class implements one (or more) interfaces, then the type of proxy that is -created depends on the configuration of the `ProxyFactoryBean`. - -If the `proxyTargetClass` property of the `ProxyFactoryBean` has been set to `true`, -then a CGLIB-based proxy will be created. This makes sense, and is in keeping with the -principle of least surprise. Even if the `proxyInterfaces` property of the -`ProxyFactoryBean` has been set to one or more fully qualified interface names, the fact -that the `proxyTargetClass` property is set to `true` __will__ cause CGLIB-based -proxying to be in effect. - -If the `proxyInterfaces` property of the `ProxyFactoryBean` has been set to one or more -fully qualified interface names, then a JDK-based proxy will be created. The created -proxy will implement all of the interfaces that were specified in the `proxyInterfaces` -property; if the target class happens to implement a whole lot more interfaces than -those specified in the `proxyInterfaces` property, that is all well and good but those -additional interfaces will not be implemented by the returned proxy. - -If the `proxyInterfaces` property of the `ProxyFactoryBean` has __not__ been set, but -the target class __does implement one (or more)__ interfaces, then the -`ProxyFactoryBean` will auto-detect the fact that the target class does actually -implement at least one interface, and a JDK-based proxy will be created. The interfaces -that are actually proxied will be __all__ of the interfaces that the target class -implements; in effect, this is the same as simply supplying a list of each and every -interface that the target class implements to the `proxyInterfaces` property. However, -it is significantly less work, and less prone to typos. - - - -[[classic-aop-api-proxying-intf]] -==== Proxying interfaces -Let's look at a simple example of `ProxyFactoryBean` in action. This example involves: - -* A __target bean__ that will be proxied. This is the "personTarget" bean definition in - the example below. -* An Advisor and an Interceptor used to provide advice. -* An AOP proxy bean definition specifying the target object (the personTarget bean) and - the interfaces to proxy, along with the advices to apply. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - Tony - 51 - - - - Custom string property value - - - - - - - com.mycompany.Person - - - - myAdvisor - debugInterceptor - - - ----- - -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 -return independent proxy instances. If any of the advisors is itself a prototype, an -independent instance would need to be returned, so it's necessary to be able to obtain -an instance of the prototype from the factory; holding a reference isn't sufficient. -==== - -The "person" bean definition above can be used in place of a Person implementation, as -follows: - -[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: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - -The `PersonUser` class in this example would expose a property of type Person. As far as -it's concerned, the AOP proxy can be used transparently in place of a "real" person -implementation. However, its class would be a dynamic proxy class. It would be possible -to cast it to the `Advised` interface (discussed below). - -It's possible to conceal the distinction between target and proxy using an anonymous -__inner bean__, as follows. Only the `ProxyFactoryBean` definition is different; the -advice is included only for completeness: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - Custom string property value - - - - - - com.mycompany.Person - - - - Tony - 51 - - - - - myAdvisor - debugInterceptor - - - ----- - -This has the advantage that there's only one object of type `Person`: useful if we want -to prevent users of the application context from obtaining a reference to the un-advised -object, or need to avoid any ambiguity with Spring IoC __autowiring__. There's also -arguably an advantage in that the ProxyFactoryBean definition is self-contained. -However, there are times when being able to obtain the un-advised target from the -factory might actually be an __advantage__: for example, in certain test scenarios. - - - -[[classic-aop-api-proxying-class]] -==== Proxying classes -What if you need to proxy a class, rather than one or more interfaces? - -Imagine that in our example above, there was no `Person` interface: we needed to advise -a class called `Person` that didn't implement any business interface. In this case, you -can configure Spring to use CGLIB proxying, rather than dynamic proxies. Simply set the -`proxyTargetClass` property on the ProxyFactoryBean above to true. While it's best to -program to interfaces, rather than classes, the ability to advise classes that don't -implement interfaces can be useful when working with legacy code. (In general, Spring -isn't prescriptive. While it makes it easy to apply good practices, it avoids forcing a -particular approach.) - -If you want to, you can force the use of CGLIB in any case, even if you do have -interfaces. - -CGLIB proxying works by generating a subclass of the target class at runtime. Spring -configures this generated subclass to delegate method calls to the original target: the -subclass is used to implement the __Decorator__ pattern, weaving in the advice. - -CGLIB proxying should generally be transparent to users. However, there are some issues -to consider: - -* `Final` methods can't be advised, as they can't be overridden. -* As of Spring 3.2 it is no longer required to add CGLIB to your project classpath. - CGLIB classes have been repackaged under org.springframework and included directly in - the spring-core JAR. This is both for user convenience as well as to avoid potential - conflicts with other projects that have dependence on a differing version of CGLIB. - -There's little performance difference between CGLIB proxying and dynamic proxies. As of -Spring 1.0, dynamic proxies are slightly faster. However, this may change in the future. -Performance should not be a decisive consideration in this case. - - - -[[classic-aop-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: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - global* - - - - - - ----- - - - - -[[classic-aop-concise-proxy]] -=== 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: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - PROPAGATION_REQUIRED - - - ----- - -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. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - ----- - -It is of course possible to override properties from the parent template, such as in -this case, the transaction propagation settings: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - PROPAGATION_REQUIRED,readOnly - PROPAGATION_REQUIRED,readOnly - PROPAGATION_REQUIRED,readOnly - PROPAGATION_REQUIRED - - - ----- - -Note that in the example above, we have explicitly marked the parent bean definition as -__abstract__ by using the __abstract__ attribute, 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 -pre-instantiate it. - - - - -[[classic-aop-prog]] -=== Creating AOP proxies programmatically with the ProxyFactory -It's easy to create AOP proxies programmatically using Spring. This enables you to use -Spring AOP without dependency on Spring IoC. - -The following listing shows creation of a proxy for a target object, with one -interceptor and one advisor. The interfaces implemented by the target object will -automatically be proxied: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl); - factory.addInterceptor(myMethodInterceptor); - factory.addAdvisor(myAdvisor); - MyBusinessInterface tb = (MyBusinessInterface) factory.getProxy(); ----- - -The first step is to construct an object of type -`org.springframework.aop.framework.ProxyFactory`. You can create this with a target -object, as in the above example, or specify the interfaces to be proxied in an alternate -constructor. - -You can add interceptors or advisors, and manipulate them for the life of the -ProxyFactory. If you add an IntroductionInterceptionAroundAdvisor you can cause the -proxy to implement additional interfaces. - -There are also convenience methods on ProxyFactory (inherited from `AdvisedSupport`) -which allow you to add other advice types such as before and throws advice. -AdvisedSupport is the superclass of both ProxyFactory and ProxyFactoryBean. - -[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. -==== - - - - -[[classic-aop-api-advised]] -=== Manipulating advised objects -However you create AOP proxies, you can manipulate them using the -`org.springframework.aop.framework.Advised` interface. Any AOP proxy can be cast to this -interface, whichever other interfaces it implements. This interface includes the -following methods: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Advisor[] getAdvisors(); - - void addAdvice(Advice advice) throws AopConfigException; - - void addAdvice(int pos, Advice advice) throws AopConfigException; - - void addAdvisor(Advisor advisor) throws AopConfigException; - - void addAdvisor(int pos, Advisor advisor) throws AopConfigException; - - int indexOf(Advisor advisor); - - boolean removeAdvisor(Advisor advisor) throws AopConfigException; - - void removeAdvisor(int index) throws AopConfigException; - - boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException; - - boolean isFrozen(); ----- - -The `getAdvisors()` method will return an Advisor for every advisor, interceptor or -other advice type that has been added to the factory. If you added an Advisor, the -returned advisor at this index will be the object that you added. If you added an -interceptor or other advice type, Spring will have wrapped this in an advisor with a -pointcut that always returns true. Thus if you added a `MethodInterceptor`, the advisor -returned for this index will be an `DefaultPointcutAdvisor` returning your -`MethodInterceptor` and a pointcut that matches all classes and methods. - -The `addAdvisor()` methods can be used to add any Advisor. Usually the advisor holding -pointcut and advice will be the generic `DefaultPointcutAdvisor`, which can be used with -any advice or pointcut (but not for introductions). - -By default, it's possible to add or remove advisors or interceptors even once a proxy -has been created. The only restriction is that it's impossible to add or remove an -introduction advisor, as existing proxies from the factory will not show the interface -change. (You can obtain a new proxy from the factory to avoid this problem.) - -A simple example of casting an AOP proxy to the `Advised` interface and examining and -manipulating its advice: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Advised advised = (Advised) myObject; - Advisor[] advisors = advised.getAdvisors(); - int oldAdvisorCount = advisors.length; - System.out.println(oldAdvisorCount + " advisors"); - - // Add an advice like an interceptor without a pointcut - // Will match all proxied methods - // Can use for interceptors, before, after returning or throws advice - advised.addAdvice(new DebugInterceptor()); - - // Add selective advice using a pointcut - advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice)); - - assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length); ----- - -[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 -found it very useful to be able to add test code in the form of an interceptor or other -advice, getting inside a method invocation I want to test. (For example, the advice can -get inside a transaction created for that method: for example, to run SQL to check that -a database was correctly updated, before marking the transaction for roll back.) -==== - -Depending on how you created the proxy, you can usually set a `frozen` flag, in which -case the `Advised` `isFrozen()` method will return true, and any attempts to modify -advice through addition or removal will result in an `AopConfigException`. The ability -to freeze the state of an advised object is useful in some cases, for example, to -prevent calling code removing a security interceptor. It may also be used in Spring 1.1 -to allow aggressive optimization if runtime advice modification is known not to be -required. - - - - -[[classic-aop-autoproxy]] -=== Using the "autoproxy" facility -So far we've considered explicit creation of AOP proxies using a `ProxyFactoryBean` or -similar factory bean. - -Spring also allows us to use "autoproxy" bean definitions, which can automatically proxy -selected bean definitions. This is built on Spring "bean post processor" infrastructure, -which enables modification of any bean definition as the container loads. - -In this model, you set up some special bean definitions in your XML bean definition file -to configure the auto proxy infrastructure. This allows you just to declare the targets -eligible for autoproxying: you don't need to use `ProxyFactoryBean`. - -There are two ways to do this: - -* Using an autoproxy creator that refers to specific beans in the current context. -* A special case of autoproxy creation that deserves to be considered separately; - autoproxy creation driven by source-level metadata attributes. - - - -[[classic-aop-autoproxy-choices]] -==== Autoproxy bean definitions -The `org.springframework.aop.framework.autoproxy` package provides the following -standard autoproxy creators. - - -[[classic-aop-api-autoproxy]] -===== BeanNameAutoProxyCreator -The `BeanNameAutoProxyCreator` class is a `BeanPostProcessor` that automatically creates -AOP proxies for beans with names matching literal values or wildcards. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - jdk*,onlyJdk - - - myInterceptor - - - ----- - -As with `ProxyFactoryBean`, there is an `interceptorNames` property rather than a list -of interceptors, to allow correct behavior for prototype advisors. Named "interceptors" -can be advisors or any advice type. - -As with auto proxying in general, the main point of using `BeanNameAutoProxyCreator` is -to apply the same configuration consistently to multiple objects, with minimal volume of -configuration. It is a popular choice for applying declarative transactions to multiple -objects. - -Bean definitions whose names match, such as "jdkMyBean" and "onlyJdk" in the above -example, are plain old bean definitions with the target class. An AOP proxy will be -created automatically by the `BeanNameAutoProxyCreator`. The same advice will be applied -to all matching beans. Note that if advisors are used (rather than the interceptor in -the above example), the pointcuts may apply differently to different beans. - - -[[classic-aop-api-autoproxy-default]] -===== DefaultAdvisorAutoProxyCreator -A more general and extremely powerful auto proxy creator is -`DefaultAdvisorAutoProxyCreator`. This will automagically apply eligible advisors in the -current context, without the need to include specific bean names in the autoproxy -advisor's bean definition. It offers the same merit of consistent configuration and -avoidance of duplication as `BeanNameAutoProxyCreator`. - -Using this mechanism involves: - -* Specifying a `DefaultAdvisorAutoProxyCreator` bean definition. -* Specifying any number of Advisors in the same or related contexts. Note that these - __must__ be Advisors, not just interceptors or other advices. This is necessary - because there must be a pointcut to evaluate, to check the eligibility of each advice - to candidate bean definitions. - -The `DefaultAdvisorAutoProxyCreator` will automatically evaluate the pointcut contained -in each advisor, to see what (if any) advice it should apply to each business object -(such as "businessObject1" and "businessObject2" in the example). - -This means that any number of advisors can be applied automatically to each business -object. If no pointcut in any of the advisors matches any method in a business object, -the object will not be proxied. As bean definitions are added for new business objects, -they will automatically be proxied if necessary. - -Autoproxying in general has the advantage of making it impossible for callers or -dependencies to obtain an un-advised object. Calling getBean("businessObject1") on this -ApplicationContext will return an AOP proxy, not the target business object. (The "inner -bean" idiom shown earlier also offers this benefit.) - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - ----- - -The `DefaultAdvisorAutoProxyCreator` is very useful if you want to apply the same advice -consistently to many business objects. Once the infrastructure definitions are in place, -you can simply add new business objects without including specific proxy configuration. -You can also drop in additional aspects very easily - for example, tracing or -performance monitoring aspects - with minimal change to configuration. - -The DefaultAdvisorAutoProxyCreator offers support for filtering (using a naming -convention so that only certain advisors are evaluated, allowing use of multiple, -differently configured, AdvisorAutoProxyCreators in the same factory) and ordering. -Advisors can implement the `org.springframework.core.Ordered` interface to ensure -correct ordering if this is an issue. The TransactionAttributeSourceAdvisor used in the -above example has a configurable order value; the default setting is unordered. - - -[[classic-aop-api-autoproxy-abstract]] -===== AbstractAdvisorAutoProxyCreator -This is the superclass of DefaultAdvisorAutoProxyCreator. You can create your own -autoproxy creators by subclassing this class, in the unlikely event that advisor -definitions offer insufficient customization to the behavior of the framework -`DefaultAdvisorAutoProxyCreator`. - - - -[[classic-aop-autoproxy-metadata]] -==== Using metadata-driven auto-proxying -A particularly important type of autoproxying is driven by metadata. This produces a -similar programming model to .NET `ServicedComponents`. Instead of using XML deployment -descriptors as in EJB, configuration for transaction management and other enterprise -services is held in source-level attributes. - -In this case, you use the `DefaultAdvisorAutoProxyCreator`, in combination with Advisors -that understand metadata attributes. The metadata specifics are held in the pointcut -part of the candidate advisors, rather than in the autoproxy creation class itself. - -This is really a special case of the `DefaultAdvisorAutoProxyCreator`, but deserves -consideration on its own. (The metadata-aware code is in the pointcuts contained in the -advisors, not the AOP framework itself.) - -The `/attributes` directory of the JPetStore sample application shows the use of -attribute-driven autoproxying. In this case, there's no need to use the -`TransactionProxyFactoryBean`. Simply defining transactional attributes on business -objects is sufficient, because of the use of metadata-aware pointcuts. The bean -definitions include the following code, in `/WEB-INF/declarativeServices.xml`. Note that -this is generic, and can be used outside the JPetStore: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - ----- - -The `DefaultAdvisorAutoProxyCreator` bean definition (the name is not significant, hence -it can even be omitted) will pick up all eligible pointcuts in the current application -context. In this case, the "transactionAdvisor" bean definition, of type -`TransactionAttributeSourceAdvisor`, will apply to classes or methods carrying a -transaction attribute. The TransactionAttributeSourceAdvisor depends on a -TransactionInterceptor, via constructor dependency. The example resolves this via -autowiring. The `AttributesTransactionAttributeSource` depends on an implementation of -the `org.springframework.metadata.Attributes` interface. In this fragment, the -"attributes" bean satisfies this, using the Jakarta Commons Attributes API to obtain -attribute information. (The application code must have been compiled using the Commons -Attributes compilation task.) - -The `/annotation` directory of the JPetStore sample application contains an analogous -example for auto-proxying driven by JDK 1.5+ annotations. The following configuration -enables automatic detection of Spring's `Transactional` annotation, leading to implicit -proxies for beans containing that annotation: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - ----- - -The `TransactionInterceptor` defined here depends on a `PlatformTransactionManager` -definition, which is not included in this generic file (although it could be) because it -will be specific to the application's transaction requirements (typically JTA, as in -this example, or Hibernate or JDBC): - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - -[TIP] -==== - -If you require only declarative transaction management, using these generic XML -definitions will result in Spring automatically proxying all classes or methods with -transaction attributes. You won't need to work directly with AOP, and the programming -model is similar to that of .NET ServicedComponents. -==== - -This mechanism is extensible. It's possible to do autoproxying based on custom -attributes. You need to: - -* Define your custom attribute. -* Specify an Advisor with the necessary advice, including a pointcut that is triggered - by the presence of the custom attribute on a class or method. You may be able to use - an existing advice, merely implementing a static pointcut that picks up the custom - attribute. - -It's possible for such advisors to be unique to each advised class (for example, -mixins): they simply need to be defined as prototype, rather than singleton, bean -definitions. For example, the `LockMixin` introduction interceptor from the Spring test -suite, shown above, could be used in conjunction with an attribute-driven pointcut to -target a mixin, as shown here. We use the generic `DefaultPointcutAdvisor`, configured -using JavaBean properties: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - ----- - -The above `swap()` call changes the target of the swappable bean. Clients who hold a -reference to that bean will be unaware of the change, but will immediately start hitting -the new target. - -Although this example doesn't add any advice - and it's not necessary to add advice to -use a `TargetSource` - of course any `TargetSource` can be used in conjunction with -arbitrary advice. - - - -[[classic-aop-ts-pool]] -==== Pooling target sources -Using a pooling target source provides a similar programming model to stateless session -EJBs, in which a pool of identical instances is maintained, with method invocations -going to free objects in the pool. - -A crucial difference between Spring pooling and SLSB pooling is that Spring pooling can -be applied to any POJO. As with Spring in general, this service can be applied in a -non-invasive way. - -Spring provides out-of-the-box support for 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 -`org.springframework.aop.target.AbstractPoolingTargetSource` to support any other -pooling API. - -[NOTE] -==== -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"] ----- - - ... properties omitted - - - - - - - - - - - ----- - -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 Javadoc for -`AbstractPoolingTargetSource` and the concrete subclass you wish to use for information -about its properties: "maxSize" is the most basic, and always guaranteed to be present. - -In this case, "myInterceptor" is the name of an interceptor that would need to be -defined in the same IoC context. However, it isn't necessary to specify interceptors to -use pooling. If you want only pooling, and no other advice, don't set the -interceptorNames property at all. - -It's possible to configure Spring so as to be able to cast any pooled object to the -`org.springframework.aop.target.PoolingConfig` interface, which exposes information -about the configuration and current size of the pool through an introduction. You'll -need to define an advisor like this: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - -This advisor is obtained by calling a convenience method on the -`AbstractPoolingTargetSource` class, hence the use of MethodInvokingFactoryBean. This -advisor's name ("poolConfigAdvisor" here) must be in the list of interceptors names in -the ProxyFactoryBean exposing the pooled object. - -The cast will look as follows: - -[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 -be the default choice, as most stateless objects are naturally thread safe, and instance -pooling is problematic if resources are cached. -==== - -Simpler pooling is available using autoproxying. It's possible to set the TargetSources -used by any autoproxy creator. - - - -[[classic-aop-ts-prototype]] -==== Prototype target sources -Setting up a "prototype" target source is similar to a pooling TargetSource. In this -case, a new instance of the target will be created on every method invocation. Although -the cost of creating a new object isn't high in a modern JVM, the cost of wiring up the -new object (satisfying its IoC dependencies) may be more expensive. Thus you shouldn't -use this approach without very good reason. - -To do this, you could modify the `poolTargetSource` definition shown above as follows. -(I've also changed the name, for clarity.) - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - -There's only one property: the name of the target bean. Inheritance is used in the -TargetSource implementations to ensure consistent naming. As with the pooling target -source, the target bean must be a prototype bean definition. - - - -[[classic-aop-ts-threadlocal]] -==== 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 -`ThreadLocalTargetSource` is pretty much the same as was explained for the other types -of target source: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - -[NOTE] -==== -ThreadLocals come with serious issues (potentially resulting in memory leaks) when -incorrectly using them in a multi-threaded and multi-classloader environments. One -should always consider wrapping a threadlocal in some other class and never directly use -the `ThreadLocal` itself (except of course in the wrapper class). Also, one should -always remember to correctly set and unset (where the latter simply involved a call to -`ThreadLocal.set(null)`) the resource local to the thread. Unsetting should be done in -any case since not unsetting it might result in problematic behavior. Spring's -ThreadLocal support does this for you and should always be considered in favor of using -ThreadLocals without other proper handling code. -==== - - - - -[[classic-aop-extensibility]] -=== 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 -after returning advice. - -The `org.springframework.aop.framework.adapter` package is an SPI package allowing -support for new custom advice types to be added without changing the core framework. The -only constraint on a custom `Advice` type is that it must implement the -`org.aopalliance.aop.Advice` tag interface. - -Please refer to the `org.springframework.aop.framework.adapter` package's Javadocs for -further information. - - - - -[[classic-aop-api-resources]] -=== Further resources -Please refer to the Spring sample applications for further examples of Spring AOP: - -* The JPetStore's default configuration illustrates the use of the - `TransactionProxyFactoryBean` for declarative transaction management. -* The `/attributes` directory of the JPetStore illustrates the use of attribute-driven - declarative transaction management. - - - -[[xsd-configuration]] -== XML Schema-based configuration - - -[[xsd-config-introduction]] -=== Introduction -This appendix details the XML Schema-based configuration introduced in Spring 2.0 and -enhanced and extended in Spring 2.5 and 3.0. - -.DTD support? -**** -Authoring Spring configuration files using the older DTD style is still fully supported. - -Nothing will break if you forego the use of the new XML Schema-based approach to -authoring Spring XML configuration files. All that you lose out on is the opportunity to -have more succinct and clearer configuration. Regardless of whether the XML -configuration is DTD- or Schema-based, in the end it all boils down to the same object -model in the container (namely one or more `BeanDefinition` instances). -**** - -The central motivation for moving to XML Schema based configuration files was to make -Spring XML configuration easier. The __'classic'__ ``-based approach is good, but -its generic-nature comes with a price in terms of configuration overhead. - -From the Spring IoC containers point-of-view, __everything__ is a bean. That's great -news for the Spring IoC container, because if everything is a bean then everything can -be treated in the exact same fashion. The same, however, is not true from a developer's -point-of-view. The objects defined in a Spring XML configuration file are not all -generic, vanilla beans. Usually, each bean requires some degree of specific -configuration. - -Spring 2.0's new XML Schema-based configuration addresses this issue. The `` -element is still present, and if you wanted to, you could continue to write the __exact -same__ style of Spring XML configuration using only `` elements. The new XML -Schema-based configuration does, however, make Spring XML configuration files -substantially clearer to read. In addition, it allows you to express the intent of a -bean definition. - -The key thing to remember is that the new custom tags work best for infrastructure or -integration beans: for example, AOP, collections, transactions, integration with -3rd-party frameworks such as Mule, etc., while the existing bean tags are best suited to -application-specific beans, such as DAOs, service layer objects, validators, etc. - -The examples included below will hopefully convince you that the inclusion of XML Schema -support in Spring 2.0 was a good idea. The reception in the community has been -encouraging; also, please note the fact that this new configuration mechanism is totally -customisable and extensible. This means you can write your own domain-specific -configuration tags that would better represent your application's domain; the process -involved in doing so is covered in the appendix entitled <>. - - - - -[[xsd-config-body]] -=== XML Schema-based configuration - - - -[[xsd-config-body-referencing]] -==== Referencing the schemas -To switch over from the DTD-style to the new XML Schema-style, you need to make the -following change. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - ----- - -The equivalent file in the XML Schema-style would be... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - ----- - -[NOTE] -==== -The `'xsi:schemaLocation'` fragment is not actually required, but can be included to -reference a local copy of a schema (which can be useful during development). -==== - -The above Spring XML configuration fragment is boilerplate that you can copy and paste -(!) and then plug `` definitions into like you have always done. However, the -entire point of switching over is to take advantage of the new Spring 2.0 XML tags since -they make configuration easier. The section entitled <> -demonstrates how you can start immediately by using some of the more common utility tags. - -The rest of this chapter is devoted to showing examples of the new Spring XML Schema -based configuration, with at least one example for every new tag. The format follows a -before and after style, with a __before__ snippet of XML showing the old (but still 100% -legal and supported) style, followed immediately by an __after__ example showing the -equivalent in the new XML Schema-based style. - - - -[[xsd-config-body-schemas-util]] -==== the util schema - -First up is coverage of the `util` tags. As the name implies, the `util` tags deal with -common, __utility__ configuration issues, such as configuring collections, referencing -constants, and suchlike. - -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. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - - -[[xsd-config-body-schemas-util-constant]] -===== - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - ----- - -The above 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 -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. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - ----- - -[[xsd-config-body-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. - -Find below an example which 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"] ----- - - - ----- - -There is also a convenience usage form where the `static` field is specified as the bean -name: - -[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: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - ----- - -It is also possible to 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 -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 JDK 5 enum: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package javax.persistence; - - public enum PersistenceContextType { - - TRANSACTION, - EXTENDED - - } ----- - -Now consider a setter of type `PersistenceContextType`: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package example; - - public class Client { - - private PersistenceContextType persistenceContextType; - - public void setPersistenceContextType(PersistenceContextType type) { - this.persistenceContextType = type; - } - - } ----- - -.. and the corresponding bean definition: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - -This works for classic type-safe emulated enums (on JDK 1.4 and JDK 1.3) as well; Spring -will automatically attempt to match the string property value to a constant on the enum -class. - - -[[xsd-config-body-schemas-util-property-path]] -===== - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - ----- - -The above 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... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - ----- - -The value of the `path` attribute of the `` tag follows the form -`beanName.beanProperty`. - -[[xsd-config-body-schemas-util-property-path-dependency]] -====== 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 -argument. - -Here's an example where a path is used against another bean, by name: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - // target bean to be referenced by name - - - - - - - - - - // will result in 11, which is the value of property 'spouse.age' of bean 'person' - - - - ----- - -In this example, a path is evaluated against an inner bean: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - ----- - -There is also a shortcut form, where the bean name is the property path. - -[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: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - ----- - -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 -this feature. - - -[[xsd-config-body-schemas-util-properties]] -===== - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - -The above configuration uses a Spring `FactoryBean` implementation, the -`PropertiesFactoryBean`, to instantiate a `java.util.Properties` instance with values -loaded from the supplied <> location). - -After... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - ----- - - -[[xsd-config-body-schemas-util-list]] -===== - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - pechorin@hero.org - raskolnikov@slums.org - stavrogin@gov.org - porfiry@gov.org - - - ----- - -The above configuration uses a Spring `FactoryBean` implementation, the -`ListFactoryBean`, to create a `java.util.List` instance initialized with values taken -from the supplied `sourceList`. - -After... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - pechorin@hero.org - raskolnikov@slums.org - stavrogin@gov.org - 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 -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"] ----- - - jackshaftoe@vagabond.org - eliza@thinkingmanscrumpet.org - vanhoek@pirate.org - d'Arcachon@nemesis.org - ----- - -If no `list-class` attribute is supplied, a `List` implementation will be chosen by -the container. - - -[[xsd-config-body-schemas-util-map]] -===== - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - ----- - -The above 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... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - ----- - -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 -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"] ----- - - - - - - ----- - -If no `'map-class'` attribute is supplied, a `Map` implementation will be chosen by the -container. - - -[[xsd-config-body-schemas-util-set]] -===== - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - pechorin@hero.org - raskolnikov@slums.org - stavrogin@gov.org - porfiry@gov.org - - - ----- - -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'`. - -After... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - pechorin@hero.org - raskolnikov@slums.org - stavrogin@gov.org - 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 -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"] ----- - - pechorin@hero.org - raskolnikov@slums.org - stavrogin@gov.org - porfiry@gov.org - ----- - -If no `'set-class'` attribute is supplied, a `Set` implementation will be chosen by the -container. - - - -[[xsd-config-body-schemas-jee]] -==== the jee schema - -The `jee` tags deal with Java EE (Java Enterprise Edition)-related configuration issues, -such as looking up a JNDI object and defining EJB references. - -To use the tags in the `jee` 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 `jee` namespace are available to you. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - - -[[xsd-config-body-schemas-jee-jndi-lookup]] -===== (simple) - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - ----- - -After... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - ----- - - -[[xsd-config-body-schemas-jee-jndi-lookup-environment-single]] -===== (with single JNDI environment setting) - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - bar - - - ----- - -After... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - foo=bar - ----- - - -[[xsd-config-body-schemas-jee-jndi-lookup-evironment-multiple]] -===== (with multiple JNDI environment settings) - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - bar - pong - - - ----- - -After... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - foo=bar - ping=pong - - ----- - - -[[xsd-config-body-schemas-jee-jndi-lookup-complex]] -===== (complex) - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - ----- - -After... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - - -[[xsd-config-body-schemas-jee-local-slsb]] -===== (simple) - -The `` tag configures a reference to an EJB Stateless SessionBean. - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - -After... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - - -[[xsd-config-body-schemas-jee-local-slsb-complex]] -===== (complex) - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - ----- - -After... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - - -[[xsd-config-body-schemas-jee-remote-slsb]] -===== - -The `` tag configures a reference to a `remote` EJB Stateless -SessionBean. - -Before... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - ----- - -After... - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - - - -[[xsd-config-body-schemas-lang]] -==== the lang schema - -The `lang` tags deal with exposing objects that have been written in a dynamic language -such as JRuby or Groovy as beans in the Spring container. - -These tags (and the dynamic language support) are comprehensively covered in the chapter -entitled <>. -Please do consult that chapter for full details on this support and the `lang` tags themselves. - -In the interest of completeness, to use the tags in the `lang` 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 `lang` namespace -are available to you. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - - - -[[xsd-config-body-schemas-jms]] -==== the jms schema - -The `jms` tags deal with configuring JMS-related beans such as Spring's -<>. These tags are detailed in the -section of the <> entitled <>. Please do consult that chapter for full details on this support -and the `jms` tags themselves. - -In the interest of completeness, to use the tags in the `jms` 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 `jms` namespace -are available to you. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - - - -[[xsd-config-body-schemas-tx]] -==== the tx (transaction) schema - -The `tx` tags deal with configuring all of those beans in Spring's comprehensive support -for transactions. These tags are covered in the chapter entitled -<>. - -[TIP] -==== - -You are strongly encouraged to look at the `'spring-tx.xsd'` file that ships with the -Spring distribution. This file is (of course), the XML Schema for Spring's transaction -configuration, and covers all of the various tags in the `tx` namespace, including -attribute defaults and suchlike. This file is documented inline, and thus the -information is not repeated here in the interests of adhering to the DRY (Don't Repeat -Yourself) principle. -==== - -In the interest of completeness, to use the tags in the `tx` 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 `tx` namespace -are available to you. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - -[NOTE] -==== -Often when using the tags in the `tx` namespace you will also be using the tags from the -`aop` namespace (since the declarative transaction support in Spring is implemented -using AOP). The above XML snippet contains the relevant lines needed to reference the -`aop` schema so that the tags in the `aop` namespace are available to you. -==== - - - -[[xsd-config-body-schemas-aop]] -==== the aop schema - -The `aop` tags deal with configuring all things AOP in Spring: this includes 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. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - - - -[[xsd-config-body-schemas-context]] -==== 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. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - -[NOTE] -==== -The `context` schema was only introduced in Spring 2.5. -==== - - -[[xsd-config-body-schemas-context-pphc]] -===== - -This element activates the replacement of `${...}` placeholders, resolved against the -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. - - -[[xsd-config-body-schemas-context-ac]] -===== - -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. - -[NOTE] -==== -This element does __not__ activate processing of Spring's -<> annotation. Use the -<`>> element for that purpose. -==== - - -[[xsd-config-body-schemas-context-component-scan]] -===== - -This element is detailed in <>. - - -[[xsd-config-body-schemas-context-ltw]] -===== - -This element is detailed in <>. - - -[[xsd-config-body-schemas-context-sc]] -===== - -This element is detailed in <>. - - -[[xsd-config-body-schemas-context-mbe]] -===== - -This element is detailed in <>. - - - -[[xsd-config-body-schemas-tool]] -==== the tool schema - -The `tool` tags are for use when you want to add tooling-specific metadata to your -custom configuration elements. This metadata can then be consumed by tools that are -aware of this metadata, and the tools can then do pretty much whatever they want with it -(validation, etc.). - -The `tool` tags are not documented in this release of Spring as they are currently -undergoing review. If you are a third party tool vendor and you would like to contribute -to this review process, then do mail the Spring mailing list. The currently supported -`tool` tags can be found in the file `'spring-tool.xsd'` in the -`'src/org/springframework/beans/factory/xml'` directory of the Spring source -distribution. - - - -[[xsd-config-body-schemas-jdbc]] -==== the jdbc schema - -The `jdbc` tags allow you to quickly configure an embedded database or initialize an -existing data source. These tags are documented in -<> -and <> respectively. - -To use the tags in the `jdbc` 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 `jdbc` namespace are available to you. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - - - -[[xsd-config-body-schemas-cache]] -==== the cache schema - -The `cache` tags can be used to enable support for Spring's `@CacheEvict`, `@CachePut` -and `@Caching` annotations. It it also supports declarative XML-based caching. See -<> and -<> for details. - -To use the tags in the `cache` 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 `cache` namespace are available to you. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - - - -[[xsd-config-body-schemas-beans]] -==== 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 -in the `beans` schema are not shown here because they are quite comprehensively covered -in <> -(and indeed in that entire <>). - -One thing that is new to the beans tags themselves in Spring 2.0 is the idea of -arbitrary bean metadata. In Spring 2.0 it is now possible to 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 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). - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - ____ - - - - ----- - -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 -metadata. - - - - -[[xml-custom]] -== Extensible XML authoring - - -[[extensible-xml-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. - -To facilitate the authoring of configuration files using 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<>. - -Creating new XML configuration extensions can be done by following these (relatively) -simple steps: - -* <> 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 - (this is where the real work is done). -* <> the above artifacts with Spring (this too - is an easy step). - -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: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - -__(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.)__ - - - - -[[extensible-xml-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. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - ----- - -(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. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - -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. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - -[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 -defined in the enumeration. -==== - - - - -[[extensible-xml-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` -element. - -The `NamespaceHandler` interface is pretty simple in that it features just 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 - 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 - 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. - -Although it is perfectly possible to 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 -use the `NamespaceHandlerSupport` class: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.samples.xml; - - import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - - public class MyNamespaceHandler extends NamespaceHandlerSupport { - - public void init() { - **registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());** - } - - } ----- - -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 -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 - - - - -[[extensible-xml-parser]] -=== 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: - -[source,java,indent=0] ----- - package org.springframework.samples.xml; - - import org.springframework.beans.factory.support.BeanDefinitionBuilder; - import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; - import org.springframework.util.StringUtils; - import org.w3c.dom.Element; - - import java.text.SimpleDateFormat; - - public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { // <1> - - protected Class getBeanClass(Element element) { - return SimpleDateFormat.class; // <2> - } - - protected void doParse(Element element, BeanDefinitionBuilder bean) { - // this will never be null since the schema explicitly requires that a value be supplied - String pattern = element.getAttribute("pattern"); - bean.addConstructorArg(pattern); - - // this however is an optional property - String lenient = element.getAttribute("lenient"); - if (StringUtils.hasText(lenient)) { - bean.addPropertyValue("lenient", Boolean.valueOf(lenient)); - } - } - - } ----- - -<1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of -the basic grunt work of creating a __single__ `BeanDefinition`. - -<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our -single `BeanDefinition` will represent. - -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 -is the extraction and setting of the bean definition's unique identifier. - - - - -[[extensible-xml-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 -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. - - - -[[extensible-xml-registration-spring-handlers]] -==== '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: - -[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 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. - - - -[[extensible-xml-registration-spring-schemas]] -==== '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 -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): - -[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 -the `NamespaceHandler` and `BeanDefinitionParser` classes on the classpath. - - - - -[[extensible-xml-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. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - ----- - - - - -[[extensible-xml-meat]] -=== Meatier examples -Find below some much meatier examples of custom XML extensions. - - - -[[extensible-xml-custom-nested]] -==== Nesting custom tags within custom tags -This example illustrates how you might go about writing the various artifacts required -to satisfy a target of the following configuration: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - ----- - -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. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package com.foo; - - import java.util.ArrayList; - import java.util.List; - - public class Component { - - private String name; - private List components = new ArrayList (); - - // mmm, there is no setter method for the 'components' - public void addComponent(Component component) { - this.components.add(component); - } - - public List getComponents() { - return components; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - } ----- - -The typical solution to this issue is to create a custom `FactoryBean` that exposes a -setter property for the `'components'` property. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package com.foo; - - import org.springframework.beans.factory.FactoryBean; - - import java.util.List; - - public class ComponentFactoryBean implements FactoryBean { - - private Component parent; - private List children; - - public void setParent(Component parent) { - this.parent = parent; - } - - public void setChildren(List children) { - this.children = children; - } - - public Component getObject() throws Exception { - if (this.children != null && this.children.size() > 0) { - for (Component child : children) { - this.parent.addComponent(child); - } - } - return this.parent; - } - - public Class getObjectType() { - return Component.class; - } - - public boolean isSingleton() { - return true; - } - - } ----- - -This is all very well, and does work nicely, but 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. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - ----- - -We'll then create a custom `NamespaceHandler`. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package com.foo; - - import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - - public class ComponentNamespaceHandler extends NamespaceHandlerSupport { - - public void init() { - registerBeanDefinitionParser("component", new ComponentBeanDefinitionParser()); - } - - } ----- - -Next up is the custom `BeanDefinitionParser`. Remember that what we are creating is a -`BeanDefinition` describing a `ComponentFactoryBean`. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package com.foo; - - import org.springframework.beans.factory.config.BeanDefinition; - import org.springframework.beans.factory.support.AbstractBeanDefinition; - import org.springframework.beans.factory.support.BeanDefinitionBuilder; - import org.springframework.beans.factory.support.ManagedList; - import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; - import org.springframework.beans.factory.xml.ParserContext; - import org.springframework.util.xml.DomUtils; - import org.w3c.dom.Element; - - import java.util.List; - - public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser { - - protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { - return parseComponentElement(element); - } - - private static AbstractBeanDefinition parseComponentElement(Element element) { - BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(ComponentFactoryBean.class); - factory.addPropertyValue("parent", parseComponent(element)); - - List childElements = DomUtils.getChildElementsByTagName(element, "component"); - if (childElements != null && childElements.size() > 0) { - parseChildComponents(childElements, factory); - } - - return factory.getBeanDefinition(); - } - - private static BeanDefinition parseComponent(Element element) { - BeanDefinitionBuilder component = BeanDefinitionBuilder.rootBeanDefinition(Component.class); - component.addPropertyValue("name", element.getAttribute("name")); - return component.getBeanDefinition(); - } - - private static void parseChildComponents(List childElements, BeanDefinitionBuilder factory) { - ManagedList children = new ManagedList(childElements.size()); - for (Element element : childElements) { - children.add(parseComponentElement(element)); - } - factory.addPropertyValue("children", children); - } - - } ----- - -Lastly, the various artifacts need to be registered with the Spring XML infrastructure. - -[literal] -[subs="verbatim,quotes"] ----- -# in 'META-INF/spring.handlers' -http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler ----- - -[literal] -[subs="verbatim,quotes"] ----- -# in 'META-INF/spring.schemas' -http\://www.foo.com/schema/component/component.xsd=com/foo/component.xsd ----- - - - -[[extensible-xml-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 -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 -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: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - -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`. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package com.foo; - - public class JCacheInitializer { - - private String name; - - public JCacheInitializer(String name) { - this.name = name; - } - - public void initialize() { - // lots of JCache API calls to initialize the named cache... - } - - } ----- - -Now onto the custom extension. Firstly, the authoring of the XSD schema describing the -custom attribute (quite easy in this case). - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - ----- - -Next, the associated `NamespaceHandler`. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package com.foo; - - import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - - public class JCacheNamespaceHandler extends NamespaceHandlerSupport { - - public void init() { - super.registerBeanDefinitionDecoratorForAttribute("cache-name", - new JCacheInitializingBeanDefinitionDecorator()); - } - - } ----- - -Next, the parser. Note that in this case, because we are going to be parsing an XML -attribute, we write a `BeanDefinitionDecorator` rather than a `BeanDefinitionParser`. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package com.foo; - - import org.springframework.beans.factory.config.BeanDefinitionHolder; - import org.springframework.beans.factory.support.AbstractBeanDefinition; - import org.springframework.beans.factory.support.BeanDefinitionBuilder; - import org.springframework.beans.factory.xml.BeanDefinitionDecorator; - import org.springframework.beans.factory.xml.ParserContext; - import org.w3c.dom.Attr; - import org.w3c.dom.Node; - - import java.util.ArrayList; - import java.util.Arrays; - import java.util.List; - - public class JCacheInitializingBeanDefinitionDecorator implements BeanDefinitionDecorator { - - private static final String[] EMPTY_STRING_ARRAY = new String[0]; - - public BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder holder, - ParserContext ctx) { - String initializerBeanName = registerJCacheInitializer(source, ctx); - createDependencyOnJCacheInitializer(holder, initializerBeanName); - return holder; - } - - private void createDependencyOnJCacheInitializer(BeanDefinitionHolder holder, - String initializerBeanName) { - AbstractBeanDefinition definition = ((AbstractBeanDefinition) holder.getBeanDefinition()); - String[] dependsOn = definition.getDependsOn(); - if (dependsOn == null) { - dependsOn = new String[]{initializerBeanName}; - } else { - List dependencies = new ArrayList(Arrays.asList(dependsOn)); - dependencies.add(initializerBeanName); - dependsOn = (String[]) dependencies.toArray(EMPTY_STRING_ARRAY); - } - definition.setDependsOn(dependsOn); - } - - private String registerJCacheInitializer(Node source, ParserContext ctx) { - String cacheName = ((Attr) source).getValue(); - String beanName = cacheName + "-initializer"; - if (!ctx.getRegistry().containsBeanDefinition(beanName)) { - BeanDefinitionBuilder initializer = BeanDefinitionBuilder.rootBeanDefinition(JCacheInitializer.class); - initializer.addConstructorArg(cacheName); - ctx.getRegistry().registerBeanDefinition(beanName, initializer.getBeanDefinition()); - } - return beanName; - } - - } ----- - -Lastly, the various artifacts need to be registered with the Spring XML infrastructure. - -[literal] -[subs="verbatim,quotes"] ----- -# in 'META-INF/spring.handlers' -http\://www.foo.com/schema/jcache=com.foo.JCacheNamespaceHandler ----- - -[literal] -[subs="verbatim,quotes"] ----- -# in 'META-INF/spring.schemas' -http\://www.foo.com/schema/jcache/jcache.xsd=com/foo/jcache.xsd ----- - - - - -[[extensible-xml-resources]] -=== Further Resources -Find below links to further resources concerning XML Schema and the extensible XML -support described in this chapter. - -* The http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/[XML Schema Part 1: Structures - Second Edition] -* The http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/[XML Schema Part 2: Datatypes - Second Edition] - - - -include::appendix/appx-spring-tld.adoc[leveloffset=+1] - -include::appendix/appx-spring-form-tld.adoc[leveloffset=+1] - diff --git a/src/docs/asciidoc/core.adoc b/src/docs/asciidoc/core.adoc index 2c40f336da8..2a503640bbf 100644 --- a/src/docs/asciidoc/core.adoc +++ b/src/docs/asciidoc/core.adoc @@ -34,3 +34,4 @@ include::core/core-aop-api.adoc[leveloffset=+1] include::core/core-null-safety.adoc[leveloffset=+1] +include::core/core-appendix.adoc[leveloffset=+1] diff --git a/src/docs/asciidoc/core/core-aop.adoc b/src/docs/asciidoc/core/core-aop.adoc index 2ab4510f9b8..64341524b18 100644 --- a/src/docs/asciidoc/core/core-aop.adoc +++ b/src/docs/asciidoc/core/core-aop.adoc @@ -259,9 +259,10 @@ element: ---- -This assumes that you are using schema support as described in <>. See <> -for how to import the tags in the `aop` namespace. +This assumes that you are using schema support as described in +<>. See +<> for how to import the tags in the `aop` +namespace. @@ -1553,9 +1554,9 @@ the new __syntax__ and refer the reader to the discussion in the previous sectio 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 <> +See <> for how to import the tags in the `aop` namespace. Within your Spring configurations, all aspect and advisor elements must be placed within @@ -2793,8 +2794,9 @@ using Java based configuration simply add `@EnableSpringConfigured` to any } ---- -If you prefer XML based configuration, the Spring <> defines a convenient `context:spring-configured` element: +If you prefer XML based configuration, the Spring +<> +defines a convenient `context:spring-configured` element: [source,xml,indent=0] [subs="verbatim,quotes"] diff --git a/src/docs/asciidoc/core/core-appendix.adoc b/src/docs/asciidoc/core/core-appendix.adoc new file mode 100644 index 00000000000..83d1af085bb --- /dev/null +++ b/src/docs/asciidoc/core/core-appendix.adoc @@ -0,0 +1,1376 @@ +:doc-root: https://docs.spring.io +:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework + += Appendix + + +[[xsd-schemas]] +== XML Schemas + +This part of the appendix lists XML schemas related to the core container. + + +[[xsd-schemas-util]] +=== The util schema + +As the name implies, the `util` tags deal with common, __utility__ configuration +issues, such as configuring collections, referencing constants, and suchlike. +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. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + + +[[xsd-schemas-util-constant]] +==== + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + +---- + +The above 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 +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. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + +---- + +[[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. + +Find below an example which 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"] +---- + + + +---- + +There is also a convenience usage form where the `static` field is specified as the bean +name: + +[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: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + +---- + +It is also possible to 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 +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 JDK 5 enum: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package javax.persistence; + + public enum PersistenceContextType { + + TRANSACTION, + EXTENDED + + } +---- + +Now consider a setter of type `PersistenceContextType`: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package example; + + public class Client { + + private PersistenceContextType persistenceContextType; + + public void setPersistenceContextType(PersistenceContextType type) { + this.persistenceContextType = type; + } + + } +---- + +.. and the corresponding bean definition: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + +---- + +This works for classic type-safe emulated enums (on JDK 1.4 and JDK 1.3) as well; Spring +will automatically attempt to match the string property value to a constant on the enum +class. + + +[[xsd-schemas-util-property-path]] +==== + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + +---- + +The above 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... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + +---- + +The value of the `path` attribute of the `` tag follows the form +`beanName.beanProperty`. + +[[xsd-schemas-util-property-path-dependency]] +===== 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 +argument. + +Here's an example where a path is used against another bean, by name: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + // target bean to be referenced by name + + + + + + + + + + // will result in 11, which is the value of property 'spouse.age' of bean 'person' + + + + +---- + +In this example, a path is evaluated against an inner bean: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + +---- + +There is also a shortcut form, where the bean name is the property path. + +[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: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + +---- + +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 +this feature. + + +[[xsd-schemas-util-properties]] +==== + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + +The above configuration uses a Spring `FactoryBean` implementation, the +`PropertiesFactoryBean`, to instantiate a `java.util.Properties` instance with values +loaded from the supplied <> location). + +After... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + +---- + + +[[xsd-schemas-util-list]] +==== + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + pechorin@hero.org + raskolnikov@slums.org + stavrogin@gov.org + porfiry@gov.org + + + +---- + +The above configuration uses a Spring `FactoryBean` implementation, the +`ListFactoryBean`, to create a `java.util.List` instance initialized with values taken +from the supplied `sourceList`. + +After... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + pechorin@hero.org + raskolnikov@slums.org + stavrogin@gov.org + 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 +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"] +---- + + jackshaftoe@vagabond.org + eliza@thinkingmanscrumpet.org + vanhoek@pirate.org + d'Arcachon@nemesis.org + +---- + +If no `list-class` attribute is supplied, a `List` implementation will be chosen by +the container. + + +[[xsd-schemas-util-map]] +==== + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + +---- + +The above 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... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + +---- + +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 +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"] +---- + + + + + + +---- + +If no `'map-class'` attribute is supplied, a `Map` implementation will be chosen by the +container. + + +[[xsd-schemas-util-set]] +==== + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + pechorin@hero.org + raskolnikov@slums.org + stavrogin@gov.org + porfiry@gov.org + + + +---- + +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'`. + +After... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + pechorin@hero.org + raskolnikov@slums.org + stavrogin@gov.org + 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 +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"] +---- + + pechorin@hero.org + raskolnikov@slums.org + stavrogin@gov.org + porfiry@gov.org + +---- + +If no `'set-class'` attribute is supplied, a `Set` implementation will be chosen by the +container. + + + +[[xsd-schemas-aop]] +=== The aop schema + +The `aop` tags deal with configuring all things AOP in Spring: this includes 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. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + + + +[[xsd-schemas-context]] +=== 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. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + + +[[xsd-schemas-context-pphc]] +==== + +This element activates the replacement of `${...}` placeholders, resolved against the +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. + + +[[xsd-schemas-context-ac]] +==== + +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. + +[NOTE] +==== +This element does __not__ activate processing of Spring's +<> annotation. Use the +<`>> element for that purpose. +==== + + +[[xsd-schemas-context-component-scan]] +==== + +This element is detailed in <>. + + +[[xsd-schemas-context-ltw]] +==== + +This element is detailed in <>. + + +[[xsd-schemas-context-sc]] +==== + +This element is detailed in <>. + + +[[xsd-schemas-context-mbe]] +==== + +This element is detailed in <>. + + + +[[xsd-schemas-beans]] +=== 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 +in the `beans` schema are not shown here because they are quite comprehensively covered +in <> +(and indeed in that entire <>). + +Note that it is possible to 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 +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). + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + ____ + + + + +---- + +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 +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. + +To facilitate the authoring of configuration files using 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<>. + +Creating new XML configuration extensions can be done by following these (relatively) +simple steps: + +* <> 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 + (this is where the real work is done). +* <> the above artifacts with Spring (this too + is an easy step). + +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: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + +__(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.)__ + + + + +[[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. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + +---- + +(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. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + +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. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + +[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 +defined in the enumeration. +==== + + + + +[[xsd-custom-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` +element. + +The `NamespaceHandler` interface is pretty simple in that it features just 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 + 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 + 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. + +Although it is perfectly possible to 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 +use the `NamespaceHandlerSupport` class: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.samples.xml; + + import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + + public class MyNamespaceHandler extends NamespaceHandlerSupport { + + public void init() { + **registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());** + } + + } +---- + +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 +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 + + + + +[[xsd-custom-parser]] +=== 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: + +[source,java,indent=0] +---- + package org.springframework.samples.xml; + + import org.springframework.beans.factory.support.BeanDefinitionBuilder; + import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; + import org.springframework.util.StringUtils; + import org.w3c.dom.Element; + + import java.text.SimpleDateFormat; + + public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { // <1> + + protected Class getBeanClass(Element element) { + return SimpleDateFormat.class; // <2> + } + + protected void doParse(Element element, BeanDefinitionBuilder bean) { + // this will never be null since the schema explicitly requires that a value be supplied + String pattern = element.getAttribute("pattern"); + bean.addConstructorArg(pattern); + + // this however is an optional property + String lenient = element.getAttribute("lenient"); + if (StringUtils.hasText(lenient)) { + bean.addPropertyValue("lenient", Boolean.valueOf(lenient)); + } + } + + } +---- + +<1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of +the basic grunt work of creating a __single__ `BeanDefinition`. + +<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our +single `BeanDefinition` will represent. + +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 +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 +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. + + + +[[xsd-custom-registration-spring-handlers]] +==== '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: + +[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 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. + + + +[[xsd-custom-registration-spring-schemas]] +==== '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 +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): + +[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 +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. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + +---- + + + + +[[xsd-custom-meat]] +=== Meatier examples +Find below some much meatier 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 +to satisfy a target of the following configuration: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + +---- + +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. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package com.foo; + + import java.util.ArrayList; + import java.util.List; + + public class Component { + + private String name; + private List components = new ArrayList (); + + // mmm, there is no setter method for the 'components' + public void addComponent(Component component) { + this.components.add(component); + } + + public List getComponents() { + return components; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + } +---- + +The typical solution to this issue is to create a custom `FactoryBean` that exposes a +setter property for the `'components'` property. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package com.foo; + + import org.springframework.beans.factory.FactoryBean; + + import java.util.List; + + public class ComponentFactoryBean implements FactoryBean { + + private Component parent; + private List children; + + public void setParent(Component parent) { + this.parent = parent; + } + + public void setChildren(List children) { + this.children = children; + } + + public Component getObject() throws Exception { + if (this.children != null && this.children.size() > 0) { + for (Component child : children) { + this.parent.addComponent(child); + } + } + return this.parent; + } + + public Class getObjectType() { + return Component.class; + } + + public boolean isSingleton() { + return true; + } + + } +---- + +This is all very well, and does work nicely, but 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. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + +---- + +We'll then create a custom `NamespaceHandler`. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package com.foo; + + import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + + public class ComponentNamespaceHandler extends NamespaceHandlerSupport { + + public void init() { + registerBeanDefinitionParser("component", new ComponentBeanDefinitionParser()); + } + + } +---- + +Next up is the custom `BeanDefinitionParser`. Remember that what we are creating is a +`BeanDefinition` describing a `ComponentFactoryBean`. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package com.foo; + + import org.springframework.beans.factory.config.BeanDefinition; + import org.springframework.beans.factory.support.AbstractBeanDefinition; + import org.springframework.beans.factory.support.BeanDefinitionBuilder; + import org.springframework.beans.factory.support.ManagedList; + import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; + import org.springframework.beans.factory.xml.ParserContext; + import org.springframework.util.xml.DomUtils; + import org.w3c.dom.Element; + + import java.util.List; + + public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser { + + protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { + return parseComponentElement(element); + } + + private static AbstractBeanDefinition parseComponentElement(Element element) { + BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(ComponentFactoryBean.class); + factory.addPropertyValue("parent", parseComponent(element)); + + List childElements = DomUtils.getChildElementsByTagName(element, "component"); + if (childElements != null && childElements.size() > 0) { + parseChildComponents(childElements, factory); + } + + return factory.getBeanDefinition(); + } + + private static BeanDefinition parseComponent(Element element) { + BeanDefinitionBuilder component = BeanDefinitionBuilder.rootBeanDefinition(Component.class); + component.addPropertyValue("name", element.getAttribute("name")); + return component.getBeanDefinition(); + } + + private static void parseChildComponents(List childElements, BeanDefinitionBuilder factory) { + ManagedList children = new ManagedList(childElements.size()); + for (Element element : childElements) { + children.add(parseComponentElement(element)); + } + factory.addPropertyValue("children", children); + } + + } +---- + +Lastly, the various artifacts need to be registered with the Spring XML infrastructure. + +[literal] +[subs="verbatim,quotes"] +---- +# in 'META-INF/spring.handlers' +http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler +---- + +[literal] +[subs="verbatim,quotes"] +---- +# 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 +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 +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: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + +---- + +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`. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package com.foo; + + public class JCacheInitializer { + + private String name; + + public JCacheInitializer(String name) { + this.name = name; + } + + public void initialize() { + // lots of JCache API calls to initialize the named cache... + } + + } +---- + +Now onto the custom extension. Firstly, the authoring of the XSD schema describing the +custom attribute (quite easy in this case). + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + +---- + +Next, the associated `NamespaceHandler`. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package com.foo; + + import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + + public class JCacheNamespaceHandler extends NamespaceHandlerSupport { + + public void init() { + super.registerBeanDefinitionDecoratorForAttribute("cache-name", + new JCacheInitializingBeanDefinitionDecorator()); + } + + } +---- + +Next, the parser. Note that in this case, because we are going to be parsing an XML +attribute, we write a `BeanDefinitionDecorator` rather than a `BeanDefinitionParser`. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package com.foo; + + import org.springframework.beans.factory.config.BeanDefinitionHolder; + import org.springframework.beans.factory.support.AbstractBeanDefinition; + import org.springframework.beans.factory.support.BeanDefinitionBuilder; + import org.springframework.beans.factory.xml.BeanDefinitionDecorator; + import org.springframework.beans.factory.xml.ParserContext; + import org.w3c.dom.Attr; + import org.w3c.dom.Node; + + import java.util.ArrayList; + import java.util.Arrays; + import java.util.List; + + public class JCacheInitializingBeanDefinitionDecorator implements BeanDefinitionDecorator { + + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + + public BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder holder, + ParserContext ctx) { + String initializerBeanName = registerJCacheInitializer(source, ctx); + createDependencyOnJCacheInitializer(holder, initializerBeanName); + return holder; + } + + private void createDependencyOnJCacheInitializer(BeanDefinitionHolder holder, + String initializerBeanName) { + AbstractBeanDefinition definition = ((AbstractBeanDefinition) holder.getBeanDefinition()); + String[] dependsOn = definition.getDependsOn(); + if (dependsOn == null) { + dependsOn = new String[]{initializerBeanName}; + } else { + List dependencies = new ArrayList(Arrays.asList(dependsOn)); + dependencies.add(initializerBeanName); + dependsOn = (String[]) dependencies.toArray(EMPTY_STRING_ARRAY); + } + definition.setDependsOn(dependsOn); + } + + private String registerJCacheInitializer(Node source, ParserContext ctx) { + String cacheName = ((Attr) source).getValue(); + String beanName = cacheName + "-initializer"; + if (!ctx.getRegistry().containsBeanDefinition(beanName)) { + BeanDefinitionBuilder initializer = BeanDefinitionBuilder.rootBeanDefinition(JCacheInitializer.class); + initializer.addConstructorArg(cacheName); + ctx.getRegistry().registerBeanDefinition(beanName, initializer.getBeanDefinition()); + } + return beanName; + } + + } +---- + +Lastly, the various artifacts need to be registered with the Spring XML infrastructure. + +[literal] +[subs="verbatim,quotes"] +---- +# in 'META-INF/spring.handlers' +http\://www.foo.com/schema/jcache=com.foo.JCacheNamespaceHandler +---- + +[literal] +[subs="verbatim,quotes"] +---- +# 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 c231dc634f3..f0d6d03101a 100644 --- a/src/docs/asciidoc/core/core-beans.adoc +++ b/src/docs/asciidoc/core/core-beans.adoc @@ -1711,7 +1711,8 @@ The above configuration is equivalent to the following Java code: The p-namespace enables you to use the `bean` element's attributes, instead of nested `` elements, to describe your property values and/or collaborating beans. -Spring supports extensible configuration formats <>, +Spring supports extensible configuration formats +<>, which are based on an XML Schema definition. The `beans` configuration format discussed in this chapter is defined in an XML Schema document. However, the p-namespace is not defined in an XSD file and exists only in the core of Spring. @@ -2771,7 +2772,7 @@ understand the "why" as well as the "how" behind it. To create such a proxy, you insert a child `` element into a scoped bean definition (see <> and -<>). +<>). Why do definitions of beans scoped at the `request`, `session` and custom-scope levels require the `` element? Let's examine the following singleton bean definition and contrast it with @@ -5293,7 +5294,9 @@ Or with an overridden value for the `proxyMode` as follows: } ---- -For further details, consult the <>. +For further details, consult the +https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model[Spring Annotation Programming Model] +wiki page. [[beans-scanning-autodetection]] diff --git a/src/docs/asciidoc/data-access-appendix.adoc b/src/docs/asciidoc/data-access-appendix.adoc new file mode 100644 index 00000000000..54bcd2a22db --- /dev/null +++ b/src/docs/asciidoc/data-access-appendix.adoc @@ -0,0 +1,80 @@ += Appendix + +[[xsd-schemas]] +== XML Schemas + +This part of the appendix lists XML schemas for data access. + + +[[xsd-schemas-tx]] +=== The `tx` schema + +The `tx` tags deal with configuring all of those beans in Spring's comprehensive support +for transactions. These tags are covered in the chapter entitled +<>. + +[TIP] +==== + +You are strongly encouraged to look at the `'spring-tx.xsd'` file that ships with the +Spring distribution. This file is (of course), the XML Schema for Spring's transaction +configuration, and covers all of the various tags in the `tx` namespace, including +attribute defaults and suchlike. This file is documented inline, and thus the +information is not repeated here in the interests of adhering to the DRY (Don't Repeat +Yourself) principle. +==== + +In the interest of completeness, to use the tags in the `tx` 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 `tx` namespace +are available to you. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + +[NOTE] +==== +Often when using the tags in the `tx` namespace you will also be using the tags from the +`aop` namespace (since the declarative transaction support in Spring is implemented +using AOP). The above XML snippet contains the relevant lines needed to reference the +`aop` schema so that the tags in the `aop` namespace are available to you. +==== + + + +[[xsd-schemas-jdbc]] +=== The `jdbc` schema + +The `jdbc` tags allow you to quickly configure an embedded database or initialize an +existing data source. These tags are documented in +<> +and <> respectively. + +To use the tags in the `jdbc` 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 `jdbc` namespace are available to you. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- diff --git a/src/docs/asciidoc/data-access.adoc b/src/docs/asciidoc/data-access.adoc index 7d4fba41f1e..c54f2082d3d 100644 --- a/src/docs/asciidoc/data-access.adoc +++ b/src/docs/asciidoc/data-access.adoc @@ -302,11 +302,8 @@ infrastructure. [NOTE] ==== The above definition of the `dataSource` bean uses the `` tag from the -`jee` namespace. For more information on schema-based configuration, see -<>, -and for more information on the `` -tags see the section entitled <>. +`jee` namespace. For more information see +<>. ==== You can also use Hibernate local transactions easily, as shown in the following @@ -4929,9 +4926,7 @@ You can configure all of the supported features for O/R (object relational) mapp tools through Dependency Injection. They can participate in Spring's resource and transaction management, and they comply with Spring's generic transaction and DAO exception hierarchies. The recommended integration style is to code DAOs against plain -Hibernate or JPA APIs. The older style of using Spring's DAO templates is no longer -recommended; however, coverage of this style can be found in the -<> in the appendices. +Hibernate or JPA APIs. Spring adds significant enhancements to the ORM layer of your choice when you create data access applications. You can leverage as much of the integration support as you @@ -6680,3 +6675,6 @@ vulnerabilities do not get invoked. NOTE: Note that XStream is an XML serialization library, not a data binding library. Therefore, it has limited namespace support. As such, it is rather unsuitable for usage within Web services. + + +include::data-access-appendix.adoc[leveloffset=+1] diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index c1ba38bc163..ab810910a6c 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -26,4 +26,3 @@ WebClient, WebSocket support. <> :: Remoting, JMS, JCA, JMX, Email, Tasks, Scheduling, Cache, Dynamic languages. <> :: Extensions, Bean Definition DSL, WebFlux DSL -<> :: XML Schemas, JSP Tag Libraries \ No newline at end of file diff --git a/src/docs/asciidoc/integration-appendix.adoc b/src/docs/asciidoc/integration-appendix.adoc new file mode 100644 index 00000000000..0563f54d59c --- /dev/null +++ b/src/docs/asciidoc/integration-appendix.adoc @@ -0,0 +1,346 @@ += Appendix + +[[xsd-schemas]] +== XML Schemas + +This part of the appendix lists XML schemas related to integration technologies. + + +[[xsd-schemas-jee]] +=== The jee schema + +The `jee` tags deal with Java EE (Java Enterprise Edition)-related configuration issues, +such as looking up a JNDI object and defining EJB references. + +To use the tags in the `jee` 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 `jee` namespace are available to you. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + + +[[xsd-schemas-jee-jndi-lookup]] +==== (simple) + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + +---- + +After... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + +---- + + +[[xsd-schemas-jee-jndi-lookup-environment-single]] +==== (with single JNDI environment setting) + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + bar + + + +---- + +After... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + foo=bar + +---- + + +[[xsd-schemas-jee-jndi-lookup-evironment-multiple]] +==== (with multiple JNDI environment settings) + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + bar + pong + + + +---- + +After... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + foo=bar + ping=pong + + +---- + + +[[xsd-schemas-jee-jndi-lookup-complex]] +==== (complex) + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + +---- + +After... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + + +[[xsd-schemas-jee-local-slsb]] +==== (simple) + +The `` tag configures a reference to an EJB Stateless SessionBean. + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + +After... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + + +[[xsd-schemas-jee-local-slsb-complex]] +==== (complex) + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + +---- + +After... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + + +[[xsd-schemas-jee-remote-slsb]] +==== + +The `` tag configures a reference to a `remote` EJB Stateless +SessionBean. + +Before... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + +---- + +After... + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + + + +[[xsd-schemas-lang]] +=== The lang schema + +The `lang` tags deal with exposing objects that have been written in a dynamic language +such as JRuby or Groovy as beans in the Spring container. + +These tags (and the dynamic language support) are comprehensively covered in the chapter +entitled <>. +Please do consult that chapter for full details on this support and the `lang` tags themselves. + +In the interest of completeness, to use the tags in the `lang` 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 `lang` namespace +are available to you. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + + + +[[xsd-schemas-jms]] +=== The jms schema + +The `jms` tags deal with configuring JMS-related beans such as Spring's +<>. These tags are detailed in the +section of the <> entitled <>. Please do consult that chapter for full details on this support +and the `jms` tags themselves. + +In the interest of completeness, to use the tags in the `jms` 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 `jms` namespace +are available to you. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + + +[[xsd-schemas-context-mbe]] +=== + +This element is detailed in +<>. + + + +[[xsd-schemas-cache]] +=== The cache schema + +The `cache` tags can be used to enable support for Spring's `@CacheEvict`, `@CachePut` +and `@Caching` annotations. It it also supports declarative XML-based caching. See +<> and +<> for details. + +To use the tags in the `cache` 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 `cache` namespace are available to you. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- diff --git a/src/docs/asciidoc/integration.adoc b/src/docs/asciidoc/integration.adoc index ae761a651d7..7dd72897982 100644 --- a/src/docs/asciidoc/integration.adoc +++ b/src/docs/asciidoc/integration.adoc @@ -9033,3 +9033,6 @@ policies and different topologies which other solutions do not (take for example `ConcurrentHashMap`) - exposing that in the cache abstraction would be useless simply because there would no backing support. Such functionality should be controlled directly through the backing cache, when configuring it or through its native API. + + +include::integration-appendix.adoc[leveloffset=+1] diff --git a/src/docs/asciidoc/web/webmvc-view.adoc b/src/docs/asciidoc/web/webmvc-view.adoc index 741adc9866e..bc3eff35cb5 100644 --- a/src/docs/asciidoc/web/webmvc-view.adoc +++ b/src/docs/asciidoc/web/webmvc-view.adoc @@ -574,10 +574,10 @@ earlier chapters. To facilitate the development of JSP pages in combination with data binding features, Spring provides a few tags that make things even easier. All Spring tags have__HTML escaping__ features to enable or disable escaping of characters. -The tag library descriptor (TLD) is included in the `spring-webmvc.jar`. Further -information about the individual tags can be found in the appendix entitled -<>. - +The tag library descriptor (TLD) is included in the `spring-webmvc.jar`. For information +on individual tags, see the API reference for the +{api-spring-framework}/web/servlet/tags/package-summary.html[spring tags] and the . +{api-spring-framework}/web/servlet/tags/form/package-summary.html[spring-form tags] [[mvc-view-jsp-formtaglib]]