Aspect-oriented Program(AOP)
Background-背景
在实际的软件系统中,虽然日志、安全、事务管理必不可缺,但开发人员更多是希望关注业务核心代码。为了能更好的实现解耦合,AOP实现了把其他重要但无需过度关注功能,如日志、安全、事务管理等(称为横切关注点,cross-cutting concern)和业务逻辑相分离。横切关注点可以被模块化为特殊的类,称为切面(aspect)。
AOP terminology-术语
通知(Advice)
通知定义了切面是什么以及何时使用。
Spring aspects can work with five kinds of advice:
- • Before —The advice functionality takes place before the advised method is invoked.
- • After —The advice functionality takes place after the advised method completes, regardless of the outcome.
- • After-returning —The advice functionality takes place after the advised method successfully completes.
- • After-throwing —The advice functionality takes place after the advised method throws an exception.
- • Around —The advice wraps the advised method, providing some functionality before and after the advised method is invoked.
连接点(JoinPoint)
连接点是在应用执行过程 中能够插入切面的一个点。
切点(Pointcut)
切点定义了切面的“何处”,会匹配通知所织入得多个连接点。
织入(Weaving)
织入是把切面应用到目标对象并创建新的代理对象的过程。在目标对象的生命周期里有多个点可以进行织入:
- • Compile time —Aspects are woven in when the target class is compiled. 这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
- • Class load time —Aspects are woven in when the target class is loaded into the JVM. 这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该目标类的字节码。
- • Runtime —Aspects are woven in sometime during the execution of the application.一般情况下在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。Spring AOP就是以这种方式织入切面。
引入(Introduction)
引入是向现有的类添加新方法或属性。
因为Spring基于动态代理,所以只支持方法连接点。Spring缺少对字段连接点的支持,无法让我们创建细粒度的通知,例如拦截对象字段的修改。不支持构造器连接点,无法在bean创建时应用通知。而例如AspectJ和JBoss,除了方法切点,还提供了字段和构造器接入点。
使用注解创建切面
解析注解,创建切面代理,启用自动代理功能:
- JavaConfig:在配置类级别上使用
@EnableAspectJAutoProxy
- XML使用
<aop:aspectj-autoproxy>
在切面中使用参数
增加bean新方法或功能
使用Spring AOP,为bean实现新接口,引入新方法。代理拦截调用并委托给实现该方法的其他对象。借助AOP的引入功能,可以不必在设计上妥协或侵入性改变现有实现。
@Aspect public class ImplementIntroducer { @DeclareParents(value="package.Class+", defaultImpl=DefaultImplement.class)
public static Implement implement ; }
When Spring discovers a bean annotated with @Aspect , it will automatically create a proxy that delegates calls to either the proxied bean or to the introduction implementation
但是,面向注解的切面声明有一个明显的劣势:必须能在通知类中添加注解,也就是说必须要有源码。如果使用第三方包的话,就必须用XML声明
在XML中声明切面
使用 <aop:around>
元素声明环绕通知
为通知使用参数
<aop:config>
<aop:aspect ref="beanAspect">
<aop:pointcut id="trigger" expreesion="execution(* package.PCClass.method(int)) and args(paramter)" />
<aop:before pointcut-ref="trigger" method="triggerbefore" />
</aop:aspect>
</aop:config>
引入新功能
<aop:aspect>
<aop:declare-parents
types-matching="concert.Performance+"
implement-interface="concert.Encoreable"
default-impl="concert.DefaultEncoreable"
/>
</aop:aspect>
注入AspectJ切面
如果在创建切面时需要注入连接点或切点时,借助Spring的DI把bean装配到AspectJ切面中。
<bean class="package.Aspect" factory-method="aspectOf">
<property name="wiredBean" ref="wiredBean" />
</bean>
通常情况下,Spring bean由Spring container初始化,AspectJ切面在运行期创建。