Spring AOP 理解

本文深入探讨了Spring AOP的实现原理,包括核心组件ProxyFactoryBean的作用、JdkDynamicAopProxy的工作流程以及如何通过配置创建AOP代理。同时,详细分析了AOP中的通知类型、拦截器链的构建过程及MethodInterceptor接口的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


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===========

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值