1、引言 2、AOP技术基础 3、
4、Java平台AOP技术研究(二)
3.2 Java平台下AOP主流工具研究
3.2.1 AsepctJ研究
AspectJ作为Java编程语言扩展的AOP工具,使得我们运用AOP技术能够像普通的Java编程那样,特殊之处,仅在于我们需要使用AspectJ提供的特殊语法。接下来,我将通过一些实例,介绍如何运用AspectJ实现AOP技术。
3.2.1.1 AspectJ语言特性
设定我们的开发项目中需要应用到日志记录,根据前面介绍的AOP知识,我们已经能够从这个需求中识别出横切关注点——日志记录。因此,我们需要定义关于“日志记录”的aspect:
public aspect AutoLog
pointcut publicMethods() : execution(public * org.apache.cactus..*(..));
pointcut logObjectCalls() : execution(* Logger.*(..));
pointcut loggableCalls() : publicMethods() && ! logObjectCalls();
before() : loggableCalls() Logger.entry(thisJoinPoint.getSignature().toString()); after() : loggableCalls() Logger.exit(thisJoinPoint.getSignature().toString()); }
如果仅仅熟悉Java编程,会发现有很多关键字是Java语言中不曾包含的,它们均是AspectJ提供的。
分析上述的代码,首先是aspect的声明,它类似于Java中的类声明,定义了一个aspect:AutoLog。在这个方面中分别包含了pointcut和advice。
pointcut共有三个:publicMethod、logObjectCalls和loggableCalls。publicMethod将选择org.apache.cactus包中的所有公共(public)方法的执行。所谓“选择”,就意味着它的join point为其选择的方法。当这些方法被调用时,就会执行pointcut的advice代码。而在pointcut中,execution 是一个原始的 Pointcut(就象 int 是一种原始的 Java 类型)。它选择与括号中定义的方法说明匹配的任何方法的执行。方法说明允许包含通配符。logObjectCalls的pointcut则选择Logger 类中的所有方法的执行。第三个pointcut比较特殊,它使用&& !合并了前两个 Pointcut,这意味着它选者了除Logger类中的公共方法以外, org.apache.cactus 中所有的公共方法。
advice在aspect中,被用来完成实际的日志纪录。advice有三种,分别为before、after和around。如上述代码中定义的advice:
before() : loggableCalls()
Logger.entry(thisJoinPoint.getSignature().toString());
}
该advice的定义表示的含义是,如果org.apache.cactus中所有的公共方法(Logger类的公共方法除外)被执行,则在这些方法执行之前,需要先执行该advice定义的逻辑。
3.2.1.2 AspectJ的高级语言特性
在本文第二部分介绍AOP技术时,提到了横切技术的分类。其中,静态横切技术能够扩展一个对象的结构。使用引入(Introduction),Aspect 可以向类中添加新的方法和变量、声明一个类实现一个接口或将检查异常转换为未检查异常(unchecked exception)。
3.2.1.2.1 向现有类添加变量和方法
假设您有一个表示持久存储的数据缓存的对象。为了测量数据的“更新程度”,您可能决定向该对象添加时间戳记字段,以便容易地检测对象是否与后备存储器同步。由于对象表示业务数据,根据AOP的知识,我们应该将这种机制性细节从对象中隔离。使用 AspectJ,可以用如下代码中所显示的语法来向现有的类添加时间戳记:
public aspect Timestamp
private long ValueObject.timestamp;
public long ValueObject.getTimestamp()
return timestamp;
public void ValueObject.timestamp()
this.timestamp = System.currentTimeMillis();
}
通过introduction,我们就非常方便的为ValueObject类型添加了timestamp的变量和相关方法。除了必须限定在哪个类上声明引入的方法和成员变量以外,声明引入的方法和成员变量几乎与声明常规类成员相同。
3.2.1.2.2实现多继承功能
利用introduction,AspectJ允许向接口和类添加成员,也突破了Java语言只能单继承的限制,允许程序按C++方式那样实现多继承。如果您希望上述的aspect Timestamp能够泛化 (generalize),以便能够对各种对象重用时间戳记代码,可以定义一个称为 TimestampedObject 的接口,并使用引入(Introduction)来将相同成员和变量添加到接口而不是添加到具体类中,如下所示:
public interface TimestampedObject
long getTimestamp();
void timestamp();
public aspect Timestamp
private long TimestampedObject.timestamp;
public long TimestampedObject.getTimestamp()
return timestamp;
public void TimestampedObject.timestamp()
this.timestamp = System.currentTimeMillis();
}
Timestamp方面由于在TimestampedObject接口中引入(introduction)了方法的实现,使得TimestampedObject接口改变其本质,成为了一个特殊的类类型。特殊之处就在于一个已经继承了一个类的类类型,通过AspectJ的语法,仍然可以再次继承TimestampedObject,这就间接地实现了类的多继承。而这个特殊的AspectJ语法就是declare parents语法。declare parents和其它AspectJ 类型表达一样,可以同时应用于多个类型:
declare parents: ValueObject || BigValueObject implements TimestampedObject;
3.2.1.3 编译器及工具支持
要让aspect能够正常工作,必须将aspect加入到它们要修改的代码中去。这项工作由AspectJ提供的ajc编译器完成。ajc 编译器用来编译类和 Aspect 代码。ajc 既可以作为编译器也可以作为预编译器操作,生成有效的 .class 或 .java 文件,可以在任何标准 Java 环境(添加一个小的运行时 JAR)中编译和运行这些文件。
要使用 AspectJ 进行编译,将需要显式地指定希望在给定编译中包含的源文件(Aspect 和类),ajc不象javac那样简单地为相关导入模块搜索类路径。之所以这样做,是因为标准 Java 应用程序中的每个类都是相对分离的组件。为了正确操作,一个类只要求其直接引用的类的存在。Aspect 表示跨越多个类的行为的聚集。因此,需要将 AOP 程序作为一个单元来编译,而不能每次编译一个类。
AspectJ 当前版本的一个重要限制是其编译器只能将aspect加入到它拥有源代码的代码中。也就是说,不能使用ajc将Advice添加到预编译类中。AspectJ 团队认为这个限制只是暂时的,AspectJ 网站承诺未来的版本(正式版 2.0)将允许字节码的修改。
AspectJ发行版包含了几种开发工具。这预示着 AspectJ 将有美好的前景,因为它表明了作者对这一部分的一个重要承诺,使 AspectJ 对于开发人员将是友好的。对于面向 Aspect 的系统工具支持尤其重要,因为程序模块可能受到它们所未知的模块所影响。
随 AspectJ 一起发布的一个最重要的工具是图形结构浏览器,它展示了 Aspect 如何与其它系统组件交互。这个结构浏览器既可以作为流行的 IDE 的插件,也可以作为独立的工具。图3.4显示了先前讨论的日志记录示例的视图。
图3.4 AspectJ提供的“结构浏览器”工具
除了结构浏览器和核心编译器之外,您还可以从 AspectJ 网站下载一个 Aspect 支持的调试器、一个javadoc工具、一个Ant任务以及一个Emacs 插件。
3.2.2 JBoss AOP研究
JBoss AOP关于AOP的实现与AspectJ是两种完全不同的风格。由于Java利用元数据来存储有关类型、方法、字段的相关信息,因此,可以通过Java提供的反射功能获得模块相关的元数据,对方法进行拦截,并将被拦截的方法与aspect逻辑进行关联。
3.2.2.1 拦截器(Interceptor)
在JBoss AOP中,是用拦截器来实现advice的。可以自定义拦截器,拦截方法调用、构造函数调用以及对字段的访问,但JBoss要求这些自定义的拦截器,必须实现org.jboss.aop.Interceptor接口:
public interface Interceptor
public String getName();
public InvocationResponse invoke(Invocation invocation) throws Throwable;
}
在JBoss AOP中,被拦截的字段、构造器和方法均被转化为通用的invoke方法调用。方法的参数接收一个Invocation对象,而方法的返回值、字段的存取以及构造函数则被填入一个InvocationResponse对象。Invocation对象同时还驱动拦截链。下面我们自定义一个拦截器,它能够拦截构造函数和方法的调用,并将跟踪信息打印到控制台上:
import org.jboss.aop.*;
import java.lang.reflect.*;
public class TracingInterceptor implements Interceptor
public String getName()
return TracingInterceptor;
public InvocationResponse invoke(Invocation invocation) throws Throwable
String message = null;
if (invocation.getType() == InvocationType.METHOD)
Method method = MethodInvocation.getMethod(invocation);
message = method: + method.getName();
else
if (invocation.getType() == InvocationType.CONSTRUCTOR)
Constructor c = ConstructorInvocation.getConstructor(invocation);
message = constructor: + c.toString();
else
// 不对字段作处理,太繁琐;
return invocation.invokeNext();
System.out.println(Entering + message);
// 继续。调用真正的方法或者构造函数
InvocationResponse rsp = invocation.invokeNext();
System.out.println(Leaving + message);
return rsp;
}
在自定义的TracingInterceptor类中,invoke()方法对invocation的类型作判断,以根据方法、构造函数和字段类型,分别作出不同的操作。而其中,invocation.invokeNext()则表示通过一个拦截链获得下一个invocation。
定义的拦截必须在xml文件配置,使其绑定到具体的类。这个定义即为AOP中的切入点pointcut。例如具体的类为BusinessObject,则该pointcut在xml中的定义如下:
<?xml version="1.0" encoding="UTF-8">
<aop>
<interceptor-pointcut class="BusinessObject">
<interceptors>
<interceptor class="TracingInterceptor" />
</interceptors>
</interceptor-pointcut>
</aop>
上面的pointcut绑定TracingInterceptor到一个叫做BusinessObject的类。如果要将该Interceptor绑定到多个类,还可以利用正则表达式。例如,如果你想绑定由JVM载入的类,类表达式将变为 .*。如果你仅仅想跟踪一个特定的包,那么表达式将是bruce.zhang.mypackge.*。
当JBoss AOP独立运行时,任何符合 META-INF/jboss-aop.xml模式的XML文件将被JBoss AOP 运行期程序载入。如果相关的路径被包含在任何JAR或你的CLASSPATH目录中,该XML文件将在启动时,由JBoss AOP 运行期程序载入。
JBoss AOP还提供了过滤功能,可以通过在xml文件中配置过滤的标志,使一些特定的方法(包括字段的访问)被过滤,从而不再执行Interceptor的相关逻辑。例如,我们要过滤BusinessObject类的所有get()和set()方法,以及main()方法,则可以修改上述的xml文件:
<?xml version="1.0" encoding="UTF-8">
<aop>
<class-metadata group="tracing" class=" BusinessObject ">
<method name="(get.*)|(set.*)">
<filter>true</filter>
</method>
<method name="main">
<filter>true</filter>
</method>
</class-metadata>
</aop>
相应的,Interceptor代码也应作相关的修改,使其能够识别配置文件中的filter属性:
public class TracingInterceptor implements Interceptor
……//getName()方法略;
public InvocationResponse invoke(Invocation invocation) throws Throwable
String filter=(String)invocation.getMetaData(tracing, filter);
if (filter != null && filter.equals(true))
return invocation.invokeNext();
}
}
3.2.2.2 引入(Introduction)
JBoss AOP同样提供introduction功能,通过它,就可以为现有的类引入第三方接口或类的API了。例如,我们可以为具体的类如BusinessObject提供Tracing的开关,使得BusinessObject对象能够根据具体的情况打开或关闭aspect的Tracing功能。为实现该功能,可以定义一个Tracing接口:
public interface Tracing
void enableTracing();
void disableTracing();
}
接下来需要定义一个混合类,它实现了接口Tracing。当BusinessObject类被实例化时,该混合类的实例就会被绑定到BusinessObject上。实现方法如下:
import org.jboss.aop.Advised;
public class TracingMixin implements Tracing Advised advised;
Public TracingMixin(Object obj) this.advised = (Advised)obj; public void enableTracing() advised._getInstanceAdvisor().getMetaData().addMetaData("tracing", "filter", true); public void disableTracing() advised._getInstanceAdvisor().getMetaData().addMetaData("tracing", "filter", false); }
enableTracing()方法将filter属性绑定到对象实例。disableTracing()方法作同样的事,但是将filter属性设置为false。
定义了Tracing接口和实现了该接口的混合类后,就可以在xml文件中定义一个pointcut,强制BusinessObject类实现Tracing接口:
<?xml version="1.0" encoding="UTF-8">
<aop>
<introduction-pointcut class="BusinessObject">
<mixin>
<interfaces>Tracing</interfaces>
<class>TracingMixin</class>
<construction>new TracingMixin(this)</construction>
</mixin>
</introduction-pointcut>
</aop>
注意xml文件中的标签,它代表的含义是当BusinessObject对象被实例化时,将执行该标签内的代码。以本例而言,当创建BusinessObject对象时,一个TracingMixin类的实例将被创建。任何单行的Java代码都可以放到标签中。
通过“引入(introduction)”功能,在处理BusinessObject对象时,就可以视其为Tracing接口类型而进行操作了,如下的示例:
public class BusinessObject
public BusinessObject () {}
public void helloWorld() { System.out.println(Hello World!); }
public static void main(String[] args)
BusinessObject bo = new BusinessObject ();
Tracing trace = (Tracing)this;
bo.helloWorld();
System.out.println("Turn off tracing.");
trace.disableTracing();
bo.helloWorld();
System.out.println("Turn on tracing.");
trace.enableTracing();
bo.helloWorld();
}
注意如下代码:
Tracing trace = (Tracing)this;
此时this代表的即为BusinessObject,从Java代码的角度来看,由于BusinessObject并没有实现Tracing接口,因此这行代码所示的显式转换为Tracing类型是不成功的。但通过“引入”功能,使得BusinessObject通过混合类,实现了Tracing接口,从而使得如上的代码能够顺利执行。隐含的意义就是,我们没有修改BusinessObject的定义,而是通过AOP技术,为BusinessObject扩展实现了第三方提供的接口Tracing。
3.2.3 Spring AOP研究
Spring AOP使用纯Java实现,不需要特别的编译过程,也不需要控制类装载层次。与JBoss AOP相同,它仍然利用了拦截器完成对方法的拦截。然而,Spring AOP实现AOP的主要技术却主要来自于AOP联盟,如拦截器应实现org.aopalliance.intercept.MethodInterceptor 接口,而所有advice必须实现org.aopalliance.aop.Advice标签接口。此外,Spring实现AOP的目标也不同于其他大部分AOP框架,它的目标不是提供及其完善的AOP实现,而是提供一个和Spring IoC紧密整合的AOP实现,帮助解决企业应用 中的常见问题。因此,Spring AOP的功能通常是和Spring IoC容器联合使用的。AOP Advice是用普通的bean定义语法来定义的,Advice和pointcut本身由Spring IoC 管理。这是一个重要的其他AOP实现的区别。
3.2.3.1 切入点(pointcut)
Spring的切入点模型能够使pointcut独立于advice类型被重用。同样的pointcut有可能接受不同的advice。将Pointcut接口分成两个部分有利于重用类和方法的匹配部分,并且组合细粒度的操作(如和另一个方法匹配器执行一个“并”的操作)。
在Spring的切入点中,org.springframework.aop.Pointcut接口是重要的接口,它用来指定通知到特定的类和方法目标。完整的接口定义如下:
public interface Pointcut
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
ClassFilte类型也是一个接口,该接口被用来将切入点限制到一个给定的目标类的集合。 如果matches()永远返回true,所有的目标类都将被匹配。
public interface ClassFilter
boolean matches(Class clazz);
}
MethodMatcher接口通常更加重要。完整的接口定义如下:
public interface MethodMatcher
boolean matches(Method m, Class targetClass);
boolean matches(Method m, Class targetClass, Object[] args);
boolean isRuntime();
}
matches(Method, Class) 方法被用来测试这个切入点是否匹配目标类的给定方法。这个测试可以在AOP代理创建的时候执行,避免在所有方法调用时都需要进行 测试。如果2个参数的matches()方法对某个方法返回true,并且MethodMatcher的isRuntime()也返回true,那么3个参数的matches()方法将在每次方法调用的时候被调用。这使切入点能够在目标advice被执行之前立即查看传递给方法调用的参数。由于大部分MethodMatcher都是静态的,意味着isRuntime()方法会返回false。此种情况下,3个参数的matches()方法永远不会被调用。
Spring AOP提供了几个实用的切入点实现,其中较为常用的是正则表达式切入点:org.springframework.aop.support.RegexpMethodPointcut,它使用Perl 5的正则表达式的语法。使用这个类你可以定义一个模式的列表。如果任何一个匹配,那个切入点将被计算成 true。用法如下:
<bean id="settersAndAbsquatulatePointcut"
class="org.springframework.aop.support.RegexpMethodPointcut">
<property name="patterns">
<list>
<value>.*get.*</value>
<value>.*absquatulate</value>
</list>
</property>
</bean>
不过,更多情况下是直接使用RegexpMethodPointcut一个实用子类: RegexpMethodPointcutAdvisor。它允许我们同时引用一个advice(在Spring AOP中,advice可以是拦截器,也可以是before advice,throws advice等)。这就简化了bean的装配,因为一个bean可以同时当作pointcut和advice,如下所示:
<bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="MyInterceptor" />
</property>
<property name="patterns">
<list>
<value>.*save.*</value>
<value>.*do.*</value>
</list>
</property>
</bean>
注意配置文件中的myPointcutAdvisor,在Spring AOP中,一个advisor就是一个aspect完整的模块化表示。通过advisor,可以将pointcut和advice(在此处即为MyInterceptor)绑定起来。
3.2.3.2 通知(advice)
Spring AOP的advice可以跨越多个被advice对象共享,或者每个被advice对象有自己的advice。要实现advice,最简单的做法就是定义一个拦截器(Interceptor)。它采用了AOP联盟(AOP Alliance)的通用AOP接口(接口定义为aopalliance.jar)。要实现advice,需要实现aopalliance.jar中定义的MethodInterceptor接口。
例如,我们定义了一个业务对象接口BusinessObject及其实现类BusinessObjectImpl,该业务对象能够存储数据,其定义如下:
public interface BusinessObject
public void save();
public class BusinessObjectImpl implements BusinessObject
public void save()
System.out.println("saving domain object......");
}
现在需要为业务对象BusinessObject的Save()方法,提供Lock机制。根据Spring AOP的实现方式,我们可以定义一个LockInterceptor来实现MethodInterceptor接口:
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class LockInterceptor implements MethodInterceptor
public Object invoke(MethodInvocation invocation) throws Throwable
// TODO Auto-generated method stub
lock();
Object ret= invocation.proceed();
unlock();
return ret;
private void lock()
System.out.println("lock domain object...");
private void unlock()
System.out.println("unlock domain object...");
}
为将interceptor与具体的advice绑定起来,需要在配置文件中配置bean:
<bean id="MyInterceptor" class="test.aop.spring.LockInterceptor"/>
3.2.3.3 AOP代理与IoC容器
由于Spring中提供了IoC容器(例如BeanFactory),因此我们可以通过Ioc机制,利用ProxyFactoryBean来创建AOP代理。ProxyFactoryBean和其他Spring的 FactoryBean实现一样,引入一个间接的层次。如果你定义一个名字为foo的ProxyFactoryBean,引用foo的对象所看到的不是ProxyFactoryBean实例本身,而是由实现ProxyFactoryBean的类的 getObject()方法所创建的对象。这个方法将创建一个包装了目标对象 的AOP代理。
AOP代理利用的是Java的动态代理技术,通过它就可以加载并执行AOP组件。同时,还需要通过IoC的方式将advice注入到接口以及其实现类。以前面的业务对象BusinessObject为例,在xml配置文件中的配置如下:
<bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>test.aop.spring.BusinessObject</value>
</property>
<property name="target">
<ref local="impl" />
</property>
<property name="interceptorNames">
<value>myPointcutAdvisor</value>
</property>
</bean>
<bean id="impl" class="test.aop.spring.BusinessObjectImpl"/>
通过上述对pointcut、advice、advisor和AOP代理的配置,我们就可以轻易地在Spring中实现AOP,例如:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class App
private BusinessObject bo = null;
public static void main(String[] args)
ApplicationContext ctx=new FileSystemXmlApplicationContext("Bean.xml");
bo= (BusinessObject) ctx.getBean("myAOPProxy");
bo.save();
}
首先,通过AOP代理获得BusinessObject对象。当调用BusinessObject对象的save()方法时,拦截器LockInterceptor根据RegexpMethodPointcutAdvisor配置的pointcut和advice之间的关系,判定该方法的调用为join point,从而拦截该方法调用,并注入advice的执行逻辑,即lock()和unlock(),最终实现了AOP。
3.2.3.4 引入(introduction)
在Spring AOP中,将introduction当作advice来处理。与一般的advice一样,introduction advice相当于一种特殊类型的拦截通知,需要实现IntroductionAdvisor和IntroductionInterceptor接口,而IntroductionInterceptor接口继承自MethodInterceptor:
public interface IntroductionInterceptor extends MethodInterceptor
boolean implementsInterface(Class intf);
}
Introduction通知不能被用于任何pointcut,因为它只能作用于类层次上,而不是方法。我们可以只用InterceptionIntroductionAdvisor来实现导入通知,它有下面的方法:
public interface InterceptionIntroductionAdvisor extends InterceptionAdvisor
ClassFilter getClassFilter();
IntroductionInterceptor getIntroductionInterceptor();
Class[] getInterfaces();
}
接下来,我以JBoss AOP一节中的例子来说明introduction在Spring AOP中的应用。我们的目标仍然是为一个已有的业务对象引入第三方接口Tracing:
public interface Tracing
void enableTracing();
void disableTracing();
boolean enabled();
}
首先,我们需要一个做大量转化的IntroductionInterceptor。在这里,我们继承 org.springframework.aop.support.DelegatingIntroductionInterceptor 实现类。当然我们可以直接实现IntroductionInterceptor接口,但是大多数情况下 DelegatingIntroductionInterceptor是最合适的。
DelegatingIntroductionInterceptor的设计是将introduction委托到真正实现introduction接口的接口,隐藏完成这些工作的拦截器。委托可以使用构造方法参数设置到任何对象中;默认的委托就是自己(当无参数的构造方法被使用时)。这样在下面的例子里,委托是DelegatingIntroductionInterceptor的子类 TracingMixin。给定一个委托(默认是自身)的 DelegatingIntroductionInterceptor实例寻找被这个委托(而不是IntroductionInterceptor)实现的所有接口,并支持它们中任何一个导入。子类如TracingMixi也可能调用suppressInterflace(Class intf) 方法来隐藏不应暴露的接口。然而,不管IntroductionInterceptor 准备支持多少接口,IntroductionAdvisor将控制哪个接口将被实际暴露。一个导入的接口将隐藏目标的同一个接口的所有实现。
这样,TracingMixin继承DelegatingIntroductionInterceptor并自己实现接口Tracing。父类自动选择支持introduction的Tracing,所以我们不需要指定它。用这种方法我们可以导入任意数量的接口。
public class TracingMixin extends DelegatingIntroductionInterceptor implements Tracing
private boolean enabled;
public void enableTracing ()
this.enabled = true;
}
public void disableTracing ()
this. enabled = false;
}
public boolean enabled() return this.enabled; public Object invoke(MethodInvocation invocation) throws Throwable return super.invoke(invocation); }
通常不要需要改写invoke()方法:实现DelegatingIntroductionInterceptor就足够了,如果是引入的方法,DelegatingIntroductionInterceptor实现会调用委托方法, 否则继续沿着连接点处理。
所需的introduction advisor是很简单的。只需保存一个独立的TracingMixin实例,并指定导入的接口,在这里就是Tracing。此时,TracingMixin没有相关配置,所以我们简单地使用new来创建它。
public class TracingMixinAdvisor extends DefaultIntroductionAdvisor
public TracingMixinAdvisor() {
super(new TracingMixin(),Tracing.class);
}
我们可以非常简单地使用这个advisor。它不需要任何配置。(但是,有一点是必要的:就是不可能在没有IntroductionAdvisor 的情况下使用IntroductionInterceptor。) 和引入一样,通常 advisor必须是针对每个实例的,并且是有状态的。我们会有不同的TracingMixinAdvisor。每个被通知对象,会有不同的TracingMixin。advisor组成了被通知对象的状态的一部分。
在Spring中,Spring AOP的核心API已经基本稳定了。和Spring的其它部分一样, AOP框架是模块化的,在保留基础设计的同时提供扩展。在Spring 1.1到1.2阶段有很多地方可能会有所提高,但是这些地方也保留了向后兼容性。它们是:
(一)性能的提高:AOP代理的创建由工厂通过策略接口处理。因此能够支持额外的AOP 代理类型而不影响用户代码或核心实现。
(二)更具表达力的pointcut:Spring目前提供了一个具有表达力的切入点接口,同时添加了更多的切入点实现。Spring正在考虑提供一个简单但具有强大表达式语言的实现。