欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Aop核心源码分析

程序员文章站 2022-06-08 18:53:55
...

提示:这里只对核心代码做讲解,如果你想彻底了解请打开你的编辑器定位到对应的源码上,一步一步跟着看相信你会有所收获的。

 

明词解释

 

链接点:在SpringAop中指的是方法.

 

目标对象:代理对象内部代理的那个对象,

 

目标方法:当前在目标对象上要执行的方法

 

通知:链接点执行前、后、异常情况下要执行的代码,SpringAop中有前置通知、后置通知、异常通知、环绕通知。

 

拦截器:将通知适配成MethodInteceptor后代理通知的执行。你可以把它理解为通知

 

 

Pointcut

    根据名字就知道它表示的是一个切入点。

Spring Aop核心源码分析
            
    
    博客分类: java Spring Aop源码分析Spring Aop 

 

 

             ClassFilter 匹配要切入的类

             MethodMatcher 匹配要切入的方法

以上三个接口中都有个属性TRUE表示自身接口的一个默认实现,均返回true。MethodMatcher.isRuntime方法除外,此方法表示是否需要在程序运行的时候动态决定是否切入某个方法。如(ControlFlowPointcut根据当前线程的堆栈信息来决定是否切入某方法的)

 

Advice

这个接口的实现类代表着你的通知(前置通知,后置通知,异常通知,环绕通知等)

 
Spring Aop核心源码分析
            
    
    博客分类: java Spring Aop源码分析Spring Aop 

Advisor

    这个接口表示一个切面,它持有Advice的引用,它的子接口PointcutAdvisor持有Pointcut的引用。你会不会这么觉得:这个接口的实现类会根据pointCut来决定是否调其advice执行相应的通知.(差不多是这样的,但不是它的实现类去做这个事,这个接口仅仅负责收集配置信息,做这件事的是AdvisedSupport类的getInterceptorsAndDynamicInterceptionAdvice方法,稍后会提)


Spring Aop核心源码分析
            
    
    博客分类: java Spring Aop源码分析Spring Aop 
 

Advised


Spring Aop核心源码分析
            
    
    博客分类: java Spring Aop源码分析Spring Aop 

 

这个接口支持多个Advisor或Advice、加入了需要代理的源对象(TargetSource)、需要代理的接口等(getProxiedInterfaces介个方法).这个接口的职责是将切面、目标对象、需要代理的接口组织起来。它的实现类是AdvisedSupport。

 

 

AdvisedSupport

 

    它实现了Advised接口。它可以动态添加,修改,删除通知和动态切换目标对象,即使代理对象已经创建。这个类有两个地方需要注意。

 

1、所有addAdvice方法的重载方法都会将参数Advice转成包装成Advisor并调用addAdvisor方法.

 

public void addAdvice(int pos, Advice advice) throws AopConfigException {
	Assert.notNull(advice, "Advice must not be null");
	if (advice instanceof IntroductionInfo) {
		//如果是一个引入通知,则将其包装成默认的实现引入切面
		addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
	}
	else if (advice instanceof DynamicIntroductionAdvice) {
		throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
	}
	else {
		//创建默认切面实现
		addAdvisor(pos, new DefaultPointcutAdvisor(advice));
	}
}
//对所有Advisor的变化操作都会调用此方法,清空拦截器链缓存.(请参看要注意的第二点)
protected void adviceChanged() {
	this.methodCache.clear();
}

 DefaultPointcutAdvisor的构造方法

public DefaultPointcutAdvisor(Advice advice) {
	this(Pointcut.TRUE, advice);
}

   它将设置一个TRUE的切入点。意味着它可以切入任何类的任何方法.

 

2、getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass)方法

 

  这个将会在目标类方法执行之前被调用,它返回匹配targetClasst和method的拦截器(其实就是通知【Advice】对象封装,利用Advisor的Pointcut属性去匹配适合的通知)

 

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
	//创建一个缓存key
	MethodCacheKey cacheKey = new MethodCacheKey(method);
	//从缓存中取出拦截器链
	List<Object> cached = this.methodCache.get(cacheKey);
	if (cached == null) {
	/*
	 * 缓存中不存在则调用DefaultAdvisorChainFactory工厂类的getInterceptorsAndDynamicInterceptionAdvice方法获取
	 */
		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
				this, method, targetClass);
		this.methodCache.put(cacheKey, cached);
	}
	return cached;
}

 

DefaultAdvisorChainFactory. getInterceptorsAndDynamicInterceptionAdvice方法

 

/**
 * 获取匹配targetClass与method的所有切面的通知
*/
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
		Advised config, Method method, Class targetClass) {
	List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
	boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
	//下面这个适配器将的通知【Advice】包装成方法拦截器【MethodInterceptor】。【DefaultAdvisorAdapterRegistry】适配器的默认实现.
	AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
	for (Advisor advisor : config.getAdvisors()) {
		if (advisor instanceof PointcutAdvisor) {
			PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
			//判断此切面【advisor】是否匹配targetClass
			if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
				//通过适配器将通知【Advice】包装成MethodInterceptor,这里为什么是个数组呢?因为一个通知类可能同时实现了前知通知【MethodBeforeAdvice】、后置通知【AfterReturningAdvice】、异常通知接口【ThrowsAdvice】,环绕通知【MethodInterceptor】,这里会将每个通知统一包装成MethodInterceptor
				MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
				MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
				//是否匹配targetClass类的method方法 
				if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
					if (mm.isRuntime()) {
						//如果是需要在运行时动态栏截方法的执行则创建一个简单的对象封装相关的数据,它将延时到方法执行的时候验证要不要执行此通知.
						for (MethodInterceptor interceptor : interceptors) {
							interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
						}
					}
					else {
						interceptorList.addAll(Arrays.asList(interceptors));
					}
				}
			}
		}
		else if (advisor instanceof IntroductionAdvisor) {
			//如果是引入切面的话则判断它是否适用于目标类,Spring中默认的引入切面实现是DefaultIntroductionAdvisor类,默认的引入通知是DelegatingIntroductionInterceptor它实现了MethodInterceptor接口
			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;
}

 

DefaultAdvisorAdapterRegistry适配器代码

 

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

	private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);


	/**
	 * 在构造器中把3种适配器写死了,你应该能猜出这是三种神马适配器吧
	 */
	public DefaultAdvisorAdapterRegistry() {
		registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
		registerAdvisorAdapter(new AfterReturningAdviceAdapter());
		registerAdvisorAdapter(new ThrowsAdviceAdapter());
	}

	/**
	 * 将Advice包装成Advisor
	 */
	public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
		if (adviceObject instanceof Advisor) {
			return (Advisor) adviceObject;
		}
		if (!(adviceObject instanceof Advice)) {
			throw new UnknownAdviceTypeException(adviceObject);
		}
		Advice advice = (Advice) adviceObject;
		if (advice instanceof MethodInterceptor) {
			return new DefaultPointcutAdvisor(advice);
		}
		for (AdvisorAdapter adapter : this.adapters) {
			if (adapter.supportsAdvice(advice)) {
				return new DefaultPointcutAdvisor(advice);
			}
		}
		throw new UnknownAdviceTypeException(advice);
	}
	/**
	 * 将Advisor中的Advice接口适配成MethodInteceptor接口
	 */
	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) {
			//当前适配器是不是支持此Advice的适配工作
			if (adapter.supportsAdvice(advice)) {
				//将Advice适配成MethodInterceptor
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		//将list转成数组返回.
		return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
	}

	public void registerAdvisorAdapter(AdvisorAdapter adapter) {
		this.adapters.add(adapter);
	}
}

 

ProxyCreatorSupport

 

     这个类继承自AdvisedSupport提供创建代理对象的支持类,默认情况下它是使用DefaultAopProxyFactory工厂类来创建代理的.它还有个功能就是在创建代理对象之前触发Listener.

protected final synchronized AopProxy createAopProxy() {
	if (!this.active) {
		//触发Listener.
		activate();
	}
	return getAopProxyFactory().createAopProxy(this);
}

 

DefaultAopProxyFactory

 

    它是创建Aop代理工厂的默认实现,它会自动判断是否使用jdk的动态代理还是使用cglib的动态代理。

//当前类路径是不是能找到cglib相关的类(可以理解成cglib的jar包有没有被放到类路径)
private static final boolean cglibAvailable =
			ClassUtils.isPresent("net.sf.cglib.proxy.Enhancer", DefaultAopProxyFactory.class.getClassLoader());

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	//启用了优化配置||启用了直接代理目标类模式||没有指定要代理的接口 则进入if.
	if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
		Class targetClass = config.getTargetClass();
		if (targetClass == null) {
			throw new AopConfigException("TargetSource cannot determine target class: " +
					"Either an interface or a target is required for proxy creation.");
		}
		if (targetClass.isInterface()) {
			return new JdkDynamicAopProxy(config);
		}
		if (!cglibAvailable) {
			throw new AopConfigException(
					"Cannot proxy target class because CGLIB2 is not available. " +
					"Add CGLIB to the class path or specify proxy interfaces.");
		}
		//返回创建cglib代理的工厂方法对象
		return CglibProxyFactory.createCglibProxy(config);
	}
	else {
		//返回创建jdk代理的工厂方法对象
		return new JdkDynamicAopProxy(config);
	}
}

 

 JdkDynamicAopProxy

 

    它是一个动态代理类,实现了java.lang.reflect.InvocationHandler接口,使用JDK自带的动态代理机制代理targetClass。它实现了AopProxy接口的getProxy方法来返回代理对象。

public Object getProxy() {
	return getProxy(ClassUtils.getDefaultClassLoader());
}
public Object getProxy(ClassLoader classLoader) {
	if (logger.isDebugEnabled()) {
		logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
	}
	//得到需要代理的所有接口,在默认情况下AopProxyUtils会把SpringProxy和Advised两个接口添加到后面。SpringProxy是一个标记接口,它仅仅标记当前对象是不是由Spring生成的一个代理;Advised接口则是为了使得代理类可以动态操作其AOP通知.默认情况下所有的代理对象均可以转换成Advised接口操作其代理对象内部的Advised对象.(这其实就是一个引入的实现,关于引入请参看后面关于引入的实现);这个要注意了,不然在后面InvocationHandler的invoke方法中第3个if会感觉慕名奇妙
	Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
	//查询这些接口中是否有eauals,hashCode的实现,以区别于代理对象的equals,hashCode方法
	findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
	return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

 

下面是代理类最核心的地方

 

//java.lang.reflect.InvocationHandler接口的实现
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	MethodInvocation invocation;
	Object oldProxy = null;
	boolean setProxyContext = false;
	//目标对象的包装类,通过AdvisedSupportr的setTarget方法设置的会被自动封闭成TargetSource的实现类SingletonTargetSource
	TargetSource targetSource = this.advised.targetSource;
	Class targetClass = null;
	Object target = null;
	try {
	//被代理的接口中没有定义equals方法且当前方法是equals方法,则调用equals方法比较两代理对象所代理的接口、切面、目标对象是不是相等的。
		if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
			return equals(args[0]);
		}
		//同上
		if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
			return hashCode();
		}
		//对Advised接口或子接口的中方法的调用不经过任何拦截器,直接委托给它内部维护Advised对象中的方法(此if块的目的是实现将advised对象引入代理对象),this.advised.opaque默认情况下是false(它只是一个开关选项,控制着代理对象是否可以操作advised.)
		if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
				method.getDeclaringClass().isAssignableFrom(Advised.class)) {
			//调用advised的method方法
			return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
		}
		Object retVal;
		//是否将当前的代理对象做一个AOP框架暴露
		if (this.advised.exposeProxy) {
			//把当前代理对象放入AopContext中(其内部使用ThreadLocal存着)并返回上下文中原来的代理对象,并且保留之前暴露设置的代理
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}
		//得到目标对象
		target = targetSource.getTarget();
		if (target != null) {
			targetClass = target.getClass();
		}
		//这个方法之前提到过,请上翻
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
		if (chain.isEmpty()) {
			//没有任何拦截器需要执行则直接执行目标对象的方法
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
		}
		else {
			//创建一个执行环境来处理拦截器和目标方法的执行(注意它的参数),这是一个递归的过程.后面再详细说明.
			invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			retVal = invocation.proceed();
		}
		//处理返回目标对象本身的情况.也许某些方法是返回this引用的,此时需要返回代理对象而不是目标对象.
		if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
				!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
			retVal = proxy;
		}
		return retVal;
	}
	finally {
		//也许你感觉finally中的代码不明白,那么可以看下介绍AdvisedSupport的红色字
		if (target != null && !targetSource.isStatic()) {
			//如果此targetSource不是一个静态的targetSource,那么释放此target,默认的SingletonTargetSource.isStatic方法是为true的
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
			//还原之前的代理对象
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

ReflectiveMethodInvocation的核心方法

public Object proceed() throws Throwable {
	//currentInterceptorIndex默认等于-1的,它记录着当前执行到了哪个栏截器
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		//如果所有的拦截器都执行完了的话,则调用invokeJoinpoint方法去执行目标对象的目标方法
		return invokeJoinpoint();
	}
	//得到当前要执行的拦截器(拦截器是顺序执行的发现木有=.=)
	Object interceptorOrInterceptionAdvice =
	    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	//下面判断当前拦截器是不是一个动态拦截器,之前有讲过 请上翻
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
		InterceptorAndDynamicMethodMatcher dm =
		    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
		//这里调用MethodMatcher类中带三个参数的matches方法
		if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
			//匹配目标类的目标方法后执行此拦截器
			return dm.interceptor.invoke(this);
		}
		else {
			//递归调用,下一个拦截器或目标类的方法.
			return proceed();
		}
	}
else {
		//调用拦截器的invoke方法并将this传递过去,这样拦截器里中的代码就有了是否继续执行的权限
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

 引入

    IntroductionAdvisor接口是引入切面的基本接口,它的默认实现是DefaultIntroductionAdvisor类,默认的引入通知是DelegatingIntroductionInterceptor它实现了MethodInterceptor接口。可以这样理解:spring其实就是通过一个特殊的MethodInteceptor来实现引入的。下面直接看这个拦截器的核心代码.

 

//delegate这个对象的方法将会引入到目标对象中,spring中只能进行接口的引入,这意味着delegate或其超类必需实现至少一个接口,在对目标类执行这些接口中的方法的时候spring会将其委托给delegate去执行,这样看上去就像是将一个类的方法(接口中的方法)动态赋予给目标类一样。
private Object delegate;
public Object invoke(MethodInvocation mi) throws Throwable {
	//如果mi中执行的方法是delegate对象实现的接口中的方法
	if (isMethodOnIntroducedInterface(mi)) {
		//将此方法的执行委托给delegate对象.
		Object retVal = AopUtils.invokeJoinpointUsingReflection(this.delegate, mi.getMethod(), mi.getArguments());
		//处理返回this的情况
		if (retVal == this.delegate && mi instanceof ProxyMethodInvocation) {
			Object proxy = ((ProxyMethodInvocation) mi).getProxy();
			if (mi.getMethod().getReturnType().isInstance(proxy)) {
				retVal = proxy;
			}
		}
		return retVal;
	}
	//执行目标方法
	return doProceed(mi);
}

 

举例Spring基于ProxyCreatorSupport做了一些扩展

1、ProxyFactory继承自ProxyCreatorSupport简化了aop的配置.例:

DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();//创建一个默认的切面实现 
advisor.setAdvice(myBeforeAdvice);//配置通知
advisor.setPointcut(myPointcut);//配置切入点

ProxyFactory proxyFactory=new ProxyFactory();
//ProxyFactory proxyFactory=new ProxyFactory(target);//这样的话就它会自动将target对象所有实现的接口都代理
proxyFactory.addAdvisor(advisor);
proxyFactory.addAdvice(null/*自定义的拦截器*/);//添加更多的通知,内部会将它封装成Advisor.
proxyFactory.setTarget(target);
proxyFactory.setInterfaces(target.getClass().getInterfaces());//指定要代理的接口,如果使用new ProxyFactory(target);创建ProxyFactory的话这句可以省略
Target targetProxy=(Target)proxyFactory.getProxy();//创建并获取代理对象
targetProxy.method();

 2、ProxyFactoryBean继承自ProxyCreatorSupport实现了FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware接口

<bean class="org.springframework.aop.framework.ProxyFactoryBean">
	 <property name="interceptorNames">interceptor*</property>
	 <property name="target" ref="targetObject" />
</bean>

 3、TransactionProxyFactoryBean事务代理工厂Bean它依赖于ProxyFactoryBean创建代理,并添加了处理事务开关的TransactionInterceptor拦截器.

<bean class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
	<property name="target" ref="targetObject"></property>
	<property name="transactionManager" ref="transactionManager"></property>
 	<property name="transactionAttributes">
 		<props>
 			<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
			<prop key="*">PROPAGATION_REQUIRED</prop>
		</props>
 	</property>
 </bean>

  4、BeanNameAutoProxyCreator

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
 	<property name="beanNames">
 		<value>user*,authenticateService</value>
 	</property>
 	<property name="interceptorNames">
 		<value>loggerInterceptor,interceptor*</value>
 	</property>
 </bean>

  

  • Spring Aop核心源码分析
            
    
    博客分类: java Spring Aop源码分析Spring Aop 
  • 大小: 37.4 KB
  • Spring Aop核心源码分析
            
    
    博客分类: java Spring Aop源码分析Spring Aop 
  • 大小: 11.4 KB
  • Spring Aop核心源码分析
            
    
    博客分类: java Spring Aop源码分析Spring Aop 
  • 大小: 8.3 KB
  • Spring Aop核心源码分析
            
    
    博客分类: java Spring Aop源码分析Spring Aop 
  • 大小: 17.7 KB