这篇文章先补充两个AOP的概念:
一)引入(Introduction)
什么是引入?引入是在不修改目标对象的源代码的情况下,为目标对象增加方法和属性一种技术手段。
比如你有如下目标对象:
我们现在要在不修改DoOneThing的基础上,对其增添一个名叫doOtherThing()的方法。那么我们该如何将doOtherThing()引入呢?
首先,将要新增加的方法声明放在新的接口中。
然后编写引入类,实现拦截器IntroductionInterception和新方法接口。
最后,配置引入类
这样用户调用方法时,拦截器IntroductionInterception将方法拦截,判断所调用方法是否为新方法接口里的方法。如果为true,则会让其去调用该方法是实现,否则让其去继续调用原先的方法。
注:1、将拦截器实现和新方法接口名注入到DefaultIntroductionAdvisor中。
2、只能用构造器注入。
3、Spring的引入在性能上有缺陷所以应该尽量少用。
二)织入(Weaving)
把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象的过程叫做织入。这可以在编译时、载入类时、运行时完成(使用AspectJ编译器)。而Spring和其他纯Java AOP框架一样,在运行时完成织入。
大白话,织入就是AOP实现的过程,也就是在内存中动态生成的类那个时间点。回想下不管是动态代理还是CGLIB,这个过程都是必须的。
一)引入(Introduction)
什么是引入?引入是在不修改目标对象的源代码的情况下,为目标对象增加方法和属性一种技术手段。
比如你有如下目标对象:
public class DoThingBean {
public void DoOneThing(){
System.out.println("Do one thing!");
}
}
我们现在要在不修改DoOneThing的基础上,对其增添一个名叫doOtherThing()的方法。那么我们该如何将doOtherThing()引入呢?
首先,将要新增加的方法声明放在新的接口中。
public interface IOtherBean {
public void doOtherThing();
}
然后编写引入类,实现拦截器IntroductionInterception和新方法接口。
public class SomeBeanIntroductionInterceptor implements IOtherBean, IntroductionInterceptor {
public void doOtherThing() {
System.out.println("do other thing!");
}
public Object invoke(MethodInvocation invocation) throws Throwable {
//判断调用的方法是否为指定类中的方法
if ( implementsInterface(invocation.getMethod().getDeclaringClass()) ) {
return invocation.getMethod().invoke(this, invocation.getArguments());
}
return invocation.proceed();
}
/**
* 判断clazz是否为给定接口IOtherBean的实现
*/
public boolean implementsInterface(Class clazz) {
return clazz.isAssignableFrom(IOtherBean.class);
}
}
最后,配置引入类
<!-- 目标对象 -->
<bean id="someBeanTarget" class="aop.spring.introduction.SomeBeanImpl" />
<!-- 通知 -->
<bean id="someBeanAdvice" class="aop.spring.introduction.SomeBeanIntroductionInterceptor" />
<!-- 通知者,只能以构造器方法注入-->
<bean id="introductionAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
<constructor-arg ref="someBeanAdvice" />
<constructor-arg value="aop.spring.introduction.IOtherBean" />
</bean>
<!-- 代理 (将我们的切面织入到目标对象)-->
<bean id="someBeanProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 若目标对象实现了代理接口,则可以提供代理接口的配置 -->
<property name="proxyInterfaces" value="aop.spring.introduction.ISomeBean" />
<!-- 配置目标对象 -->
<property name="target" ref="someBeanTarget" />
<!-- 配置切面 -->
<property name="interceptorNames">
<list>
<value>introductionAdvisor</value>
</list>
</property>
</bean>
这样用户调用方法时,拦截器IntroductionInterception将方法拦截,判断所调用方法是否为新方法接口里的方法。如果为true,则会让其去调用该方法是实现,否则让其去继续调用原先的方法。
注:1、将拦截器实现和新方法接口名注入到DefaultIntroductionAdvisor中。
2、只能用构造器注入。
3、Spring的引入在性能上有缺陷所以应该尽量少用。
二)织入(Weaving)
把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象的过程叫做织入。这可以在编译时、载入类时、运行时完成(使用AspectJ编译器)。而Spring和其他纯Java AOP框架一样,在运行时完成织入。
大白话,织入就是AOP实现的过程,也就是在内存中动态生成的类那个时间点。回想下不管是动态代理还是CGLIB,这个过程都是必须的。