1. Spring AOP 的实现类是 ProxyFactoryBean ,这个工厂bean 提供了可配置的特性。一个简单的例子:
<bean name="speakServiceProxy" class="other.pattern.SpringAopProxy.ServiceProxy">
</bean>
<bean name="speakService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>speakServiceProxy</value>
</list>
</property>
<!-- 被代理的接口 -->
<!--
<property name="proxyInterfaces" value="other.pattern.SpringAopProxy.SpeakService"/>
-->
<property name="interfaces">
<list>
<value>other.pattern.SpringAopProxy.SpeakService</value>
</list>
</property>
</bean>
<!-- test Bean -->
<bean name="test" class="other.pattern.SpringAopProxy.TestAop">
<property name="speakService">
<ref bean="speakService"></ref>
</property>
</bean>
AOP 的几个概念:参见Spring 参考手册。
1. Advisor = pointcut+advice ;
切点就是接口对应的方法,在Spring实现中,ProxyFactoryBean,指定需要代理的接口:配置bean的属性 interfaces。
或者 proxyInterface 属性,指定interceptorNames ,这个就是advice,需要织入的逻辑。
最后返回一个实现了这个接口的代理,对于环切增强要实现 MethodInterceptor接口:包装成DefaultPointcutAdvisor;
2. JdkDynamicAopProxy 是Spring自带的Aop代理,是JDK动态代理实现。
interceptorNames 对应的是方法拦截器:通过IOC配置的 speakService 这个bean,返回的就是ProxyFactoryBean 的getObject()方法返回的实例对象。
=========注解===========
这是因为 Spring的IOC 容器(IOC容器就是一个工厂的具体实现,典型的工厂方法。Spring根据不同的场景有几种不同的IOC容器,比如在classpath上下文加载bean的ClassPathXmlApplicationContext)发现这个 "speakService " 配置的class是一个factoryBean ,就会调用这个factoryBean的getObject() 方法,“speakService”就是getObject()返回的实例(FactoryBean就是一个简单工厂,简单工厂不在23种设计模式里面)。
==========end===========
getObject()方法返回一个代理,ProxyFactoryBean 由下面方法返回代理
protected Object getProxy(AopProxy aopProxy)
{
return aopProxy.getProxy(this.proxyClassLoader);
}
AopProxy 的JDK代理的实现类是 JdkDynamicAopProxy ,实现了 InvocationHandler接口 。
JdkDynamicAopProxy 调用 Proxy.newProxyInstance(classLoader, proxiedInterfaces, this) 方法生成一个代理实例对象。
Proxy 类需要持有一个 InvocationHandler 实例,这个实例就是动态生成的代理实例真正调用的对象。
======================JDK代理=========================
JDK动态代理:
Jdk动态代理,是基于接口的。先定义一个subject接口,以及一个代理实现类。
代理实现类要实现InvocationHandler接口。在生成的代理实例proxy对象里,实现了subject接口的全部方法。
下面是jdk生成的代理实例对象的字节码;反编译过来的。
继承Proxy类,实现目标接口UserInterface。
可以发现,代理实例对象的所有方法都是调用java包 Proxy类持有的super.h.invoke(this, m4, null)方法。h就是我们调用Proxy生成字节码时传进去的代理实现类实例对象。
这个方法用来生成代理实例对象的字节码。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h)
public final class UserInterface extends Proxy
implements UserInterface
{
public UserInterface(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void jump()
{
try
{
super.h.invoke(this, m4, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String speak()
{
try
{
return (String)super.h.invoke(this, m3, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m1;
private static Method m4;
private static Method m0;
private static Method m3;
private static Method m2;
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m4 = Class.forName("jvm.JDKProxy.UserInterface").getMethod("jump", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("jvm.JDKProxy.UserInterface").getMethod("speak", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
==================end======================
下面看看 JdkDynamicAopProxy 实现的 InvocationHandler 接口的 方法:
public Object invoke(Object proxy, Method method, Object[] args)
这个方法里调用了AOP联盟的方法,所以需要引入aopallien.jar 包。真正的方法调用就是这一段
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
/* */
/* 204 */ retVal = invocation.proceed();
具体看看 MethodInvocation的实现:
public Object proceed()
/* */ throws Throwable
/* */ {
/* 149 */ if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
/* 150 */ return invokeJoinpoint();
/* */ }
/* */
/* 153 */ Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
/* */
/* 155 */ if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher)
/* */ {
/* 158 */ InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
/* */
/* 160 */ if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
/* 161 */ return dm.interceptor.invoke(this);
/* */ }
/* */
/* 166 */ return proceed();
/* */ }
/* */
/* 172 */ return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
/* */ }
interceptorsAndDynamicMethodMatchers 就是xml配置的 intercpterNames 对应的拦截器列表。
你会发现如果是 实现 MethodInterceptor 接口的通知,就会直接调用该拦截器返回结果,并且不再继续执行后续操作。
调用逻辑分析如下:
首先在 JdkDynamicAopProxy 的 invoke 方法里获取拦截器链:
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
这个方法里对Advisor 进行封装, 调用 AdvisedSupport 类的方法
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.<span style="color:#ff0000;">getInterceptorsAndDynamicInterceptionAdvice</span>(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
调用的是 DefaultAdvisorChainFactory 类的方法,
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class targetClass) {
// This is somewhat tricky... we have to process introductions first,
// but we need to preserve order in the ultimate list.
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
registry.getInterceptors(advisor) 如下:DefaultAdvisorAdapterRegistry 类的方法:
DefaultAdvisorAdapterRegistry 类持有一个adapter 列表,适配器用来适配各种advice,有3中适配器
MethodBeforeAdviceAdapter;
AfterReturningAdviceAdapter;
ThrowsAdviceAdapter;
这个类的方法如下:
1. 如果是环切通知实现MethodInterceptor ,直接加入拦截器链;
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
2. 采用策略模式,针对一个advice,匹配到对应的adapter 适配器,适配器模式是基于接口的适配器,
adapter选择策略,这个策略将advice包装成一个SPI希望的接口 MethodInterceptor ,
适配器基于接口适配,比如 MethodBeforeAdviceInterceptor implements MethodInterceptor ,这个MethodBeforeAdviceInterceptor 持有现有的 Advice类,
调用 advice完成功能,这也就是适配器模式的本质。原本Advice的方法不符合 MethodInterceptor 接口要求,所以非常适合采用适配器模式。
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
private MethodBeforeAdvice advice;
/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
}
=========注意========
从上面代码最后一行看,如果是普通的Advice,比如前置advice,后置advice,或者异常advice,都会自动完成advice链的顺序执行。
但是对于环绕advice,因为实现 MethodInterceptor 接口,而直接放入拦截器链,Spring没有提供适配器,所以对于环绕Advice,
对于拦截器链的执行完全控制在开发者手里。
========end===========