Spring AOP基础2009-02-10 13:41本文目的简单了解Spring AOP基础知识点。
AOP概述
Spring AOP所涉及的Java基础知识
Spring AOP的增强类型
Spring AOP的切面类型
通过自动代理技术创建切面
AOP概述
编程语言最终极的目标就是能以更自然,更灵活的方式模拟世界,从原始机器语言道过程语言在岛面向对象的语言,编程语言一步步地用更自然,更强大的方式描述软件。AOP是软件开发饲养发展到一定阶段的产物,但Aop的出现并不是要完全代替OOP,而仅仅是作为OOP的有益补充。虽然AOP作为一项编程技术已经有多年的历史,但一直长时间停顿在学术领域,直到近几年,AOP才作为一项真正的实用技术在应用领域开疆扩土。需要指出的是AOP的应用场合是受限的,它一般只适合用于那些具有横切逻辑的应用场合:如性能监测,访问控制,事物管理以及日志记录(虽然很多讲解日志记录的例子用于AOP的讲解,但很多人认为很难用AOP编写实用日志。)不过,这丝毫不影响AOP作为一种新的软件开发思想在软件开发领域所占的地位。
AOP到底是什么
AOP 是Aspect Oriented Programing 的简称,最初被翻译为“面向方面编程”,这个翻译向来为人所诟病,但是由于先入为主的效应,受众广泛,所以这个翻译依然被很多人使用。但我们更倾向于用“面向切面编程”的译法,因为他表达更加准确。
AOP是一个软件层面的高度抽象,在现实世界中很难找到贴切的对应物,所以没有办法也只能同其他的讲解一样通过代码来帮助大家理解AOP的概念。
按照软件重构思想的概念,如果多个类中出现相同的代码,应该考虑定义一个相同的抽象类,将这些相同的代码提取到抽象类中。比如Cat,Dog,Pig这些对象都有跑行为run()和吃行为eat(),我们完全可以定义一个包含这两个方法的抽象父类Animal,然后通过引入父类来消除多个类中重复代码的方式。看一下代码:
package com.animal;
import java.util.Date;
public class IAnimalImpl implements IAnimal {
public void toEat(String animalName) {
System.out.println("IAnimalImpl 类toEat(String animalName)方法开始执行"+new Date());----*
System.out.println(animalName+"开始吃饭了");
System.out.println("IAnimalImpl 类toEat(String animalName)方法执行结束"+new Date());-----*
}
public void toRun(String animalName) {
System.out.println("IAnimalImpl 类toRun(String animalName)方法开始执行"+new Date());-----*
System.out.println(animalName+"吃饱了开始跑了");
System.out.println("IAnimalImpl 类toRun(String animalName)方法执行结束"+new Date());-----*
}
}
带*号的粗体部分淹没在业务逻辑代码中,这些非业务代码像藤一样缠着业务逻辑代码,而且执行的操作几乎相同。显然我们无法通过抽象父类的方式消除以上所示的重复性横切代码,因为这些代码横切逻辑依附在业务逻辑代码中,他们不能转移到其他的地方去。
AOP为我们通过横向抽取机制为这类无法通过纵向继承体系进行抽象的重复性代码提供了解决方案,AOP希望这些分散在各个业务中逻辑代码中的相同代码通过横向切割的方式提取一个独立的模块中,还业务逻辑类一个清新的世界。
当然我们知道将这些重复性的横切逻辑独立出来是很容易的,但如何将这些独立的逻辑融合到业务逻辑中完成和原来一样的业务逻辑,这才是事情的关键,也正是AOP要解决的主要问题。
AOP术语
连接点:Joinpoint
程序执行的某特特定位置:如类开始初始化前,类初始化后,类某个方法调用前,调用后,方法抛出异常后。一个类或一段程序拥有一些具有边界性质的特定点,这些代码中的特定点九称为“连接点”,Spring仅支持方法的连接点,即仅能在方法调用前,方法调用后,方法抛出异常时以及方法调用前后这些程序执行点织入增强,从某种程度上说AOP是一个黑客(因为它要想目前类中嵌入额外的代码逻辑),连接点就是AOP向目标类打入楔子的时候的点。
连接点有两个信息确定:第一是用方法表示的程序执行点,第二个是用相对点表示的方位。如在Test.to()方法执行前的连接点,执行点为Test.to(),方位为该方法执行前的位置。Spring使用切点对执行点进行定位,而方位则在增强类型中定义。
切点:Pointcut
每个程序都拥有多个连接点,如一个拥有两个方法的类,这两个方法都是连接点,即连接点是程序类中客观存在的事物,但在这为数不多的连接点中,如何定位到某个感兴趣的连接点上呢?AOP通过“切点”定位特定的连接点,通过数据库查询的感念来理解切点和连接点的关系在合适不过了:连接点相当于数据库中的记录,而切点相当于查询条件。切点和连接点不是一对一的关系,一个切点可以匹配多个连接点。
在Spring中,切点通过org.springframework.aop.Pointcut接口进行描述,他使用类和方法作为连接的查询条件,Spring AOP的规则解析引擎负责解析切点所设定的查询条件,找到对应的连接点---其实确切的说,应该是执行点而非连接点,因为连接点是方法执行前,执行后等包括方位信息的具体程序执行点,而切点只定位到某个方法上,所以如果希望定位到具体的连接点上,还需要提供方位信息。
增强:Advice
增强是织入到目标类连接点上的一段程序代码。是不是觉得AOP越来越像黑客了?这不是往业务代码中装入木马吗?在Spring中,增强除用于描述一段程序代码外,还拥有另一个和连接点相关的信息。这便是执行点的方法。结合执行点方法信息和切点信息。我们就可以找到特定的连接点了。正因为增强即包含了用于添加到目标连接点上的一段执行逻辑,有包含了用于定位连接点的方位信息,所以Spring所提供的增强接口带方位名的:BeforeAdvice,AfterRetuningAdvice,ThrowsAdvice等,
目标对象(traget):
增强逻辑的织入目标类,如果没有AOP,目标业务类需要自己实现所有逻辑,在AOP帮助下,目标类只需实现非横切逻辑的程序逻辑,而日志处理,性能监视等横切逻辑可以使用AOP动态织入到特定的连接点上.
引介: Introdction
引介是一种特殊的增强,他为类添加一些属性和方法,这样既使一个业务类原本没有实现某个接口,通过AOP的引介功能,我们可以动态地位该业务类添加接口的实例逻辑,让业务类成为这个接口的实现
类。
织入:Weaving
织入是将增强添加对目标类具体连接点上的过程,AOP像一台织布机,将目标类,增强或者引介通过AOP这台织布机天衣无缝的编制在一起,我们不能不说“织入”这个词太精辟了,根据不同的实现技术
,AOP有三种织入技术:
1)编译期织入,这要求使用特殊的Java编译器。
2)类加载期织入,这要求使用特殊的类装载器
3)动态代理织入,在运行期为目标类添加增强生成子类的方式。
Spring采用动态代理织入。
代理:Proxy
一个被AOP织入增强后,就产生了一个结果类,它是融合了原类和增强逻辑的代理类,根据不同的代理方式,代理类即可能是和原类具有相同接口的类,也可能就是原类的子类,所以我们可以采用调用原类相同的方式调用代理类。
切面:Aspect
切面由切点和增强(引介)组成,它既包括了横切逻辑的定义,也包括了连接点的定位,Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。
AOP的工作重心在于如何将增强应用于目标类对象的连接点上,这里首先包括两个工作,第一:如何通过切点和增强定位到连接点上,第二:如何在增强中编写切面的代码
Sprig AOP
Sping AOP是AOP的实现者之一:他使用纯Java实现,不需要专门的编译过程,不需要特殊的类加载器,他在运行期通过代理方式向目标类织入增强代码,Spring并不尝试提供最完美的AOP实现,相反它侧重于提供一种和Spring IoC容器整合的AOP实现,用以解决企业级开发中常见的问题,在Spring2.0中,我们可以天衣无缝的将Spring AOP,IoC和AspectJ整合在一起.
Spring 增强
前置增强:
Spring 使用增强类定义横切逻辑,同时由于Spring只支持方法连接点,增强还包括了在方法的那一个点加入横切代码的方法信息,所以增强还包括了在方法的那一点加入横切代码的方位信息,所以增强即包含横切逻辑,还包括部分连接点的信息.
创建一个前置增强类实现MethodBeforeAdvice接口,MethodBeforAdvice是BeforAdvice前置增强接口的子类。MethodBeforeAdvice接口中只定义了一个befor(Method method,Object[] args,Object obj)throws Throwabe,其中method为目标类的方法,args为目标类方法的入参,而obj为目标类的实例。当该方法出现异常时候,将阻止目标类方法的执行。
下面我们以刚才的代码为例子创建一个前置增强类,继承MethodBeforeAdvice接口,
package com.advice;
import java.lang.reflect.Method;
import java.util.Date;
import org.springframework.aop.MethodBeforeAdvice;
public class AnimalBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] arges, Object obj)
throws Throwable {
// TODO Auto-generated method stub
System.out.println(obj.getClass().getName()+"类"+method.getName()+"方法开始执 行"+new Date());
}
}
测试输出类
package test;
import com.animal.IAnimal;
import com.animal.IAnimalImpl;
import com.advice.AnimalBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
public class Test {
public static void main(String arges[])
{
//创建目标类
IAnimal CatTrage=new IAnimalImpl();
//目标类调用输出
CatTrage.toEat("小猫");
//前置增强类
AnimalBeforeAdvice beforeAdvice=new AnimalBeforeAdvice();
//Spring提供的代理工厂
ProxyFactory pf=new ProxyFactory();
//指定对接口代理
pf.setInterfaces(CatTrage.getClass().getInterfaces());
//指定代理目标
pf.setTarget(CatTrage);
//指定增强
pf.addAdvice(beforeAdvice);
//通过Spring工厂获得代理实例
IAnimal CatProxy=(IAnimal)pf.getProxy();
//调用输出
CatProxy.toEat("小猫");
CatProxy.toRun("小狗");
}
}
输出结果
小猫开始吃饭了
代理结果输出:
com.animal.IAnimalImpl类toEat方法开始执行Mon Feb 09 18:44:21 CST 2009
小猫开始吃饭了
com.animal.IAnimalImpl类toRun方法开始执行Mon Feb 09 18:44:21 CST 2009
小狗吃饱了开始跑了
解剖Spring中ProxyFactory
在Spring中我们使用了org.springframework.aop.framework.ProxyFactory代理工厂将Adivce织入到目标Bean中,ProxyFactory内部就是使用了JDK代理或CGIib代理的技术,将Adive应用到目标类中。
ProxyFactory是FactoryBean接口的实现类,它负责为其他的Bean创建代理实例,他内部使用ProxyFactory来完成这一工作,下面我们进一步了解ProxyFactoryBean的几个常用的可配置属性。
target:代理的目标对象。
proxyInterfaces:代理所有实现的接口,可以是多个接口,该属性还有一个别名属性interfaces
interceptorNames:需要织入目标对象的增强类名数组(必需采用全限定类名),在内部interceptorNames是一个字符串数组,ProxyFactoryBean通过反射机制获取对应的类,它们可以是拦截器,增强或包含增强和切点的Advisor,配置中的顺序对应调用的顺序。
Singleton:返回的代理是否为单实例,默认为单实例。
optimize:当设置为true时,强制使用CGLib代理,对于singleton的代理,我们推荐使用才CGLib代理,因为CGLib代理创建代理时速度慢,而产生出的代理对象运行效率高,而使用JDK代理的表现正好相反。
proxyTargetClass:是否对类进行代理(而不是对接口进行代理)设置为true时,使用CGLib代理。当设置成true时,无须在设置proxyInterface属性,即使设置也会被ProxyFactoryBean忽略。
大家可能已经注意到ProxyFactory通过addAdvice(Advice)添加一个增强,用户可以使用该方法添加多个增强,多个增强形成一个增强链,他们的调用顺序和添加顺序一致,可以通过addAdvice(int,Advice)将增强添加到增强链的具体位置。第一个位置为0。
Spring后置增强
同理自定义后置增强类实现AfterReturningAdvice来定义后置增强的逻辑,AfterReturningAdvice接口也定义了唯一方法afterReturning(Object returnObj,Method method,Object[] arges,Object obj)throws Throwable 其中returnObj为目标类实例方法返回结果,method为目标类方法,arges为目标类方法入参,obj为目标类实例。
假设在后置增强中抛出异常,如果该异常是目标类方法声明的异常,则该异常并归到目标类方法所声明的异常,如果该异常不是目标类方法声明的异常,Spring将其转为运行期异常抛出。
创建后置增强类:
package com.advice;
import java.lang.reflect.Method;
import java.util.Date;
import org.springframework.aop.AfterReturningAdvice;
public class AnimalAfterAdvice implements AfterReturningAdvice {
public void afterReturning(Object returnObj, Method method, Object[] arges,
Object obj) throws Throwable {
System.out.println(obj.getClass().getName()+"类"+method.getName()+"方法执行结束"+new Date());
}
}
利用ProxyFactory的addAdvice(Advice)方法添加后置增强pf.addAdvice(afterAdvice);
增强在Spring中的配置
<!-- 代理目标 -->
<bean id="targetAnimal" class="com.animal.IAnimalImpl" />
<!-- 前置增强 -->
<bean id="beforeAdvice" class="com.advice.AnimalBeforeAdvice" />
<!-- 后置增强 -->
<bean id="afterAdvice" class="com.advice.AnimalAfterAdvice" />
<!-- 创建代理 -->
<bean id="animal"
class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 指定代理接口 -->
<property name="proxyInterfaces">
<value>com.animal.IAnimal</value>
</property>
<!-- 指定增强类 -->
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
<value>afterAdvice</value>
</list>
</property>
<!-- 指定目标类 -->
<property name="target">
<ref local="targetAnimal" />
</property>
</bean>
环绕增强
环绕增强允许在目标类方法调用前后织入横切逻辑,它综合实现了前置,后置增强两者的功能。
Spring直接使用AOP联盟定义的MethodInterceptor最为环绕增强的接口,该接口容有唯一的接口方法Object invoke(MethodInvocation invocation)throws Throwable,MethodInvocation不但封装目标方法以及入参数组,还封装了目标方法所在实例对象,通过MethodInvocation的getArguments()可以获取目标方法的入参数组,通过procees()放射调用目标类实例相应的方法,通过在实现类中定义横切逻辑,很容易实现方法前后增强。
创建环绕增强类
package com.advice;
import java.util.Date;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AnimalInterceptAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
//目标类方法返回值
Object result=null;
//目标类名
String objName=invocation.getThis().getClass().getName();
//目标方法名
String methodName=invocation.getMethod().getName();
//目标方法参数
Object[] arges=invocation.getArguments();
//方法执行前增强
System.out.println(objName+"类"+methodName+"方法开始执行"+new Date()+"环绕增强");
//通过反射机制调用目标方法
result=invocation.proceed();
//方法执行后增强
System.out.println(objName+"类"+methodName+"方法执行结束"+new Date()+"环绕增强");
return result;
}
}
环绕增强在Spring中的配置
<!-- 代理目标 -->
<bean id="targetAnimal" class="com.animal.IAnimalImpl" />
<!-- 环绕增强 -->
<bean id="interceptAdvice" class="com.advice.AnimalInterceptAdvice" />
<!-- 创建代理 -->
<bean id="animal"
class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 指定代理接口 -->
<property name="proxyInterfaces">
<value>com.animal.IAnimal</value>
</property>
<!-- 指定增强类 -->
<property name="interceptorNames">
<list>
<value>interceptAdvice</value>
</list>
</property>
<!-- 指定目标类 -->
<property name="target">
<ref local="targetAnimal"/>
</property>
</bean>
创建切面
在介绍增强时,我们可能注意到一个问题,增强被织入目标类的所有方法中,假设我们希望有选择织入到目标类某些特定方法中,就需要使用切点进行目标连接点的定位了,增强提供了连接点的方位信息:如织入到方法前面,后面等,而切点进一步描述织入到那些类的那些方法上。
Spring通过org.springframework.aop.Pointcu接口描述切点,Pointcut由ClassFilter和MethodMatcher构成,它通过ClassFliter定位到某些特定类上,通过MethodMatcher定位到某些特定的方法上,这样Pointcut就拥有了描述某些特定类的某些特定方法的能力。
其中ClassFilter 只定义了一个方法matches(Class clazz),其参数代表一个被检测类,该方法判别被检测的类是否匹配过滤条件。
Spring支持两种方法匹配器:静态方法匹配器和动态方法匹配器,所谓静态方法匹配器,它仅对方法名签名(包括方法名和入参类型及顺序)进行匹配,而动态方法匹配器会在运行期检查方法入参的值。静态匹配仅会匹配一次,而动态匹配因为每次调用方法的入参可能都不一样,所以每次调用方法都必须判断,因此动态匹配对性能的影响很大。
一般情况下,动态匹配不常用,方法匹配器的类型由isRuntime()返回值决定。返回false,表示是静态方法匹配器,true表示动态方法匹配器。
切面类型:
由于增强即包含横切代码,有包含部分的连接点信息(方法前,方法后主方位信息),所以我们可以仅通过增强类生成一个切面,但切点仅代表目标类连接点的部分信息(类和方法的定位),所以仅有切点我们无法制作一个切面必须结合增强才能制作出切面。Spring中使用org.springframework.aop.Advisor接口表示切面的概念。一个切面同时包含横切代码和连接点的信息切面可以分为三类:一般切面,切点切面和引介切面。
下面我们介绍PointcutAdvisor切点切面:他包含Advice和Pointcut两个类。这样,我们就可以通过类,方法名以及方法为等信息灵活地定义切面的连接点,提供更具适用性的切面。
PointcutAdvisor主要有6个具体的实现类,我们只介绍一种:
RegexpMethodPointcutAdvisor:对于按正则表达式匹配方法名进行切点定义切面,可以通过扩展该实现类进行操作。RegexpMethodPointcutAdvisor允许用户以正则表达式模式串定义方法匹配的切点,其内部通过JdkRegexpMethodPointcut构造出正则表达式方法名切点。RegexpMethodPointcutAdvisor是用于同一个类中多个方法满足一定命名规范情况下。
advice属性:表示织入的增强。
patterns属性:用正则表达式定义目标类全限定方法名的匹配模式串。当只有一个匹配模式串时使用属性
pattern,当有多个匹配模式时候使用patterns,这些匹配串之间是“或”的关系。
order切面的织入时对应的顺序。
Spring环境下创建切面
<!-- 代理目标 -->
<bean id="targetAnimal" class="com.animal.IAnimalImpl" />
<!-- 环绕增强 -->
<bean id="interceptAdvice" class="com.advice.AnimalInterceptAdvice" />
<!-- 创建切面 -->
<bean id="regexAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!-- 指定正则表达式匹配串-->
<property name="patterns">
<list>
<value>.*toEat*.</value>
</list>
</property>
<!-- 织入增强-->
<property name="advice" ref="interceptAdvice"/>
</bean>
<!-- 创建代理 -->
<bean id="animal"
class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 指定代理接口 -->
<property name="proxyInterfaces">
<value>com.animal.IAnimal</value>
</property>
<!-- 指定增强类 -->
<property name="interceptorNames">
<list>
<value>regexAdvisor</value>
</list>
</property>
<!-- 指定目标类 -->
<property name="target">
<ref local="targetAnimal" />
</property>
</bean>
自动代理:
在前面所有例子中我们通过ProxyFactoryBean创建织入切面的代理,每一个需要被代理的Bean都需要使用一个ProxyFactoryBean 进行配置,虽然可以使用父子类关系进行改造,但仍属于增量配置,而且配置文件不易读懂,幸运的是Spring提供了自动代理机制,让容器为我们自动生成代理,在内部Spring使用BeanPostProcessor自动完成这项工作。
代理创建器:
基于BeanPostProcessor的自动代理创建器的实现类,将根据一些规则自动在容器实例化Bean时为匹配的Bean生成代理实例,这些代理创建器可以分为以下三类 :
基于Bean配置名规则的自动代理创建器,允许为一组特定配置名的Bean自动创建代理实例的代理创建器,实现类为BeanNameAutoPorxyCreator。
基于Advisor匹配机制的自动代理创建器,他会对容器中所有的Advisor进行扫描,自动将这些切面应用到匹配的Bean中(即为目标Bean创建代理实例)实现类为DefaultAdvisorAutoProxyCreator。
基于Bean中AspjectJ注解标签的自动代理创建器:为包含AspectJ注解的Bean自动创建代理实例,他的实现类是AnnotationAwareAspectJAutoProxyCreator该类是Spring2.0的新增类。
BeanNameAutoProxyCreator
下面我们以刚才的例子为基础,使用BeanNameAutoProxyCreator自动完成代理配置
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<!-- 添加代理的目标类 -->
<value>targetAnimal</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>regexAdvisor</value>
<!-- 此处可添加更新的拦截器 -->
</list>
</property>
</bean>
BeanNameAutoProxyCreator是Bean后处理器不需要被引用,因此没有ID属性,他根据指定拦截器为目标Bean自动创建代理。
beanNames属性: 他允许用户指定一组需要自动代理的Bean名称,Bean名称也可以使用通配符*,例如*er就指定了以er为后缀的规则可以将这两个Bean和容器中其他的Bean区分开。
配置如下:<property name="beanNames" value="*er">
当然这样有风险:我们也可以这样设置:value="wariter,seller".
interceptorNames:属性指定一个或者多个增强Bean 的名称,此外,还有一个optimize属性,如果将此属性设置为true将强制使用CGLib动态代理代理技术。
通过这样配置后我们可以向平常依赖注入一样使用目标Bean,而Bean后处理器BeanNameAutoProxyCreator根据指定的配置来自动完成代理。当我们需要为新的目标Bean做代理时只需添加beanNames属性,需要添加新的拦截器时只需添加interceptorNames属性,这样配置文件就变得简洁易懂了。
DefaultAdvisorAutoProxyCreator
我们知道切面Advisor是切点的增强复合体,Advisor本身已经包含了足够的信息,横切逻辑(要织入什么)以及连接点(织入到哪里)
DefaultAdvisorAutoProxyCreator能够扫描容器中Advisor,并将Advisor自动织入到匹配的目标Bean中,即为匹配的目标Bean自动创建代理
Spring 的配置文件如下
<!-- 代理目标 -->
<bean id="targetAnimal" class="com.animal.IAnimalImpl" />
<bean id="afterAdvice" class="com.advice.AnimalAfterAdvice" />
<!-- 环绕增强 -->
<bean id="interceptAdvice" class="com.advice.AnimalInterceptAdvice"/>
<!-- 创建切面 -->
<bean id="regexAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<list>
<value>.*toEat*.</value>
</list>
</property>
<property name="advice" ref="interceptAdvice"/>
</bean>
<!--Bean后处理器,没有ID属性不需要被应用-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
DefaultAdvisorAutoProxyCreator他将扫描配置文件中所有Advisor并为所有匹配的Bean自动创建代理.
BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator,Bean后处理器在Spring声明式事务处理中被广泛应用.在以后的部分我们详细介绍.
AOP与OOP的概念比较
常听到这样的声音AOP将要取代OOP,这是不正确的,首先AOP与OOP是两个方向的概念,AOP是横向的横切提取,OOP是纵向的抽象,封装继承.AOP只是OOP的延伸,他为程序开发提供了一个新的思考角度,可以将重复性的横切逻辑抽取到统一的模块中,通过OOP纵向抽象和AOP的横向提取,程序才可以真正的解决重复性问题.
OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分AOP则是针对业务处理过程中的切面(某个公共功能)进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。
AOP应该更确切的成为面向切面编程.
华语传统语义中的“方面”,大多数情况下指的是一件事情的不同维度、或者说不同角度上的特性,比如我们常说:“这件事情要从几个方面来看待”,往往意思是:需要从不同的角度来看待同一个事物。这里的“方面”,指的是事务的外在特性在不同观察角度下的体现。
举个简单的例子,对于“雇员”这样一个业务实体进行封
装,自然是OOP/OOD的任务,我们可以为其建立一个“Employee”类,并将“雇员”相关的属性和行为封装其中。而用AOP设计思想对“雇员”进行封装将无从谈起。
同样,对于“权限检查”这一动作片断进行划分,则是AOP的目标领域。而通过OOD/OOP对一个动作进行封装,则有点不伦不类。
AOP和OOD/OOP并不冲突,我们完全可以在一个应用系统中同时应用OOD/OOP和AOP设计思想,通过OOD/OOP对系统中的业务对象进行建模,同时通过AOP对实体处理过程中的阶段进行隔离处理.
AOP的两个最主要的特性
将不同阶段领域加以分隔
源码组成无关性