Spring(二十):ObjenesisCglibAopProxy

回顾

上一章仔细分析了Spring对于JDK代理的代理类的invoke方法,也填下了之前没有接触AOP导致循环依赖未彻底弄明白的坑,下面就认识一下Spring对于Cglib代理是如何实现的

ObjenesisCglibAopProxy

在这里插入图片描述
仍然都是由ObjenesisCglobAopProxy创建的

在这里插入图片描述
可以看到其构建方法仅仅只是初始化了父类而已

拓展:这里拓展一下之前是如何使用Cglib代理的,之前也提到过,对于JDK代理和Cglib代理的最基本的区别,就是JDK代理的是接口,而Cglib代理的是类

这里也提一下Cglib的实现原理,Cglib代理其实是通过对指定的类生成一个子类,覆盖其中的方法来实现的,生成的子类的类名称是指定的类名$ E n h a n c e r Enhancer Enhancer $,说白了,代理对象其实是目标对象的子类,因此我们使用Cglib代理的时候,不能将类声明为final,不然会出错的

使用步骤如下

  1. 创建代理类,代理类实现MethodInterceptor方法,重写intercept方法

  2. 创建Enhancer实例,用于根据被代理类和代理类来生成代理实例

    • setSuperClass:注入被代理的类

    • setCallBack:注入代理实例

    • create:生成完整的代理对象

  3. 使用完整的代理对象来执行被代理的类的方法,此时方法就会被代理实例给拦截到了

下面就来看看Spring是如何创建的,我们从获取切面的方法入手,也就是getProxy

在这里插入图片描述

可以看到,对于getProxy的实现,是交由CglibAopProxy来完成的

源码如下

public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
		}

		try {
            //获取被代理对象的目标Class(之前在构造方法上成功注入)
			Class<?> rootClass = this.advised.getTargetClass();
			Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
			//创建另外一个变量存放目标class
			Class<?> proxySuperClass = rootClass;
            //判断目标class的名字是不是包含$$的字样
            //包含这两个字符就比较特殊了,代表其就是一个代理对象
            //此时就要代理的对象是一个代理对象
			if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
                //此时目标就应该为父类class了,也就是目标对象的被代理对象
                //相当于找到了最初的被代理对象,让目标对象变成最初的被代理对象
				proxySuperClass = rootClass.getSuperclass();
                //获取此时被代理的代理对象的接口
				Class<?>[] additionalInterfaces = rootClass.getInterfaces();
				for (Class<?> additionalInterface : additionalInterfaces) {
                    //遍历接口添加进增强器里面
					this.advised.addInterface(additionalInterface);
				}
			}

			// Validate the class, writing log messages as necessary.
            //校验,并输出日志(不重要)
			validateClassIfNecessary(proxySuperClass, classLoader);

			// Configure CGLIB Enhancer...
            //接下来就是Cglib创建代理的步骤啦
            //创建Enhancer(Enhancer就是用来根据代理实例来增强被代理类的)
			Enhancer enhancer = createEnhancer();
			if (classLoader != null) {
				enhancer.setClassLoader(classLoader);
				if (classLoader instanceof SmartClassLoader &&
						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
					enhancer.setUseCache(false);
				}
			}
            //设置被代理类,可以看到这里使用的是proxySuperClass(如果是代理对象,那么proxySuperClass会为父类)
			enhancer.setSuperclass(proxySuperClass);
            //通常配置
			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
			//设置拦截器
			Callback[] callbacks = getCallbacks(rootClass);
            //获取拦截器的所有类型
            //用于注入进enhancer
			Class<?>[] types = new Class<?>[callbacks.length];
			for (int x = 0; x < types.length; x++) {
				types[x] = callbacks[x].getClass();
			}
			// 给enhancer注入拦截器链
			enhancer.setCallbackFilter(new ProxyCallbackFilter(
					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            //注入callBack的类型,callBack就是拦截器
			enhancer.setCallbackTypes(types);
            //使用enhancer生成代理对象
			return createProxyClassAndInstance(enhancer, callbacks);
		}
		catch (CodeGenerationException | IllegalArgumentException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (Throwable ex) {
			// TargetSource.getTarget() failed
			throw new AopConfigException("Unexpected AOP exception", ex);
		}
	}
  • 获取被代理的目标对象
  • 获取proxySupperClass,proxySupperClass,其实是真正的目标对象,为什么是真正呢?
    • 判断要被代理的目标对象有没有$ $这两个关键字,这两个关键字,出现这两个关键字就相当于被代理的目标对象已经是一个代理对象了,一般Cglib的代理Class的name是类名 E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIB
    • 如果目标对象是一个Cglib代理对象,获取其父类,将父类的所有接口都添加进拦截器链中
  • 校验操作
  • 创建Enhancer
  • 注入属性进去Enhancer,比如代理对象的类型、策略、拦截器集合、拦截器集合对应的类型集合
  • 最终使用Enhancer创建代理对象

拦截器链如何形成

对应的方法就是getCallbacks方法

在这里插入图片描述

该方法源码如下

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
		// Parameters used for optimization choices...
    	//判断是不是要进行曝光
		boolean exposeProxy = this.advised.isExposeProxy();
		boolean isFrozen = this.advised.isFrozen();
		boolean isStatic = this.advised.getTargetSource().isStatic();

		// 使用advised创建DynamicAdvisedInterceptor,里面就是前面定义的拦截器了
    	//要记住此时advised里面拥有着被代理Bean的信息,和所有的拦截器
		Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

		// Choose a "straight to target" interceptor. (used for calls that are
		// unadvised but can return this). May be required to expose the proxy.
		Callback targetInterceptor;
    	//判断是否要曝光
    	//根据是否要曝光并且是动态代理还是静态代理去生成拦截器
    	//这里的targetInterceptor拦截器称为目标拦截器
    	//这个拦截器的作用实质上没有对方法进行增强,但里面的额外操作会将当前代理对象切面曝光出来
    	//Cglib还支持静态代理咧。。。
		if (exposeProxy) {
            //如果要曝光,对应要创建exposedInterceptor
            //并且从创建方法可以看到,直接给了目标对象,并没有给增强器
            //在这里exposedInterceptor是会对代理对象进行曝光的
			targetInterceptor = (isStatic ?
					new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
					new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
		}
		else {
            //如果不需要曝光,创建unadvvisedInterceptor,从名字就可以看出,是一个没有增强器的拦截器
            //但其实还会对返回值做一些处理
			targetInterceptor = (isStatic ?
					new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
					new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
		}

		// Choose a "direct to target" dispatcher (used for
		// unadvised calls to static targets that cannot return this).
    	// 创建targetDispatcher,这个跟unadvisedInterceptor的作用其实差不多
    	// 直接执行目标对象的方法,本质上没有做其他任何其他增强操作,不过可能会对返回值做一些处理
		Callback targetDispatcher = (isStatic ?
				new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());

    	//组装所有的拦截器
		Callback[] mainCallbacks = new Callback[] {
            	//第一位是我们定义的那些AOP拦截
				aopInterceptor,  // for normal advice
            	//第二位是targetInterceptor,也就是是否曝光的拦截器
				targetInterceptor,  // invoke target without considering advice, if optimized
            	//第三位是真的什么都不增强,只去执行目标对象的方法
            	//这个SerializableNoOp其实本是上就是cglib的NoOp
				new SerializableNoOp(),  // no override for methods mapped to this
            	//第四位是targetDispatcher
				targetDispatcher, this.advisedDispatcher,
            	//第五位是equal方法的拦截器
				new EqualsInterceptor(this.advised),
            	//第六位是hashCode方法的拦截器
				new HashCodeInterceptor(this.advised)
		};
		
		Callback[] callbacks;

		// If the target is a static one and the advice chain is frozen,
		// then we can make some optimizations by sending the AOP calls
		// direct to the target using the fixed chain for that method.
    	//如果目标对象是静态的或者拦截器链是冻结的
    	//这里会做一些修复措施
		if (isStatic && isFrozen) {
            //获取代理对象类型的所有方法
			Method[] methods = rootClass.getMethods();
			Callback[] fixedCallbacks = new Callback[methods.length];
			this.fixedInterceptorMap = CollectionUtils.newHashMap(methods.length);

			// TODO: small memory optimization here (can skip creation for methods with no advice)
            //遍历目标对象类型的所有方法
			for (int x = 0; x < methods.length; x++) {
                //当前的方法
				Method method = methods[x];
                //获取目标当前的方法需要执行的拦截器链,每个方法要进行的拦截器链都不一样
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
                //封装成FixedChainStaticTargetInterceptor存放进fixedCallBacks中
				fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
						chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
				this.fixedInterceptorMap.put(method, x);
			}

			// Now copy both the callbacks from mainCallbacks
			// and fixedCallbacks into the callbacks array.
            //将三个callBacks都集合起来
			callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
			System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
			System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
			this.fixedInterceptorOffset = mainCallbacks.length;
		}
		else {
			callbacks = mainCallbacks;
		}
    //最终返回整个callbacks
		return callbacks;
	}

可以看到,这里的拦截器链形成不单单只针对我们设置的AOP的拦截器链,还有额外的一些提前曝光的拦截器链

  • aopInterceptor
  • targetInterceptor
  • SerialbleNoOp
  • targetDispatcher

而决定适用哪些拦截器链的由传进给Enhancer的ProxyCallbackFilter来进行

自定义拦截

在这里插入图片描述
从代码上可以看到,对于拦截器链,是CglibAopProxy里面的一个ProxyCallBackFilter,该内部类实现了CallbackFilter接口(Cglib的接口),那么对应的肯定会实现accept方法,先来说一下这个CallbackFilter的作用,顾名思义它是一个过滤接口,用来过滤回调的方法的,说白了,accept方法可以给方法自定义要执行的增强器,即哪些方法执行对应的增强器,该方法返回的是一个整形,该返回值对应的就是注入进Enhancer里面的拦截器集合(setCallbaks方法,该方法在最终使用Enhancer创建代理对象时调用)的索引值,根据这个索引值去找到拦截器

该方法的源码如下

public int accept(Method method) {
    		//判断当前方法是不是final类型
    		//如果是final类型,代表不能重写
			if (AopUtils.isFinalizeMethod(method)) {
				logger.trace("Found finalize() method - using NO_OVERRIDE");
                //返回2
				return NO_OVERRIDE;
			}
    		//如果方法是来自于接口的,并且实现的Class是一个Advise
    		//那就说明
			if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				if (logger.isTraceEnabled()) {
					logger.trace("Method is declared on Advised interface: " + method);
				}
				return DISPATCH_ADVISED;
			}
			// We must always proxy equals, to direct calls to this.
    		//如果执行equals方法,适用Equals方法的拦截器
			if (AopUtils.isEqualsMethod(method)) {
				if (logger.isTraceEnabled()) {
					logger.trace("Found 'equals' method: " + method);
				}
				return INVOKE_EQUALS;
			}
    		//如果适用HashCode,同样适用HashCode的拦截器
			// We must always calculate hashCode based on the proxy.
			if (AopUtils.isHashCodeMethod(method)) {
				if (logger.isTraceEnabled()) {
					logger.trace("Found 'hashCode' method: " + method);
				}
				return INVOKE_HASHCODE;
			}
			Class<?> targetClass = this.advised.getTargetClass();
			// Proxy is not yet available, but that shouldn't matter.
    		//获取拦截器链
			List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
			boolean haveAdvice = !chain.isEmpty();
			boolean exposeProxy = this.advised.isExposeProxy();
			boolean isStatic = this.advised.getTargetSource().isStatic();
			boolean isFrozen = this.advised.isFrozen();
    		//如果拥有拦截器链
			if (haveAdvice || !isFrozen) {
				// If exposing the proxy, then AOP_PROXY must be used.
                //并且代理对象会被曝光
				if (exposeProxy) {
					if (logger.isTraceEnabled()) {
						logger.trace("Must expose proxy on advised method: " + method);
					}
                    //适用AOP的拦截器链
					return AOP_PROXY;
				}
				// Check to see if we have fixed interceptor to serve this method.
				// Else use the AOP_PROXY.
				if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(method)) {
					if (logger.isTraceEnabled()) {
						logger.trace("Method has advice and optimizations are enabled: " + method);
					}
					// We know that we are optimizing so we can use the FixedStaticChainInterceptors.
					int index = this.fixedInterceptorMap.get(method);
					return (index + this.fixedInterceptorOffset);
				}
				else {
					if (logger.isTraceEnabled()) {
						logger.trace("Unable to apply any optimizations to advised method: " + method);
					}
                    //适用AOP的拦截器链
					return AOP_PROXY;
				}
			}
			else {
				// See if the return type of the method is outside the class hierarchy of the target type.
				// If so we know it never needs to have return type massage and can use a dispatcher.
				// If the proxy is being exposed, then must use the interceptor the correct one is already
				// configured. If the target is not static, then we cannot use a dispatcher because the
				// target needs to be explicitly released after the invocation.
				//如果AOP拦截器链是空的,使用targetIntercetor,不进行增强了执行目标对象的方法
                if (exposeProxy || !isStatic) {
					return INVOKE_TARGET;
				}
				Class<?> returnType = method.getReturnType();
				if (targetClass != null && returnType.isAssignableFrom(targetClass)) {
					if (logger.isTraceEnabled()) {
						logger.trace("Method return type is assignable from target type and " +
								"may therefore return 'this' - using INVOKE_TARGET: " + method);
					}
					return INVOKE_TARGET;
				}
				else {
					if (logger.isTraceEnabled()) {
						logger.trace("Method return type ensures 'this' cannot be returned - " +
								"using DISPATCH_TARGET: " + method);
					}
					return DISPATCH_TARGET;
				}
			}
		}

从代码上可以看到,会根据当前执行的方法来进行区分使用哪个拦截器

  • 只有当不是equals、hashCode方法,并且方法的实现不来自于一个Advised里面,并且拦截器链不为空,才会去执行AOP的拦截器链,也就是执行我们自定义的AOP拦截器

下面时对应的createProxyClassAndInstance方法,可以看到,只是最终给enhancer注入了组装好的callBacks后,判断要不要进行输入参数来进行创建代理对象而已
![在这里插入图片描述](https://img-### 如何执行拦截器链

现在我们已经知道了对于AOP拦截器链是被封装成一个DynamicAdvisedInterceptor的,那么就来看看是如何进行执行的
在这里插入图片描述

可以看到,DynamicAdvisedInterceptor是一个实现了MethodInterceptor的,代表了这是一个Cglib代理对象,并且会去执行intercept方法

该方法源码如下

@Override
		@Nullable
		public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object oldProxy = null;
			boolean setProxyContext = false;
			Object target = null;
            //获取目标代理对象
			TargetSource targetSource = this.advised.getTargetSource();
			try {
                //判断需不需要进行暴露
				if (this.advised.exposeProxy) {
					// Make invocation available if necessary.
                    //将当前的代理对象暴露,并且保留旧的代理对象
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}
				// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
				target = targetSource.getTarget();
				Class<?> targetClass = (target != null ? target.getClass() : null);
                //获取拦截器链
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
				Object retVal;
				//判断拦截器链是否为空
				if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
					//如果拦截器链为空,直接执行目标对象的方法
					Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
					retVal = methodProxy.invoke(target, argsToUse);
				}
				else {
					// We need to create a method invocation...
                    //否则的话交由CglibMethodInvocatin来执行
                   	//是不是跟JDK代理很相像,JDK是交由ReflectiveMethodInvocation执行的
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
                //处理返回值
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null && !targetSource.isStatic()) {
					targetSource.releaseTarget(target);
				}
                //如果代理对象被提前曝光了,执行完所有的操作之后要将曝光的代理对象还原
				if (setProxyContext) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

可以看到,执行拦截器链的逻辑跟JDK代理的几乎一致

  • 判断需不需要进行曝光AOP代理对象
  • 获取拦截器链
    • 如果拦截器链为空,直接执行目标对象的方法
    • 如果拦截器链不为空,交由CglibMethodInvocation去执行拦截器链
  • 最终将之前曝光的AOP代理对象进行还原

CglibMethodInvocation

这个对象是用来执行AOP拦截器链的

在这里插入图片描述
可以看到这个CglibMethodInvocation继承了ReflectiveMethodInvocation

对应的proceed方法源码如下

public Object proceed() throws Throwable {
   try {
       //调用了ReflectiveMethodInvocation的proceed方法
      return super.proceed();
   }
   catch (RuntimeException ex) {
      throw ex;
   }
   catch (Exception ex) {
      if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||
            KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {
         // Propagate original exception if declared on the target method
         // (with callers expecting it). Always propagate it for Kotlin code
         // since checked exceptions do not have to be explicitly declared there.
         throw ex;
      }
      else {
         // Checked exception thrown in the interceptor but not declared on the
         // target method signature -> apply an UndeclaredThrowableException,
         // aligned with standard JDK dynamic proxy behavior.
         throw new UndeclaredThrowableException(ex);
      }
   }
}

可以看到,CglobMethodInvocation的proceed方法直接调用了ReflectiveMethodInvocation的,因此本质作用跟ReflectiveMethodInvocation基本一致

到此,Cglib代理也讲完了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值