【Spring】Spring Framework Reference Documentation中文版35

40. Classic Spring AOP Usage

经典的springAOP使用

 

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 AOP chapter, but when working with existing applications, or when reading books and articles, you may come across Spring 1.2 style examples. Spring 2.0 is fully backwards compatible with Spring 1.2 and everything described in this appendix is fully supported in Spring 2.0.

在这一部分,我们讨论低级别的springAOPAPIAOP的支持在spring1.2应用中的使用。对于新的应用。我们建议使用spring2.0AOP支持描述在AOP章节但是当对于已有的应用或者读取书籍和文章是,你可能需要一些spirng1.2的样式的例子。spring2.0是向下兼容spring1.2的并且大部分描述都在spring2.0中支持。

 

40.1 Pointcut API in Spring

springPointcutAPI

 

Lets look at how Spring handles the crucial pointcut concept.

让我们看一下spring是如何处理pointcut的内容的。

 

40.1.1 Concepts

内容

 

Springs pointcut model enables pointcut reuse independent of advice types. Its possible to target different advice using the same pointcut.

spring的切点模型允许切点重用依赖于通知类型。他是重要的对于目标的不同使用相同的切点。

 

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:

org.springframework.aop.Pointcut接口是重要的接口,使用目标advices对于普通的类和方法。完整的接口展示如下:

 

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).

分开Pointcut接口为两部分允许类的重用和方法匹配部分。和细粒度的组合操作(例如执行union和另一个方法匹配)。

 

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:

ClassFilter接口被使用来限制切点对于给定的目标类。如果matches方法允许返回true,所有的目标类将被匹配。

 

public interface ClassFilter {

 

    boolean matches(Class clazz);

 

}

 

The MethodMatcher interface is normally more important. The complete interface is shown below:

MethodMatcher接口通常是很重要的。完整的接口展示如下:

 

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.

matches方法被使用于测试当ponitcut将匹配给定的方法对于目标类。这个处理可以被执行当一个AOP代理被创建的时候,来避免对于测试每个方法调用的需要。如果两个参数匹配方法返回true对于给定的方法并且isRuntine方法对于MethdMatcher返回true,三个参数匹配方法将被在每次方法执行中被调用。这允许一个切点看起来对于一个参数的传递对于方法直接在目标advice被执行之前。

 

Most MethodMatchers are static, meaning that their isRuntime() method returns false. In this case, the 3-argument matches method will never be invoked.

大部分MethodMatchers是静态的,意味着他们的isRuntime方法返回false。在这个例子中,三个参数的匹配方法将不会被调用。

 

[Tip]

提示

 

If possible, try to make pointcuts static, allowing the AOP framework to cache the results of pointcut evaluation when an AOP proxy is created.

如果可以,尝试使得切点是静态的,允许AOP框架来缓存切点执行的值当AOP代理被创建的时候。

 

40.1.2 Operations on pointcuts

对于切点的操作

 

Spring supports operations on pointcuts: notably, union and intersection.

spring支持操作对于切点是:notablyunionintersection

 

    Union means the methods that either pointcut matches.

Union意味着方法和切点的匹配

    Intersection means the methods that both pointcuts match.

Intersection意味着方法和多个切点的匹配

    Union is usually more useful.

Union通常是更加有用的。

    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.

切点可以被组合使用静态方法在org.springframework.aop.support.Pointcuts类或使用ComposablePointcut类在相同的包中。然而使用AspectJ切点表达式通常是一个更加简单的方式。

 

40.1.3 AspectJ expression pointcuts

AspectJ表达式的切点

 

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.

自从2.0,大部分重要的切点类型由spring使用是org.springframework.aop.aspectj.AspectJExpressionPointcut。这是一个切点使用AspectJ支持库来解析AspectJ切点表达式字符串。

 

See the previous chapter for a discussion of supported AspectJ pointcut primitives.

见之前的章节对于支持AspectJ切点的内容。

 

40.1.4 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.

spring提供了一些方便的切点实现。一些可以使用在外部,另一些可以是指定应用切点的子类。

 

Static pointcuts

静态切点

 

Static pointcuts are based on method and target class, and cannot take into account the methods arguments. Static pointcuts are sufficient - and best - for most usages. Its 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.

静态切点基于方法和目标类并且不能直接访问方法的参数。静态切点是足够的并且是最好的对于大部分使用的情况。对于spring来说可以解析一个静态切点一次,当方法被首次调用的时候,并且不需要在方法执行时再次调用切点。

 

Lets consider some static pointcut implementations included with Spring.

让我们考虑一些静态的切点实现在spring中。

 

Regular expression pointcuts

正则表达式切点

 

One obvious way to specify static pointcuts is regular expressions. Several AOP frameworks besides Spring make this possible. org.springframework.aop.support.Perl5RegexpMethodPointcut is a generic regular expression pointcut, using Perl 5 regular expression syntax. The Perl5RegexpMethodPointcut class depends on Jakarta ORO for regular expression matching. Spring also provides the JdkRegexpMethodPointcut class that uses the regular expression support in JDK 1.4+.

一个明显的方法来指定静态切点就是正则表达式。一些AOP框架基于spring使得这一项成为可能。org.springframework.aop.support.Perl5RegexpMethodPointcut是一个通常的正则表达式切点。使用Perl5的正则表达式语法。Perl5RegexpMethodPointcut类依赖于JakartaORO用于正则表达式匹配。spring也提供了JdkRegexpMethodPointcut类使用正则表达式支持在JDK1.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.)

使用Perl5RegexpMethodPointcut类,你可以提供一个匹配字符串列表。如果对于任何的匹配,切点将被设置为true。(因此有效的结果是这些切点的统一。)

 

The usage is shown below:

使用方法展示如下:

 

<bean id="settersAndAbsquatulatePointcut"

        class="org.springframework.aop.support.Perl5RegexpMethodPointcut">

    <property name="patterns">

        <list>

            <value>.set.</value>

            <value>.*absquatulate</value>

        </list>

    </property>

</bean>

 

Spring provides a convenience class, RegexpMethodPointcutAdvisor, that allows us to also reference an Advice (remember that an Advice can be an interceptor, before advice, throws advice etc.). Behind the scenes, Spring will use a JdkRegexpMethodPointcut. Using RegexpMethodPointcutAdvisor simplifies wiring, as the one bean encapsulates both pointcut and advice, as shown below:

spring提供了一个方便的类,RegexpMethodPointcutAdvisor,允许我们使用引用Advice(记住一个Advice可以是一个拦截器,前置通知,异常通知等等)。在这些场景下,spring将使用JdkRegexpMethodPointcut。使用RegexpMethodPointcutAdvisor简化处理。作为一个bean处理切点和advice,展示如下:

 

<bean id="settersAndAbsquatulateAdvisor"

        class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

    <property name="advice">

        <ref bean="beanNameOfAopAllianceInterceptor"/>

    </property>

    <property name="patterns">

        <list>

            <value>.set.</value>

            <value>.*absquatulate</value>

        </list>

    </property>

</bean>

 

RegexpMethodPointcutAdvisor can be used with any Advice type.

RegexpMethodPointcutAdvisor可以被使用于任意的Advice类型。

 

Attribute-driven pointcuts

属性驱动切点

 

An important type of static pointcut is a metadata-driven pointcut. This uses the values of metadata attributes: typically, source-level metadata.

一个重要的静态切点类型是元数据驱动切点。他使用了元数据属性的值:通常是源码级别的元数据。

 

Dynamic pointcuts

动态切点

 

Dynamic pointcuts are costlier to evaluate than static pointcuts. They take into account methodarguments, as well as static information. This means that they must be evaluated with every method invocation; the result cannot be cached, as arguments will vary.

动态切点被复杂的解析将对于静态的切点。他们需要考虑方法参数。包括静态信息。这意味着他们必须要在每次方法调用时被执行;结果不能被缓存由于参数是可变的。

 

The main example is the control flow pointcut.

主要的例子是控制流切点。

 

Control flow pointcuts

控制流切点

 

Spring control flow pointcuts are conceptually similar to AspectJ cflow pointcuts, although less powerful. (There is currently no way to specify that a pointcut executes below a join point matched by another pointcut.) A control flow pointcut matches the current call stack. For example, it might fire if the join point was invoked by a method in the com.mycompany.web package, or by the SomeCaller class. Control flow pointcuts are specified using the org.springframework.aop.support.ControlFlowPointcut class.

spring控制流切点在概念上是相似于AspectJcflow且蒂娜,虽然功能没有那么强大。(不会指定切点执行在一个join point匹配另一个切点之前。)一个控制流切点匹配当前的调用栈。例如,他们可以使用于如果join点被调用通过一个方法在com.myconmpay包中或通过SomeCaller类。控制流切点被指定使用org.springframework.aop.support.ControlFlowPointcut类。

 

[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.

控制流切点是重要的对于执行在运行时比相对于动态切点。在Java1.4中,消费大概是其他动态切点的5倍。

 

40.1.5 Pointcut superclasses

切点超类

 

Spring provides useful pointcut superclasses to help you to implement your own pointcuts.

spring提供了有用的切点超类来帮助我们实现你自己的切点。

 

Because static pointcuts are most useful, youll probably subclass StaticMethodMatcherPointcut, as shown below. This requires implementing just one abstract method (although its possible to override other methods to customize behavior):

因为静态切点是最有用的,你可以继承StaticMethodMatcherPointcut,就如下面展示的。这要求实现一个抽象方法(尽管可以覆盖其他的方法来自定义行为):

 

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.

你可以使用自定义的切点通知类型在spring1.0RC2或更高级的版本中。

 

40.1.6 Custom pointcuts

自定义切点

 

Because pointcuts in Spring AOP are Java classes, rather than language features (as in AspectJ) its 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.

因为切点在springAOP中是Java类,而不是语言特性(比如在AspectJ中)他可以定义自定义切点,不管是静态还是动态。spring中的自定义切点可以是非常复杂的。然而,使用AspectJ的切点表达式语言是建议的如果可以的话。

 

[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."

spring最新的版本提供了支持对于“语义切点”通过JAC:例如,“所有的方法对于目标object可以改变实例变量”

 

40.2 Advice API in Spring

spring中的AdviceAPI

 

Lets now look at how Spring AOP handles advice.

让我们看一下如何在springAOP中处理advice

 

40.2.1 Advice lifecycles

Advice的生命周期

 

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.

每个advice是一个springbean。一个advice实例可以共享对于所有的advciedobject,或对于每个object唯一。这依赖于每个类或每个实例的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.

每个类的advice使用更加频繁。他适用于通用的advice例如事务advisor。这不依赖于代理object的状态或添加新的状态;他扮演了方法和参数的角色。

 

Per-instance advice is appropriate for introductions, to support mixins. In this case, the advice adds state to the proxied object.

每个实例advice是适用于介绍的,为了支持最小化。在这个例子中,advice添加了状态对于代理object

 

Its possible to use a mix of shared and per-instance advice in the same AOP proxy.

可以使用共享和每个实例混合advice在相同的AOP代理中。

 

40.2.2 Advice types in Spring

springAdvice类型

 

Spring provides several advice types out of the box, and is extensible to support arbitrary advice types. Let us look at the basic concepts and standard advice types.

spring提供了一些advice类型,并且扩展他们来支持任意的advice类型。让我们看一下基本的内容和标准的advice类型。

 

Interception around advice

拦截环绕advice

 

The most fundamental advice type in Spring is interception around advice.

spring中最基本的advice类型就是拦截环绕advice

 

Spring is compliant with the AOP Alliance interface for around advice using method interception. MethodInterceptors implementing around advice should implement the following interface:

spring使用AOPAlliance接口对于环绕advice使用方法拦截。MethodInterceptors实现了环绕advice应当实现下面的接口。

 

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 invocations result: the return value of the join point.

对于invoke方法的MethodInvocation参数暴露了被调用的方法;目标连接点;AOP代理,和对于参数的方法。invoke方法应当返回调用的结果:连接点的返回类型。

 

A simple MethodInterceptor implementation looks as follows:

一个简单的MethodInterceptor实现展示如下:

 

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 MethodInvocations 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 dont want to do this without good reason!

注意对于MethodInvocation的调用方法。这个处理拦截了拦截器链子对于连接点。大部分拦截器应当调用方法并且返回返回值。然而,MethodInterceptor类似于环绕advice,可以返回一个默认值或抛出一个异常若不是调用处理的方法。有时这么做是对的。

 

[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.

MethodInterceptors提供你了使用其他AOP的连接或AOP实现的互相操作性。其他的advice类型在剩下的章节中将讨论实现了通用的了AOP内容,但是在spring指定的方式下。这是使用大部分指定advice类型的优点,相对于MethodInterceptor的环绕advice如果你希望运行aspect在其他的AOP框架中。注意切点在框架之间不是通用的,并且AOP不会定义切点接口。

 

Before advice

前置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.

一个简单的advice类型是前置advice。他不需要MethodInvocationobject,因为他只需要在方法之前调用。

 

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.

前置advice的主要优点是不需要调用proceed方法,并且不需要考虑调用链的失败。

 

The MethodBeforeAdvice interface is shown below. (Springs API design would allow for field before advice, although the usual objects apply to field interception and its unlikely that Spring will ever implement it).

MethodBeforeAdvice接口展示如下。(springAPI设计允许用于屏蔽前置advice,尽管通用的object应用来使用拦截并且spirng不是实现他。)

 

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.

注意返回类型是void。前置advice可以加入自定义的行为在连接点执行之前,但是不能改变返回值。如果一个前置advice抛出异常,这将放弃后续连接器链的执行。异常将返回给拦截器链。如果没有检查或对于调用的方法签名,他将传递给客户端;或者将被处理为一个非检查异常通过AOP的代理。

 

An example of a before advice in Spring, which counts all method invocations:

一个前置advice的例子在spring中,记录了所有方法的调用:

 

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.

前置advice而可以使用于任意的切点。

 

Throws advice

异常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:

异常advice在返回连接点时如果发生了异常则会被调用。spring提供了异常advice。注意这意味着org.springframework.aop.ThrowsAdvice接口不包含任何方法:他是一个标签接口定义了给定的object实现一个或多个类型的异常advice方法。格式看起来是这样的:

 

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.

只有最后一个参数是必须的。方法签名可以是一个或四个参数。依赖于adivce方法是关注于方法还是参数。下面的类是异常advice的例子。

 

The advice below is invoked if a RemoteException is thrown (including subclasses):

下面的advice被调用如果抛出的异常是RemoteException(包括子类):

 

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:

下面的advice被调用如果ServletException被抛出的。不像上面的advice,他定义了四个参数。因此他访问了调用方法、方法参数和目标object

 

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.

最后一个例子展示了这两个方法可以被使用在单一的类中,处理RemoteExceptionServletException。任意数量的异常advice方法可以组合在单一的类中。

 

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 methods signature!

注意:如果一个异常advice方法抛出了一个异常,他将覆盖原有的异常(例如,改变异常抛出给用户)。覆盖异常将通常是RuntimeException;这是对于每个方法签名的一致性。然而,一个异常advice方法抛出一个检查异常,他将需要匹配目标方法的定义异常并且因此在一些程度上指定了目标方法签名。不会抛出非检查异常不适合于目标方法的签名!

 

[Tip]

提示

 

Throws advice can be used with any pointcut.

异常advice可以使用任意的切点。

 

After Returning advice

最终advice

 

An after returning advice in Spring must implement the org.springframework.aop.AfterReturningAdvice interface, shown below:

一个最终advicespring中必须实现org.springframework.aop.AfterReturningAdvice接口,展示如下:

 

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.

一个最终advice方法返回值(不能被修改),调用方法,方法参数和目标。

 

The following after returning advice counts all successful method invocations that have not thrown exceptions:

下面的最终advice计算所有的成功方法调用并且是没有抛出异常的。

 

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 doesnt change the execution path. If it throws an exception, this will be thrown up the interceptor chain instead of the return value.

这个advice不能改变执行的路径。如果他抛出异常,这将会返回给拦截链而不是返回给返回值。

 

[Tip]

提示

 

After returning advice can be used with any pointcut.

最终advice可以被使用于任意的切点。

 

Introduction advice

 

Spring treats introduction advice as a special kind of interception advice.

spring对待introductionadvice作为一个指定类型的拦截advice

 

Introduction requires an IntroductionAdvisor, and an IntroductionInterceptor, implementing the following interface:

introduction要求一个IntroductionAdvisorIntroductionInterceptor,实现了下面的接口:

 

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().

invoker方法来自AOPMethodInterceptor接口必须实现introduction:就是如果调用方法对于intorduced接口,introduction拦截器是代表处理额方法调用————他不能调用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:

introductionadvice不能适用于任何的切点,因为他只能应用于类而不是方法级别。你可以使用introductionadvice使用IntroductionAdvisor,有以下的方法:

 

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.

没有MethodMatcher对于introductionadvice。只有类过来是逻辑的。

 

The getInterfaces() method returns the interfaces introduced by this advisor.

getInterfaces方法返回接口有这个advisorintroduce

 

The validateInterfaces() method is used internally to see whether or not the introduced interfaces can be implemented by the configured IntroductionInterceptor.

validateInterfaces方法使用内部来实现或不introduce可以实现通过配置的IntroductionInterceptor

 

Lets look at a simple example from the Spring test suite. Lets suppose we want to introduce the following interface to one or more objects:

让我们看一个简单的例子来自spring的测试包。让我们假设我们希望introduce下面的接口对于一个或多个object

 

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.

这展示了一个混合。我们希望可以转换adviseobjectLockable,的类型,和调用lockunlock方法。如果我们调用了lock方法,我们希望所有的setter方法抛出一个LockerException异常。我们可以添加一个aspect来提供使得object是不可以变的而不俗要任何有关的只是:一个AOP的好的例子。

 

Firstly, well 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.

首先,我们需要一个IntroductionInterceptor有很强大的功能。在这个例子中,我们扩展了org.springframework.aop.support.DelegatingIntroductionInterceptor的方便的类。我们可以直接实现IntroductionInterceptor,使用DelegatingIntroductionInterceptor是最好的选择对于大多数的情况。

 

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. Its 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.

DelegatingIntroductionInterceptor被设计用于introduction对于实际的实现对于introduced的接口,隐藏使用拦截器来这么做。委托可以被设置对于任何使用构造器参数的object;默认的委托(当使用无参数的构造器)。下面的例子中,委托市LockMixinDelegatingIntroductionInterceptor的子类。给定了一个委托(通过默认本身),一个DelegatingIntroductionInterceptor实例查找所有的接口实现通过委托(而不是IntroductionInterceptor),并且将支持introduction对于每一个。他可以适用于子类列LockMixin来调用suppressInterface(Class intf)方法对于抑制接口不应当被暴露。然而多少个接口对于IntroductionInterceptor可以被支持,IntroductionAdvisor将控制接口的实际暴露。一个introduced接口将隐藏相同接口对于目标的实现。

 

Thus LockMixin subclasses DelegatingIntroductionInterceptor and implements Lockable itself. The superclass automatically picks up that Lockable can be supported for introduction, so we dont need to specify that. We could introduce any number of interfaces in this way.

LockMixin子类的DelegatingIntroductionInterceptor和实现Lockable本身。超类自动使用Lockable可以被支持用于introduction,因此我们不需要指定他。我们可以introduce任何数量的接口以这种方式。

 

Note the use of the locked instance variable. This effectively adds additional state to that held in the target object.

注意locked实例变量的使用。他有效的添加的额外的状态来使用对于目标object

 

public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {

 

    private boolean locked;

 

    public void lock() {

        this.locked = true;

    }

 

    public void unlock() {

        this.locked = false;

    }

 

    public boolean locked() {

        return this.locked;

    }

 

    public Object invoke(MethodInvocation invocation) throws Throwable {

        if (locked() && invocation.getMethod().getName().indexOf("set") == 0) {

            throw new LockedException();

        }

        return super.invoke(invocation);

    }

 

}

 

Often it isnt 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.

通常他不能覆盖invoke方法DelegatingIntroductionInterceptor的实现————调用了委托方法如果方法是introduced,此外对于连接点的执行————是足够的。在之前的例子中,我们需要添加检查:没有sertter方法可以被调用在locked的模式下。

 

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, theres no configuration relevant for a LockMixin, so we simply create it using new.

introductionadvisor要求是简单的。所有他需要做的的需要一个明显的LockMixin实例和指定intorduced接口————在这个情况下,就像Lockable。一个复杂的例子可以使用引用对于introductiong拦截器(可以定义一个原型):在这个例子中,这不需要配置相关的用于LockMixin,因此我们简单的创建他使用一个新的就可以。

 

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: Its 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 objects state.

我们可以十分简单的应用这个advisor:他不需要配置。(然而,他是必要的:对于使用IntroductionInterceptor而不需要IntroductionAdvisor。)一个通常的intorductionadvisor必须是对应于每个实例的,因此他是有状态的。我们需要一个不同的LockMixinAdvisor实例并且因此LockMinxin对于每个advisedobject。这个advisor部分是advisedobject的状态。

 

We can apply this advisor programmatically, using the Advised.addAdvisor() method, or (the recommended way) in XML configuration, like any other advisor. All proxy creation choices discussed below, including "auto proxy creators," correctly handle introductions and stateful mixins.

我们可以编程应用这个advisor,使用Advised.addAdvisor()方法,或(建议的方式)在xml配置中,类似于其他的advisor。所有的代理创建选择讨论如下,包括“自动代理创建”,正确处理introduction和有状态的mixins

 

40.3 Advisor API in Spring

spring中的AdvisorAPI

 

In Spring, an Advisor is an aspect that contains just a single advice object associated with a pointcut expression.

spring中,一个Advisor是一个aspect包括一个adviceobject连接切点表达式。

 

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.

对于指定的例子对于introductions,任何advisor可以被使用对于每个adviceorg.springframework.aop.support.DefaultPointcutAdvisor是大部分通用的advisor类。例如,它可以使用在MethodInterceptorBeforeAdviceThrowsAdvice

 

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.

他可以混合advisoradvice类型在spring中在相同的AOP代理中。例如,你可以使用拦截器环绕advice、异常advice和前置advice在一个代理配置中:spring将自动创建需要的拦截器链。

 

40.4 Using the ProxyFactoryBean to create AOP proxies

使用ProxyFactoryBean来创建AOP代理

 

If youre using the Spring IoC container (an ApplicationContext or BeanFactory) for your business objects - and you should be! - you will want to use one of Springs AOP FactoryBeans. (Remember that a factory bean introduces a layer of indirection, enabling it to create objects of a different type.)

如果你使用springIOC容器(一个ApplicationContextBeanFactory)用于你的业务object————并且你应当————你将需要使用springAOPFactoryBeans的其中之一。(记住工厂bean引入了indirection层,允许创建不同类型的object。)

 

[Note]

注意

 

The Spring 2.0 AOP support also uses factory beans under the covers.

spring2.0AOP支持也适用工厂bena

 

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 dont need such control.

基本的方式来创建一个AOP代理在spring中是使用org.springframework.aop.framework.ProxyFactoryBean。这使用了复杂的控制对于切点和advice的应用,并且他们是有序的。然而你他们是简单的徐昂想适用于你不需要这样的控制。

 

40.4.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 ProxyFactoryBeans implementation of the `getObject() method. This method will create an AOP proxy wrapping a target object.

ProxyFactoryBean类似于其他的springFacotryBean实现,引入了indirection层。如果你定义了一个ProxyFactoryBean使用了一个名字为fooobject引用foo将不是ProxyFactoryBean实例本身,而是创建的object通过ProxyFactoryBean的实现对于getObject方法。这个方法将创建一个AOP代理包裹一个目标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.

对于大部分重要的优点中其中一个使用ProxyFactoryBean或另一个IOC-aware类来创建AOP代理就是意味着advices和切点可以匹配IOC。这是一个重要的特性,允许获取访问对于获得其他的AOP框架。例如,一个advice本身可以医用应用的object(对于目标,应当是可用的对于AOP框架)。对于依赖注入是很有益处的。

 

40.4.2 JavaBean properties

JavaBean属性

 

In common with most FactoryBean implementations provided with Spring, the ProxyFactoryBean class is itself a JavaBean. Its properties are used to:

对于spring中大部分FactoryBean的实现,ProxyFactoryBean类本身是一个JavaBean。他的属性是:

 

    Specify the target you want to proxy.

指定你希望代理的目标

    Specify whether to use CGLIB (see below and also Section 12.5.3, JDK- and CGLIB-based proxies).

指定是否使用CGLIB(见如下和章节12.5.3,“JDK和基于CGLIB代理”)

 

Some key properties are inherited from org.springframework.aop.framework.ProxyConfig (the superclass for all AOP proxy factories in Spring). These key properties include:

一些关键属性是继承org.springframework.aop.framework.ProxyConfig(超类用于所有的AOP代理工厂在spring中。)这些关键属性包括:

 

    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 Section 12.5.3, JDK- and CGLIB-based proxies).

proxyTargetClasstrue如果目标类是被代理的,而不是目标类的接口。如果这个属性被设置为true,则CGLIB代理将被创建(但是见下面的章节12.5.3,“JDK和基于CGLIB的代理”)。

    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.

optimize:控制是否是强制优化应用于代理创建通过CGLIB。应当使用这种设置除非完全理解了相应的AOP代理的处理优化。这是当前只被CGLIB代理使用,不会影响JDK的动态代理。

    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 dont 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.

frozen:如果一个代替配置是frozen,则改变配置为不在允许。这是有用的并且作为一个轻量的优化用于这些案例当你不希望调用者来控制代理(通过Advised接口在代理被创建之后。这个属性的默认值是false,因此这样的改变作为添加额外的advice是被允许的。)

    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.

exposeProxy:决定是否当前代理应当被暴露在一个ThreadLocal中因此他可以被目标访问。如果一个目标需要获取代理则exposeProxy属性被设置为true,目标可以使用AopContext.currentProxy方法。

    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.

aopProxyFactoryAopProxyFactory的实现来使用。提供一个自定义的方式对于使用动态代理,CGLIB或其他代理测试。默认的实现将选择动态代理或CGLIB根据需要。他应当不需要使用代理,他允许额外的新的代理类型在spring1.1中。

 

Other properties specific to ProxyFactoryBean include:

其他的属性对于ProxyFactoryBean包括:

 

    proxyInterfaces: array of String interface names. If this isnt supplied, a CGLIB proxy for the target class will be used (but see also below Section 12.5.3, JDK- and CGLIB-based proxies).

proxyInterfaces:字符串接口名的数组。如果他没有被提供,CGLIB代理对于目标类将被使用(见章节12.5.3,“JDK和基于CGLIB的代理”)。

    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.

interceptorNamesAdvisor的字符串数组,拦截器或应用其他的advice名字。顺序是重要的,对于第一个服务基础。他是第一个拦截器在列表中将首先拦截调用。

 

The names are bean names in the current factory, including bean names from ancestor factories. You cant mention bean references here since doing so would result in the ProxyFactoryBean ignoring the singleton setting of the advice.

名字是bean的名字在当前的factory中,包括bean的名字来自于祖先factory。你不能在这里使用bean的应用因为这将导致在ProxyFactoryBean中忽略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 Section 12.5.6, Using 'global' advisors.

你可以添加一个拦截器名字使用asterisk ( *)。这将导致在所有advisorbean的应用中对于民资开始的部分在asterisk被应用之前。使用这个特性的例子可以在章节12.5.6中找到,“使用全局的advisors”。

 

    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.

singleton:对于factory应当返回一个单个object,不管getObject方法被调用。一些FactoryBean实现提供这样的一个方法。默认值是true。如果你希望使用有状态的advice————例如,对于有状态的mixins————使用prototypeadvice使用单例的值是false

 

40.4.3 JDK- and CGLIB-based proxies

JDK和基于CGLIB的代理

 

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).

这个章节服务于意向文档关于如何ProxyFactoryBean选择创建其中一个JDK或基于CGLIB的代理用于特定的目标object(可以被代理)。

 

[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.

ProxyFactoryBean的行为用于创建JDK或基于CGLIB的代理时在spring1.2.x版本和2.0版本之间改变的。ProxyFactoryBean现在使用了相似的语义来处理自动探测的接口作为TransactionProxyFactoryBean的类。

 

If the class of a target object that is to be proxied (hereafter simply referred to as the target class) doesnt 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 isnt 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.)

如果目标object的类被代理(简单的引用目标类)没有实现任何接口,则一个基于CGLIB的代理将被使用。这是最简单的场景,因为JDK代理时基于接口的并且这样的接口意味着JDK代理不可用。一个简单的插件对于目标bean和指定拦截器列表通过interceptorNames属性。注意基于CGLIB的代理将被创建如果ProxyFactoryBeanproxyTargetClass属性被设置为false的话。(很明显这是没有意义的并且最好移除bean的定义因为这是多余的并且是欠考虑的。)

 

If the target class implements one (or more) interfaces, then the type of proxy that is created depends on the configuration of the ProxyFactoryBean.

如果目标类实现了一个(或多个)接口,代理的类型创建将依赖于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.

如果ProxyFactoryBeanproxyTargetClass属性被设置为true,则基于CGLIB的代理将被创建。这是有意义的并且为了保证至少一个的原则。即使ProxyFactoryBeanproxyInterfaces属性已经被设置为一个或多个全限定名的接口名,proxyTargetClass属性被设置为true的事实讲导致基于CGLIB的代理受到影响。

 

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.

如果ProxyFactoryBeanproxyInterfaces属性已经被设置为一个或多个全限定的接口名,则给予JDK的代理将被创建。创建的代理将实现所有的接口指定在proxyInterfaces属性中;如果目标类已经实现了接口指定在proxyInterfaces属性中,这是很好的但是额外的接口将不会被返回的代理实现。

 

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.

如果ProxyFactoryBeanproxyInterfaces属性没有被设置,但是目标类实现了一个(或多个)接口,ProxyFactoryBean将自动探测目标类的实际并且实际实现至少一个接口,并且一个基于JDK的代理将被创建。接口实际的代理将至少是所有的接口实现在目标类上;实际上,他和简单应用一个列表和每个接口的目标类实现对于proxyInterfaces属性。然而,这是有意义的并且有打字错误的倾向。

 

40.4.4 Proxying interfaces

代理接口

 

Lets look at a simple example of ProxyFactoryBean in action. This example involves:

让我们看一个简单的例子对于ProxyFactoryBean。这个例子调用了:

 

    A target bean that will be proxied. This is the "personTarget" bean definition in the example below.

一个目标的bean将被代理。这是"personTarget"bean定义在下面的例子中。

    An Advisor and an Interceptor used to provide advice.

一个Advisor和一个拦截器使用来提供advice

    An AOP proxy bean definition specifying the target object (the personTarget bean) and the interfaces to proxy, along with the advices to apply.

一个AOP代理的bean定义指定了目标objectpersonTargetbean)和被代理的接口,应用advice

 

<bean id="personTarget" class="com.mycompany.PersonImpl">

    <property name="name"><value>Tony</value></property>

    <property name="age"><value>51</value></property>

</bean>

 

<bean id="myAdvisor" class="com.mycompany.MyAdvisor">

    <property name="someProperty"><value>Custom string property value</value></property>

</bean>

 

<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor">

</bean>

 

<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="proxyInterfaces"><value>com.mycompany.Person</value></property>

    <property name="target"><ref bean="personTarget"/></property>

    <property name="interceptorNames">

        <list>

            <value>myAdvisor</value>

            <value>debugInterceptor</value>

        </list>

    </property>

</bean>

 

Note that the interceptorNames property takes a list of String: the bean names of the interceptor or advisors in the current factory. Advisors, interceptors, before, after returning and throws advice objects can be used. The ordering of advisors is significant.

注意interceptorNames属性接收一个字符串列表:拦截器的bean的名字或advisor在当前的fatory中。Advisor、拦截器、前置、最终和异常adviceobject可以被使用。advisors的顺序是重要的。

 

[Note]

注意

 

You might be wondering why the list doesnt hold bean references. The reason for this is that if the ProxyFactoryBeans 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 its necessary to be able to obtain an instance of the prototype from the factory; holding a reference isnt sufficient.

你想知道为什么列表没有持有bean的引用。这个原因是如果ProxyFactoryBeans的单例属性被设置为false,他必须可以返回独立的代理实例。如果任意的advisor是其本身是一个原型,一个独立的实例将需要被返回,因此他需要可以获取一个原型的实例来自factory:持有引用不是必须的。

 

The "person" bean definition above can be used in place of a Person implementation, as follows:

上面的personbean定义可以被使用在一个Person的实现中,如下:

 

Person person = (Person) factory.getBean("person");

 

Other beans in the same IoC context can express a strongly typed dependency on it, as with an ordinary Java object:

其他的bean在相同IOC上下文中可以被展示为一个强类型的依赖,对于一个有顺序的Javaobject

 

<bean id="personUser" class="com.mycompany.PersonUser">

    <property name="person"><ref bean="person" /></property>

</bean>

 

The PersonUser class in this example would expose a property of type Person. As far as its 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).

PersonUser类在例子中可以暴露一个Person类型的属性。因此他是被考虑的,AOP代理可以被明确使用在实际的person实现中。然而,他的类将是一个动态代理类。他可以转化为Advised接口(讨论如下)。

 

Its possible to conceal the distinction between target and proxy using an anonymous inner bean, as follows. Only the ProxyFactoryBean definition is different; the advice is included only for completeness:

可以隐藏目标和带来之间使用一个匿名内部bean的区别,如下。就是ProxyFactoryBean的定义是不同的,advice是包括完整的。

 

<bean id="myAdvisor" class="com.mycompany.MyAdvisor">

    <property name="someProperty"><value>Custom string property value</value></property>

</bean>

 

<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>

 

<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="proxyInterfaces"><value>com.mycompany.Person</value></property>

    <!-- Use inner bean, not local reference to target -->

    <property name="target">

        <bean class="com.mycompany.PersonImpl">

            <property name="name"><value>Tony</value></property>

            <property name="age"><value>51</value></property>

        </bean>

    </property>

    <property name="interceptorNames">

        <list>

            <value>myAdvisor</value>

            <value>debugInterceptor</value>

        </list>

    </property>

</bean>

 

This has the advantage that theres 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. Theres 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.

这是有有点的只是一个Person类型的object:是有用的如果我们希望阻止应用上下文的使用来获取一个引用对于非advisedobject或需要避免模糊的使用springIOC注入。这也是有争议的在ProxyFactoryBean定义中是自包含的。然而,这是优势可以获取一个非advised的目标来自factory可以实际是一个优点:例如,在一个确定的测试场景中。

 

40.4.5 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 didnt 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 its best to program to interfaces, rather than classes, the ability to advise classes that dont implement interfaces can be useful when working with legacy code. (In general, Spring isnt prescriptive. While it makes it easy to apply good practices, it avoids forcing a particular approach.)

想象在我们上面的例子中,没有Person实例;我们需要advise一个类名字为Person不需要实现任何接口。在这个情况下,你可以配置spring来使用CGLIB代理,而不是动态代理。简单的设置ProxyFactoryBean中的proxyTargetClass属性为true。最好是变成接口而不是类,advise类的能力不是实现接口是有意义的对于老旧的程序。(通常,spring不是规定话的,他标志简单的应用好的策略,避免强制一个特定的方式。)

 

If you want to, you can force the use of CGLIB in any case, even if you do have interfaces.

如果你想要做,你可以强制使用CGLIB在任何情况,如果你希望使用接口。

 

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代理使用生成一个目标类的子类在运行时。spring配置这个生成的子类对于委派的方法调用对于原有的object:子类被使用来实现装饰者模式,使用advice

 

CGLIB proxying should generally be transparent to users. However, there are some issues to consider:

CGLIB代理应当通常是透明的对于用户。然而需要有一些问题需要考虑:

 

    Final methods cant be advised, as they cant be overridden.

最终方法不能被advise,由于他不能被覆盖。

    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.

由于spring3.2不在要求添加CGLBI到你的项目的classpath中。CGLIB类重新打包在org.springframework中并且直接包含的spring-coreJAR中。这是对用户的方便避免额外的配置冲突对于其他的项目依赖于一个不同版本的CGLIB

 

Theres 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.

这是不同点对于CGLIB代理和动态代理。由于spring1.0,动态代理是轻量级的。然而,他可能在未来发生改变。性能应当不是一个决定性因素在这个案例中。

 

40.4.6 Using 'global' advisors

使用全局的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:

通过添加一个星号到一个拦截器的名字,所有的advisor使用bean的名字匹配部分在星号之前,将被添加advisor链。这是有用的如果你需要添加一个标准的集合对于全局的advisors

 

<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="target" ref="service"/>

    <property name="interceptorNames">

        <list>

            <value>global*</value>

        </list>

    </property>

</bean>

 

<bean id="global_debug" class="org.springframework.aop.interceptor.DebugInterceptor"/>

<bean id="global_performance" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>

 

40.5 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.

尤其定义事务代理,你可以使用许多相似的代理定义。parentchildbean的定义的使用,允许内部的bean的定义,可以导致更加简明的代理定义。

 

First a parent, template, bean definition is created for the proxy:

首先一个parent、模板、bean的定义被创建用于代理:

 

<bean id="txProxyTemplate" abstract="true"

        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

    <property name="transactionManager" ref="transactionManager"/>

    <property name="transactionAttributes">

        <props>

            <prop key="*">PROPAGATION_REQUIRED</prop>

        </props>

    </property>

</bean>

 

This will never be instantiated itself, so may actually be incomplete. Then each proxy which needs to be created is just a child bean definition, which wraps the target of the proxy as an inner bean definition, since the target will never be used on its own anyway.

浙江不会被实例化,因此许多是不完整的。则每个代理需要被创建是一个childbean定义,处理代理的目标作为内部的bean的定义,因此目标将不会被使用它本身的方式。

 

<bean id="myService" parent="txProxyTemplate">

    <property name="target">

        <bean class="org.springframework.samples.MyServiceImpl">

        </bean>

    </property>

</bean>

 

It is of course possible to override properties from the parent template, such as in this case, the transaction propagation settings:

可以覆盖来自父模板的属性,例如在这个例子中,事务的传播设置:

 

<bean id="mySpecialService" parent="txProxyTemplate">

    <property name="target">

        <bean class="org.springframework.samples.MySpecialServiceImpl">

        </bean>

    </property>

    <property name="transactionAttributes">

        <props>

            <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>

            <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>

            <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>

            <prop key="store*">PROPAGATION_REQUIRED</prop>

        </props>

    </property>

</bean>

 

Note that in the example above, we have explicitly marked the parent bean definition as abstract by using the abstract attribute, as described previously, so that it may not actually ever be instantiated. Application contexts (but not simple bean factories) will by default pre-instantiate all singletons. It is therefore important (at least for singleton beans) that if you have a (parent) bean definition which you intend to use only as a template, and this definition specifies a class, you must make sure to set theabstract attribute to true, otherwise the application context will actually try to pre-instantiate it.

注意在上面的例子中,我们明确标记的parentbean的定义作为一个抽象使用抽象的属性,描述在前面,因此他是可以被实例化的。应用上下文(单不是简单的bean的工厂)将是默认的提前实例化所有的代理。这是重要的(至少对于单例的bean)如果你有一个(parent)的bean定义你洗完使用作为一个模板,这个定义指定了一个类,你必须设置theabstract属性为true,因此应用上下文将实例试图提前实例化。

 

40.6 Creating AOP proxies programmatically with the ProxyFactory

编程创建AOP的代理使用ProxyFactory

 

Its easy to create AOP proxies programmatically using Spring. This enables you to use Spring AOP without dependency on Spring IoC.

编程创建AOP的代理时简单的对于spring的使用。这允许你使用springAOP而不需要依赖springIOC

 

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:

下面的列表展示了目标object的代理的创建,对于一个拦截器和一个行为。接口实现通过目标object将自动被代理:

 

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.

第一步构建一个object且类型是org.springframework.aop.framework.ProxyFactory。你可以创建一个目标object,因此在上面的例子中,或指定代理的接口在另一个构造器中。

 

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.

你可以添加拦截器或advisors,和管理他们对于ProxyFactorylife。如果你添加一个IntroductionInterceptionAroundAdvisor你可以使得代理实现额外的接口。

 

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.

这是方便的方法对于ProxyFactory(继承自AdvisedSupport)允许你添加额外的advice类型例如前置和异常adviceAdvisedSupportProxyFactoryProxyFactoryBean的超类。

 

[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.

拦截AOP代理创建使用IOC框架是最好的选择在大部分应用中。我们建议你扩展配置对于使用AOPjava代码在通常情况下。

 

40.7 Manipulating advised objects

操作advisedobject

 

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:

然而你创建AOP代理,你可以操作他们使用org.springframework.aop.framework.Advised接口。任何的AOP代理可以被转换为这个接口,及其他的接口实现。这个接口包括下面的方法:

 

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.

getAdvisors方法将返回一个Advisor用于每个advisor、拦截器或其他的advice类型可以被添加到工厂中。如果你添加了一个Advisor,返回的advisor在这个情况将会是你添加的object。如果你添加一个拦截器或其他advice类型,spring将可以包裹在advisor中使用一个起点并且一直返回true。如果你添加一个MethodInterceptoradvisor的返回将是一个DefaultPointcutAdvisor返回你的MethodInterceptor和一个切点匹配所有的类和方法。

 

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).

addAdvisor方法可以使用来添加Advisor。通常advisor持有切点和advice是通常的DefaultPointcutAdvisor,可以被使用于advice或切点(不能用于intoroductions)。

 

By default, its possible to add or remove advisors or interceptors even once a proxy has been created. The only restriction is that its 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.)

默认的,他可以添加或移除advisors或拦截器即使已经创建了代理。唯一禁止的是添加或移除intorductionadvisor,一个已有的来自工厂的代理将不会展示接口的改变。(你可以获取一个新的来自工厂的代理来避免这个问题。)

 

A simple example of casting an AOP proxy to the Advised interface and examining and manipulating its advice:

一个简单的例子有关转换AOP代理为Advised接口并且检查和处理他的advice

 

Advised advised = (Advised) myObject;

Advisor[] advisors = advised.getAdvisors();

int oldAdvisorCount = advisors.length;

System.out.println(oldAdvisorCount + " advisors");

 

// Add an advice like an interceptor without a pointcut

// Will match all proxied methods

// Can use for interceptors, before, after returning or throws advice

advised.addAdvice(new DebugInterceptor());

 

// Add selective advice using a pointcut

advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));

 

assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length);

 

[Note]

注意

 

Its questionable whether its 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.)

问题是advisable(不是双关语)修改advice对于一个业务object在生产中,尽管他是合法的使用。然而,他可以在开发中是很有用的:例如,在测试中。我有时发现对于添加测试代码在拦截器或其他advice中是十分有用的,获取内部的我需要测试的方法调用。(例如,advice可以获得内部的由方法创建的事务:例如运行一个SQL来检查数据库是否正确被更新了在标记事务为回滚之前。)

 

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.

依赖于你如何创建代理,你通常可以设置一个frozon标志位,由于AdvicsedisFrozen方法将返回true并且任何尝试修改advice不管是添加还是移除将导致一个AopConfigException异常。这个功能锁定了advisedobject的状态并且在一些情况下是很有用的,例如,来保证调用代码移除一个安全的拦截器。他可以使用在spring1.1中允许强制的优化如果运行时advice修改不是必须的话。

 

40.8 Using the "autoproxy" facility

使用自动代理的策略

 

So far weve considered explicit creation of AOP proxies using a ProxyFactoryBean or similar factory bean.

因此我们考虑AOP代理的创建使用ProxyFactoryBean或相似的工厂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.

spring允许我们使用自动代理的bean定义,可以自动选择代理的bean定义。这是由spring的“bean的后处理器”来实现的,允许修改任意的bean的定义作为容器的加载。

 

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 dont need to use ProxyFactoryBean.

在这个模型下,你设置一些指定的bean定义在你的xmlbean定义文件中来配置自动代理的结构。这允许你来定义目标的能力用于自动代理:你不需要使用ProxyFactoryBean

 

There are two ways to do this:

这里有两种实现的方式:

 

    Using an autoproxy creator that refers to specific beans in the current context.

使用一个自动代理创建引用指定的bean在当前的上下文中。

    A special case of autoproxy creation that deserves to be considered separately; autoproxy creation driven by source-level metadata attributes.

一个特定的自动代理的案例是值得被分开考虑的:自动代理创建基于源码级别的元数据属性。

 

40.8.1 Autoproxy bean definitions

自动代理bean的定义

 

The org.springframework.aop.framework.autoproxy package provides the following standard autoproxy creators.

org.springframework.aop.framework.autoproxy包中下面的标准的自动代理创建。

 

BeanNameAutoProxyCreator

 

The BeanNameAutoProxyCreator class is a BeanPostProcessor that automatically creates AOP proxies for beans with names matching literal values or wildcards.

BeanNameAutoProxyCreator是一个BeanPostProcessor自动为bean创建AOP代理使用名字匹配或通配符。

 

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">

    <property name="beanNames"><value>jdk*,onlyJdk</value></property>

    <property name="interceptorNames">

        <list>

            <value>myInterceptor</value>

        </list>

    </property>

</bean>

 

As with ProxyFactoryBean, there is an interceptorNames property rather than a list of interceptors, to allow correct behavior for prototype advisors. Named "interceptors" can be advisors or any advice type.

由于ProxyFactoryBean,只是一个interceptorNames属性而不是一个拦截器列表,允许正确的行为用于原型的advisor。名字为interceptors可以是advisor或任意的advice类型。

 

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.

由于通常自动代理,使用BeanNameAutoProxyCreator的主要目的是应用相同的配置一致性来处理object,使用最小范围的配置。他是一种常见的方式对于应用声明式的事务来处理object

 

Bean definitions whose names match, such as "jdkMyBean" and "onlyJdk" in the above example, are plain old bean definitions with the target class. An AOP proxy will be created automatically by the BeanNameAutoProxyCreator. The same advice will be applied to all matching beans. Note that if advisors are used (rather than the interceptor in the above example), the pointcuts may apply differently to different beans.

bean定义使用名称匹配,例如"jdkMyBean"和“onlyJdk”在上面的例子中,普通的bean定义使用目标类。一个AOP代理将被自动创建通过BeanNameAutoProxyCreator。相同的advice将被应用对于所有匹配的bean。注意如果advisor被使用(而不是上面例子中的拦截器),切点可以应用于不同的bean

 

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 advisors bean definition. It offers the same merit of consistent configuration and avoidance of duplication as BeanNameAutoProxyCreator.

功能更加强大的自动代理创建是DefaultAdvisorAutoProxyCreator。将自动应用合适的advisor在当前的上下文中,而不需要包括指定的bean在自动代理的advisorbean定义中。他提供了相同一致性配置的优点和避免了重复作为BeanNameAutoProxyCreator

 

Using this mechanism involves:

使用这个策略调用:

 

    Specifying a DefaultAdvisorAutoProxyCreator bean definition.

指定一个DefaultAdvisorAutoProxyCreatorbean定义

    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.

指定任意数量的Advisor在相同或相关的上下文中。注意这些必须是Advisor,不只是拦截器或其他的advice。这是有必要的因为他们必须是一个可以计算的切点,来检查每个advice的合法性对于条件bean的定义。

 

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).

DefaultAdvisorAutoProxyCreator将自动评估切点包含在每个advice中的切点,来检查(任何)的advice应当应用于每个业务object(例如在上面例子中的businessObject1businessObject2)。

 

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.

这意味着任意数目的advisor可以被应用于每个业务object。如果没有切点在任何的advisor中匹配任何业务object中的方法,object将不会被代理。由于bean的定义被添加用于新的业务object,他们将自动被代理根据需要。

 

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.)

自动代理通常可以为用户标记不可能活依赖获取一个非advisedobject。调用应用上下文中的getBean("businessObject1")返回一个AOP代理,不是目标业务object。(之前的内部的bean的展示也提供了这样的效果。)

 

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

 

<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">

    <property name="transactionInterceptor" ref="transactionInterceptor"/>

</bean>

 

<bean id="customAdvisor" class="com.mycompany.MyAdvisor"/>

 

<bean id="businessObject1" class="com.mycompany.BusinessObject1">

    <!-- Properties omitted -->

</bean>

 

<bean id="businessObject2" class="com.mycompany.BusinessObject2"/>

 

The DefaultAdvisorAutoProxyCreator is very useful if you want to apply the same advice consistently to many business objects. Once the infrastructure definitions are in place, you can simply add new business objects without including specific proxy configuration. You can also drop in additional aspects very easily - for example, tracing or performance monitoring aspects - with minimal change to configuration.

DefaultAdvisorAutoProxyCreator是十分有用的如果你希望应用相同的advice一致的用于许多业务object。一旦基础结构定义,你可以简单的添加一个新的业务object而不需要包括指定的代理配置。你可以删除额外的aspect————例如跟踪或执行监控asepct————使用配置的最小化改变。

 

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.

DefaultAdvisorAutoProxyCreator也支持过滤(使用一个名称规范因此只有适当的advisor被处理,允许使用多种不同的配置的AdvisorAutoProxyCreators在相同的工厂)和顺序。Advisor可以实现org.springframework.core.Ordered接口来保证正确的顺序如果他是一个问题的话。TransactionAttributeSourceAdvisor在上面的例子中可以配置一个顺序变量;默认设置是无序的。

 

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.

这是DefaultAdvisorAutoProxyCreator的超类。你可以创建你自己的自动代理创建器通过继承这个类,在一些情况下advisor定义提供了足够的自定义对于框架DefaultAdvisorAutoProxyCreator的行为。

 

40.8.2 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.

一个特殊重要的自动代理类型是由元数据驱动的。这产生了一个类型的编程模型对于.NETServicedComponents。代替了使用xml部署描述符在EJB中,配置用于事务管理和其他企业级服务在源码级别的属性中。

 

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.

在这个例子中,你可以使用DefaultAdvisorAutoProxyCreator,组合Advisor来理解元数据属性。元数据指定可以保存在切点部分对于候选的advisor,而不是在自动代理创建类本身。

 

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.)

这是一个特殊的例子对于DefaultAdvisorAutoProxyCreator,但是值得考虑。(元数据代码在切点中包含在advisor中,而不是AOP框架本身。)

 

The /attributes directory of the JPetStore sample application shows the use of attribute-driven autoproxying. In this case, theres 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:

/attributes目录对于JPetStore的简单应用展示了使用属性驱动的自动代理。在这个例子中,不需要使用TransactionProxyFactoryBean。简单的定义事务属性对于业务object是足够的,因为使用元数据的切点。bean的定义包括在下面的代码中,在/WEB-INF/declarativeServices.xml文件中。注意这是通用的并且可以使用在JPetStore的外部。

 

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

 

<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">

    <property name="transactionInterceptor" ref="transactionInterceptor"/>

</bean>

 

<bean id="transactionInterceptor"

        class="org.springframework.transaction.interceptor.TransactionInterceptor">

    <property name="transactionManager" ref="transactionManager"/>

    <property name="transactionAttributeSource">

        <bean class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource">

            <property name="attributes" ref="attributes"/>

        </bean>

    </property>

</bean>

 

<bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/>

 

The DefaultAdvisorAutoProxyCreator bean definition (the name is not significant, hence it can even be omitted) will pick up all eligible pointcuts in the current application context. In this case, the "transactionAdvisor" bean definition, of type TransactionAttributeSourceAdvisor, will apply to classes or methods carrying a transaction attribute. The TransactionAttributeSourceAdvisor depends on a TransactionInterceptor, via constructor dependency. The example resolves this via autowiring. The AttributesTransactionAttributeSource depends on an implementation of the org.springframework.metadata.Attributes interface. In this fragment, the "attributes" bean satisfies this, using the Jakarta Commons Attributes API to obtain attribute information. (The application code must have been compiled using the Commons Attributes compilation task.)

DefaultAdvisorAutoProxyCreatorbean的定义(名字不是重要的,因此他可以被忽略)将使用所有合法的切点在当前的应用上下文中。在这个例子中,transactionAdvisorbean定义,类型是TransactionAttributeSourceAdvisor将应用于类或方法使用事务属性。TransactionAttributeSourceAdvisor依赖于TransactionInterceptor通过构造器依赖。案例处理这些自动包裹。AttributesTransactionAttributeSource依赖于org.springframework.metadata.Attributes接口的实现。在这个例子中,attributebean状态使用了Jakarta的通用属性API来获取属性信息。(应用代码必须被编译使用CommonAttribute的编译任务。)

 

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 Springs Transactional annotation, leading to implicit proxies for beans containing that annotation:

JPetStore/annotation目录的简单应用包含了一个类似的样例对于自动代理使用JDK1.5以上的注解驱动。下面的配置允许spring的事务注解的自动探测,暗示代理对于bean包含这些注解:

 

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

 

<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">

    <property name="transactionInterceptor" ref="transactionInterceptor"/>

</bean>

 

<bean id="transactionInterceptor"

        class="org.springframework.transaction.interceptor.TransactionInterceptor">

    <property name="transactionManager" ref="transactionManager"/>

    <property name="transactionAttributeSource">

        <bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>

    </property>

</bean>

 

The TransactionInterceptor defined here depends on a PlatformTransactionManager definition, which is not included in this generic file (although it could be) because it will be specific to the applications transaction requirements (typically JTA, as in this example, or Hibernate, JDO or JDBC):

TransactionInterceptor在这里的定义对于PlatformTransactionManager的定义,不包括在通用的文件中(尽管他是可以的)因为他是指定的对于应用事务需求(通常是JTA,作为在例子中,或HibernateJDOJDBC):

 

<bean id="transactionManager"

        class="org.springframework.transaction.jta.JtaTransactionManager"/>

 

[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 wont need to work directly with AOP, and the programming model is similar to that of .NET ServicedComponents.

如果你要求声明事务管理,使用这些通常的XML定义将导致在spring自动代理所有的类或方法使用事务属性。你不需要直接使用AOP,并且编程模型是类似于.NETServicedComponents的。

 

This mechanism is extensible. Its 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.

指定一个Advisor使用必要的advice,包括一个切点使用自定义的属性展示对于一个类或方法。你可以使用一个已有的advice、实现一个静态的切点使用自定义的属性。

 

Its 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:

对于一些advisor来说是唯一的对于每个advised类(例如,mixins):他们简单需要被定义作为原型而不是单例的bean的定义。例如,LockMixinintroduction的拦截器来自spring的测试包展示如上,可以被使用配合属性驱动的切点对于目标一个mixin,展示在这里。我们使用通常的DefaultPointcutAdvisor,配置使用JavaBean的属性。

 

<bean id="lockMixin" class="org.springframework.aop.LockMixin"

        scope="prototype"/>

 

<bean id="lockableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"

        scope="prototype">

    <property name="pointcut" ref="myAttributeAwarePointcut"/>

    <property name="advice" ref="lockMixin"/>

</bean>

 

<bean id="anyBean" class="anyclass" ...

 

If the attribute aware pointcut matches any methods in the anyBean or other bean definitions, the mixin will be applied. Note that both lockMixin and lockableAdvisor definitions are prototypes. The myAttributeAwarePointcut pointcut can be a singleton definition, as it doesnt hold state for individual advised objects.

如果属性意识到切点匹配任何在anyBean中的方法或其他bean的定义,mixin将被应用。注意lockMixinlockableAdvisor定义是原型的。myAttributeAwarePointcut点可以是一个单例的定义,因此他不能保持状态对于独立的advisedobject

 

40.9 Using TargetSources

使用TargetSources

 

Spring offers the concept of a TargetSource, expressed in the org.springframework.aop.TargetSource interface. This interface is responsible for returning the "target object" implementing the join point. The TargetSource implementation is asked for a target instance each time the AOP proxy handles a method invocation.

spring提供了TargetSources的内容,表述在org.springframework.aop.TargetSource接口中。这个接口代表返回的“目标object”实现了连接点。TargetSource实现被每次被要求一个AOP代理处理一个方法调用。

 

Developers using Spring AOP dont normally need to work directly with TargetSources, but this provides a powerful means of supporting pooling, hot swappable and other sophisticated targets. For example, a pooling TargetSource can return a different target instance for each invocation, using a pool to manage instances.

开发者使用springAOP不会直接需要使用TargetSource,但是这提供了一个强有力的方式关于支持池化,热部署和其他的复杂的object。例如,一个池话的TargetSource可以返回一个不同的目标接口对于每次调用,使用一个池来管理实例。

 

If you do not specify a TargetSource, a default implementation is used that wraps a local object. The same target is returned for each invocation (as you would expect).

如果你没有指定TargetSource,一个默认的实现会被使用来处理一个本地的object。相同的目标被返回对于每次的调用(根据你的期望)。

 

Lets look at the standard target sources provided with Spring, and how you can use them.

让我们来看一个标准的目标sourcesspring来提供以及如何使用他们。

 

[Tip]

提示

 

When using a custom target source, your target will usually need to be a prototype rather than a singleton bean definition. This allows Spring to create a new target instance when required.

当使用一个自定义的目标source,你的目标将需要是一个原型而不是一个单例的bean的定义。这允许spring根据需要来创建一个新的目标实例。

 

40.9.1 Hot swappable target sources

热替换目标source

 

The org.springframework.aop.target.HotSwappableTargetSource exists to allow the target of an AOP proxy to be switched while allowing callers to keep their references to it.

org.springframework.aop.target.HotSwappableTargetSource的存在使得允许AOP代理的目标可以被切换允许调用者来持有他们的引用。

 

Changing the target sources target takes effect immediately. The HotSwappableTargetSource is threadsafe.

改变目标的的目标可以直接生效。HotSwappableTargetSource是线程安全的。

 

You can change the target via the swap() method on HotSwappableTargetSource as follows:

你可以改变目标通过swap方法在HotSwappableTargetSource如下所示:

 

HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");

Object oldTarget = swapper.swap(newTarget);

 

The XML definitions required look as follows:

xml的定义要求如下:

 

<bean id="initialTarget" class="mycompany.OldTarget"/>

 

<bean id="swapper" class="org.springframework.aop.target.HotSwappableTargetSource">

    <constructor-arg ref="initialTarget"/>

</bean>

 

<bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="targetSource" ref="swapper"/>

</bean>

 

The above swap() call changes the target of the swappable bean. Clients who hold a reference to that bean will be unaware of the change, but will immediately start hitting the new target.

上面的swap调用改变了可替换bean的目标。客户端可以保持一个引用对于bean而察觉不到改变,但是将直接开始命中新的目标。

 

Although this example doesnt add any advice - and its not necessary to add advice to use a TargetSource - of course any TargetSource can be used in conjunction with arbitrary advice.

尽管这个例子不需要添加任何的advie————并且他不需要添加advice来使用TargetSource————当然任何的TargetSource可以被使用连同人任意的advice

 

40.9.2 Pooling target sources

池化目标source

 

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.

使用一个池话的目标source提供了一个类似的编程模型用于无状态的会话EJB,对于池中相同的实例在上面提到的,方法调用freeobject在池中。

 

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的池化和SLSB的池化石spring的池化可以应用于任意的POJO。由于spring是通用的,这个服务可以使用一个非侵入的方式。

 

Spring provides out-of-the-box support for Commons Pool 2.2, which provides a fairly efficient pooling implementation. Youll need the commons-pool Jar on your applications classpath to use this feature. Its also possible to subclass org.springframework.aop.target.AbstractPoolingTargetSource to support any other pooling API.

spring提供了一个外部的Common Pool 2.2,提哦了一个不同的池化实现。你需要一个commons-poolJar在你应用的classpath中来使用这个特性。他也可以继承org.springframework.aop.target.AbstractPoolingTargetSource来支持其他的池化的API

 

[Note]

注意

 

Commons Pool 1.5+ is also supported but deprecated as of Spring Framework 4.2.

Commons Pool1.5以上的版本支持但是没有废弃spring框架4.2

 

Sample configuration is shown below:

相同的配置被展示如下:

 

<bean id="businessObjectTarget" class="com.mycompany.MyBusinessObject" scope="prototype">

    ... properties omitted

</bean>

 

<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPool2TargetSource">

    <property name="targetBeanName" value="businessObjectTarget"/>

    <property name="maxSize" value="25"/>

</bean>

 

<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="targetSource" ref="poolTargetSource"/>

    <property name="interceptorNames" value="myInterceptor"/>

</bean>

 

Note that the target object - "businessObjectTarget" in the example - must be a prototype. This allows the PoolingTargetSource implementation to create new instances of the target to grow the pool as necessary. See the 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.

注意目标object————例子中的"businessObjectTarget"————必须是一个原型的。这允许PoolingTargetSource实现来创建一个新的实例对于目标来自于池根据需要。详见AbstractPoolingTargetSourcejavadocs和相关你希望使用的子类的内容有关maxSize是最基本的并且是可以实现的。

 

In this case, "myInterceptor" is the name of an interceptor that would need to be defined in the same IoC context. However, it isnt necessary to specify interceptors to use pooling. If you want only pooling, and no other advice, dont set the interceptorNames property at all.

在这个例子中,"myInterceptor"是一个拦截器的名字需要被定义在相同的IOC上下文中。然而,他不需要指定使用池化的拦截器。如果你只希望使用池化和其他的advice,不希望设置interceptorNames属性。

 

Its 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. Youll need to define an advisor like this:

可以配置spring对于转换任何的池化的objectorg.springframework.aop.target.PoolingConfig接口,暴露的消息有关配置和当前池的大小通过introduction。你将需要定义一个advisor如下:

 

<bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">

    <property name="targetObject" ref="poolTargetSource"/>

    <property name="targetMethod" value="getPoolingConfigMixin"/>

</bean>

 

This advisor is obtained by calling a convenience method on the AbstractPoolingTargetSource class, hence the use of MethodInvokingFactoryBean. This advisors name ("poolConfigAdvisor" here) must be in the list of interceptors names in the ProxyFactoryBean exposing the pooled object.

advisor通过一个方便的方法来获取对于AbstractPoolingTargetSource类,因此使用MethodInvokingFactoryBeanadvisor的名字(在这里是"poolConfigAdvisor")必须在拦截器的列表中在ProxyFactoryBean暴露了池化的object

 

The cast will look as follows:

转换展示如下:

 

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 dont believe it should be the default choice, as most stateless objects are naturally thread safe, and instance pooling is problematic if resources are cached.

池化的无状态服务不是必须的。我们不相信他可以是默认的选择,因为大部分无状态的object是天然线程安全的并且实例池是存在问题的如果资源被缓存的化。

 

Simpler pooling is available using autoproxying. Its possible to set the TargetSources used by any autoproxy creator.

相似的池对于使用自动代理是可用的。他可以设置TargetSources使用自动代理创建。

 

40.9.3 Prototype target sources

原型的目标source

 

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 isnt high in a modern JVM, the cost of wiring up the new object (satisfying its IoC dependencies) may be more expensive. Thus you shouldnt use this approach without very good reason.

设置一个原型的目标source是相似于池化的TargetSource。在这个例子中,一个新的目标的实例将被创建对于每次方法调用。尽管创建一个新的object的花费不是高于一个现代的JVM,处理新的object的花费(定义了IOC的依赖)大部分是很耗费资源的。因此你不应当使用这个方式除非有一个很好的理由。

 

To do this, you could modify the poolTargetSource definition shown above as follows. (Ive also changed the name, for clarity.)

为了这么做,你可以修改poolTargetSource的定义展示如下。(我们已经改变了名字,为了更加的清楚。)

 

<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">

    <property name="targetBeanName" ref="businessObjectTarget"/>

</bean>

 

Theres 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.

这只是一个属性:目标bean的名字。继承是使用在TargetSource实现来保证一致的命名。由于池化的目标source,目标bean必须是一个原型的bean的定义。

 

40.9.4 ThreadLocal target sources

本地线程的目标source

 

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是有用的如果你需要创建一个object对于每个输入的请求(对于每个线程)。本地线程的内容提供了一个JDK范围的工具对于存储资源对于一个线程。设置一个ThreadLocalTargetSource是相似于被表达的其他类型的目标source

 

<bean id="threadlocalTargetSource" class="org.springframework.aop.target.ThreadLocalTargetSource">

    <property name="targetBeanName" value="businessObjectTarget"/>

</bean>

 

[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. Springs ThreadLocal support does this for you and should always be considered in favor of using ThreadLocals without other proper handling code.

本地线程使用一些问题(潜在的结果在内存的缺陷中)当不正确的使用他们在多线程和多个classloader的环境中。应当考虑除了线程本地化在一些其他的类中并不直接使用线程本地化本身(除非包裹类)。尽管应当正确的设置和取消(后续可以简单的调用ThreadLocal.set(null))资源本地化对于一个线程。取消应当在任何的例子中不设置它的结果在一个有问题的行为中。spring的线程本地支持这么做并且考虑了使用线程本地化而没有其他适当的处理代码的情况。

 

40.10 Defining new Advice types

定义一个新的Advice类型

 

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.

springAOP是设计了一个可以扩展的。当拦截器实现策略是在内部使用的,他可以支持任意的advice类型对于外部的拦截器对于advice此外,异常advice和最终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.

org.springframework.aop.framework.adapter包是一个SPI的包允许支持一个自定义的advice类型的添加而不需要改变核心的框架。唯一的约束对于一个自定义的advice类型是必须实现org.aopalliance.aop.Advice的标记接口。

 

Please refer to the org.springframework.aop.framework.adapter packages Javadocs for further information.

请参考org.springframework.aop.framework.adapter包的javadocs来了解更多信息。

 

40.11 Further resources

更多的资源

 

Please refer to the Spring sample applications for further examples of Spring AOP:

请参考spring的样例应用来了解更多springAOP的例子:

 

    The JPetStores default configuration illustrates the use of the TransactionProxyFactoryBean for declarative transaction management.

JPetStore的默认配置指示了TransactionProxyFactoryBean的使用对于声明式的事务管理。

    The /attributes directory of the JPetStore illustrates the use of attribute-driven declarative transaction management.

/attributes对于JPetStore的目标指示了属性驱动的声明式事务管理。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值