Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >AOP详解之三-创建AOP代理后记,创建AOP代理

AOP详解之三-创建AOP代理后记,创建AOP代理

原创
作者头像
程序员田同学
发布于 2022-03-24 02:21:18
发布于 2022-03-24 02:21:18
4860
举报
文章被收录于专栏:java-springjava-spring

AOP详解之三-创建AOP代理后记,创建AOP代理。

上篇文章已经获取到了AOP的信息,接下来就是拿着这些AOP的信息去创建代理了。

首先我们看下创建AOP代理的入口处。

代码语言:txt
AI代码解释
复制
//这个方法将返回代理类
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		// 1.判断当前bean是否在targetSourcedBeans缓存中存在(已经处理过),如果存在,则直接返回当前bean
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		// 2.在advisedBeans缓存中存在,并且value为false,则代表无需处理
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		// 3.bean的类是aop基础设施类 || bean应该跳过,则标记为无需处理,并返回
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		// 4.获取当前bean的Advices和Advisors
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		// 5.如果存在增强器则创建代理
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 创建代理...创建代理...创建代理...
			// 5.1 创建代理对象:这边SingletonTargetSource的target属性存放的就是我们原来的bean实例(也就是被代理对象),
			// 用于最后增加逻辑执行完毕后,通过反射执行我们真正的方法时使用(method.invoke(bean, args))
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			// 5.2 创建完代理后,将cacheKey -> 代理类的class放到缓存
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}
		// 6.标记为无需处理
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

在5.1的位置开始创建代理对象,我们从此开始深入创建AOP代理的源码。

代码语言:txt
AI代码解释
复制
// 注意看这个方法的几个参数,
	//   第三个参数携带了所有的 advisors
	//   第四个参数 targetSource 携带了真实实现的信息
	protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		// 创建 ProxyFactory 实例
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		// 检查proxyTargetClass属性,判断对于给定的bean使用类代理还是接口代理,
		// proxyTargetClass值默认为false,可以通过proxy-target-class属性设置为true
		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		// 获取Advisor顾问对象
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		// 2.使用proxyFactory获取代理
		return proxyFactory.getProxy(getProxyClassLoader());
	}

在2位置拿着我们new的代理工厂获取我们的代理对象。

代码语言:txt
AI代码解释
复制
	public Object getProxy(@Nullable ClassLoader classLoader) {
		// 1.createAopProxy:创建AopProxy
		// 2.getProxy(classLoader):获取代理对象实例
		return createAopProxy().getProxy(classLoader);
	}

第一步是获取AOP的代理对象

代码语言:txt
AI代码解释
复制
/**
	 * 创建AOP对象的真正实例
	 * @param config the AOP configuration in the form of an
	 * AdvisedSupport object
	 * @return
	 * @throws AopConfigException
	 */
	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		// 1.判断使用JDK动态代理还是Cglib代理
		// optimize:用于控制通过cglib创建的代理是否使用激进的优化策略。除非完全了解AOP如何处理代理优化,
		// 否则不推荐使用这个配置,目前这个属性仅用于cglib代理,对jdk动态代理无效
		// proxyTargetClass:默认为false,设置为true时,强制使用cglib代理,设置方式:<aop:aspectj-autoproxy proxy-target-class="true" />
		// hasNoUserSuppliedProxyInterfaces:config是否存在代理接口或者只有SpringProxy一个接口
		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.");
			}
			// 要被代理的对象是接口 || targetClass是Proxy class
			// 当且仅当使用getProxyClass方法或newProxyInstance方法动态生成指定的类作为代理类时,才返回true。
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				// JDK动态代理,这边的入参config(AdvisedSupport)实际上是ProxyFactory对象
				// 具体为:AbstractAutoProxyCreator中的proxyFactory.getProxy发起的调用,在ProxyCreatorSupport使用了this作为参数,
				// 调用了的本方法,这边的this就是发起调用的proxyFactory对象,而proxyFactory对象中包含了要执行的的拦截器

				return new JdkDynamicAopProxy(config);
			}
			// Cglib代理
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			// JDK动态代理
			return new JdkDynamicAopProxy(config);
		}
	}

第二步是获取真实的对象

我们接着看getProxy这个方法,该方法有两个实现类。

image-20220324091153589
image-20220324091153589

我们实现类也就是我们常说的实现AOP的两种方式,使用cglib和jdk动态代理的方式。

我们简要的介绍一下这两种aop的原理。

动态代理步骤:

1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法

2.创建被代理的类以及接口

3.通过Proxy的静态方法

newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理

4.通过代理调用invoke方法

我们分别看下这两种实现方式。

JDK的方式

代码语言:txt
AI代码解释
复制
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isTraceEnabled()) {
      logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
   }
   // 1.拿到要被代理对象的所有接口
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   // 2.通过classLoader、接口、InvocationHandler实现类,来获取到代理对象
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

getproxy这个方法已经创建了代理对象,接下来就要执行实现类的invoke方法了。

显而易见,我们这上一步将环绕通知都已经包装好了,这一步代理对象也已经创建好了,接下来肯定就是要处理我们环绕通知里面的方法了。

代码语言:txt
AI代码解释
复制
//当我们调用了被 AOP 代理的方法时,使用 JDK 动态代理会走到 JdkDynamicAopProxy#invoke 方法
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;

   // 1.advised就是proxyFactory,而targetSource持有被代理对象的引用
   TargetSource targetSource = this.advised.targetSource;
   Object target = null;

   try {
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
         // The target does not implement the equals(Object) method itself.
         // 目标不实现equals(Object)方法本身。
         return equals(args[0]);
      }
      else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
         // The target does not implement the hashCode() method itself.
         return hashCode();
      }
      else if (method.getDeclaringClass() == DecoratingProxy.class) {
         // There is only getDecoratedClass() declared -> dispatch to proxy config.
         // 只有getDecoratedClass()声明 - > dispatch到代理配置。
         return AopProxyUtils.ultimateTargetClass(this.advised);
      }
      else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
            method.getDeclaringClass().isAssignableFrom(Advised.class)) {
         // Service invocations on ProxyConfig with the proxy config...
         // ProxyConfig上的服务调用与代理配置..
         return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      }

      Object retVal;

      // 有时候目标对象内部的自我调用将无法实施切面中的增强则需要通过此属性暴露代理
      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.
      // 2.拿到我们被代理的对象实例
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);

      // Get the interception chain for this method.
      // 3.获取拦截器链:例如使用@Around注解时会找到AspectJAroundAdvice,还有ExposeInvocationInterceptor
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      // Check whether we have any advice. If we don't, we can fallback on direct
      // reflective invocation of the target, and avoid creating a MethodInvocation.
      // 4.检查我们是否有任何拦截器(advice)。 如果没有,直接反射调用目标,并避免创建MethodInvocation。
      if (chain.isEmpty()) {
         // We can skip creating a MethodInvocation: just invoke the target directly
         // Note that the final invoker must be an InvokerInterceptor so we know it does
         // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
         // 5.不存在拦截器链,则直接进行反射调用
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         // We need to create a method invocation...
         // 6.如果存在拦截器,则创建一个ReflectiveMethodInvocation:代理对象、被代理对象、方法、参数、
         // 被代理对象的Class、拦截器链作为参数创建ReflectiveMethodInvocation
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
         // 7.触发ReflectiveMethodInvocation的执行方法
         retVal = invocation.proceed();
      }

      // Massage return value if necessary.
      // 8.必要时转换返回值
      Class<?> returnType = method.getReturnType();
      if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
         // Special case: it returned "this" and the return type of the method
         // is type-compatible. Note that we can't help if the target sets
         // a reference to itself in another returned object.
         retVal = proxy;
      }
      else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
         throw new AopInvocationException(
               "Null return value from advice does not match primitive return type for: " + method);
      }
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         // Must have come from TargetSource.
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

cglib方式

代码语言:txt
AI代码解释
复制
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isTraceEnabled()) {
      logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
   }

   try {
      // 1.拿到要代理目标类
      Class<?> rootClass = this.advised.getTargetClass();
      Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

      Class<?> proxySuperClass = rootClass;
      if (ClassUtils.isCglibProxyClass(rootClass)) {
         proxySuperClass = rootClass.getSuperclass();
         Class<?>[] additionalInterfaces = rootClass.getInterfaces();
         for (Class<?> additionalInterface : additionalInterfaces) {
            // 将父类的接口也添加到advised的interfaces属性
            this.advised.addInterface(additionalInterface);
         }
      }

      // Validate the class, writing log messages as necessary.
      // 2.校验proxySuperClass,主要是校验方法是否用final修饰、跨ClassLoader的包可见方法,如果有将警告写入日志
      validateClassIfNecessary(proxySuperClass, classLoader);

      // Configure CGLIB Enhancer...
      // 3.创建和配置Cglib Enhancer
      Enhancer enhancer = createEnhancer();
      if (classLoader != null) {
         enhancer.setClassLoader(classLoader);
         if (classLoader instanceof SmartClassLoader &&
               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
         }
      }
      // superclass为被代理的目标类proxySuperClass,通过名字可以看出,生成的代理类实际上是继承了被代理类
      enhancer.setSuperclass(proxySuperClass);
      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

      // 4.获取所有要回调的拦截器
      Callback[] callbacks = getCallbacks(rootClass);
      Class<?>[] types = new Class<?>[callbacks.length];
      for (int x = 0; x < types.length; x++) {
         types[x] = callbacks[x].getClass();
      }
      // fixedInterceptorMap only populated at this point, after getCallbacks call above
      // 在上面调用getCallbacks之后,此时仅填充fixedInterceptorMap
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);

      // Generate the proxy class and create a proxy instance.
      // 5.生成代理类并创建代理实例,返回代理实例
      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);
   }
}

总结一下AOP的整个流程,在Spring的核心方法refresh()中,创建单例对象前会执行InstantiationAwareBeanPostProcessor 方法的实现类,类似于Spring的前置处理器。

在实现类中会先将环绕通知包装好,后执行创建代理方法,执行前判断是jdk动态代理还是cglib,在jdk动态代理中,处理我们的环绕通知,以执行切面方法时进行执行。

历时三个月将Spring的IOC和AOP的源码解读就结束了,如果读者想完整的熟悉整个流程,可以看历史文章一步步的揭开Spring的神秘面纱。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring AOP 创建代理的源码解析
在上篇文章 Spring AOP 注解方式源码解析 中已经获取到了 bean 的对应增强器,之后,就可以创建对应的代理了,Spring AOP 底层使用的是 JDK 动态代理和 CGLIB 的代理,在什么情况下使用JDK动态代理,什么时候使用 CGLIB 代理呢,下面通过源码来看一下.
Java技术编程
2020/05/20
1.2K0
Spring AOP源码学习:创建 AOP 代理
Spring AOP源码学习:创建 AOP 代理
Java架构师必看
2021/06/17
9170
spring源码篇(七)AOP原理
spring是如何实现AOP切面的,从原理上来说是动态代理,那么怎样去实现这个动态代理呢就是本篇的内容。
用针戳左手中指指头
2021/09/10
4720
最简 Spring AOP 源码分析
最近在研究 Spring 源码,Spring 最核心的功能就是 IOC 容器和 AOP。本文定位是以最简的方式,分析 Spring AOP 源码。
Yano_nankai
2019/09/24
2.1K0
最简 Spring AOP 源码分析
Spring的AOP底层解析
            基于两种动态代理技术,在Spring中进行了封装,封装出来的类叫做ProxyFactory,表示是创建代理对象的一个工厂,使用起来会更加方便。
忧愁的chafry
2022/10/30
5290
Spring的AOP底层解析
Spring Aop之Cglib实现原理详解
Spring Aop实现对目标对象的代理,主要有两种方式:Jdk代理和Cglib代理。这两种代理的区别在于,Jdk代理与目标类都会实现同一个接口,并且在代理类中会调用目标类中被代理的方法,调用者实际调用的则是代理类的方法,通过这种方式我们就可以在代理类中织入切面逻辑;Jdk代理存在的问题在于目标类被代理的方法必须实现某个接口,Cglib代理则是为了解决这个问题而存在的,其实现代理的方式是通过为目标类动态生成一个子类,通过在子类中织入相应逻辑来达到织入代理逻辑的目的。
田维常
2019/07/16
7700
深入理解Spring框架之AOP实现原理
该动态代理是基于接口的动态代理,所以并没有一个原始方法的调用过程,整个方法都是被拦截的。
JavaQ
2019/05/15
2.2K0
深入理解Spring框架之AOP实现原理
Spring事务是如何应用到你的业务场景中的?
日常开发中经常用到@Transaction注解,那你知道它是怎么应用到你的业务代码中的吗?本篇文章将从以下两个方面阐述Spring事务实现原理:
AI乔治
2020/09/14
6280
Spring事务是如何应用到你的业务场景中的?
(六)Spring源码解析:Spring AOP源码解析
当我们对某些类有横切性的逻辑时,为了不破坏目标类,我们则可以使用AOP的方式将增强逻辑注入到目标类上。为了更清晰的了解AOP的用法,下面我们通过一个使用案例,实现一下面向切面编程。
爪哇缪斯
2023/09/06
8920
(六)Spring源码解析:Spring AOP源码解析
Spring事务原理详解
spring事务开启和使用比较简单,需要有数据源和事务管理器,然后在启动门面类上开启事务,在需要使用事务的地方添加注解就可以了,我们简单做一下回顾。
叔牙
2022/01/04
7143
Spring事务原理详解
Spring异步编程
在很多场景中,业务操作完成后会完成一些收尾操作,并不希望实时等待其实时返回结果,甚至不关心执行成功与否,比如:
叔牙
2021/04/26
1.9K0
玩一玩编程式 AOP
平时我们项目中涉及到 AOP,基本上就是声明式配置一下就行了,无论是基于 XML 的配置还是基于 Java 代码的配置,都是简单配置即可使用。声明式配置有一个好处就是对源代码的侵入小甚至是零侵入。不过今天松哥要和小伙伴们聊一聊编程式的 AOP,为什么要聊这个话题呢?因为在 Spring 源码中,底层就是通过这种方式创建代理对象的,所以如果自己会通过编程式的方式进行 AOP 开发,那么在看 Spring 中相关源码的时候,就会很好理解了。
江南一点雨
2023/09/09
1730
玩一玩编程式 AOP
Spring AOP 源码分析 - 创建代理对象
在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的。现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 bean 的某些方法前后。与筛选合适的通知器相比,创建代理对象的过程则要简单不少,本文所分析的源码不过100行,相对比较简单。在接下里的章节中,我将会首先向大家介绍一些背景知识,然后再去分析源码。那下面,我们先来了解一下背景知识。
田小波
2018/06/21
6020
Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义
回看生成DefaultAopProxyFactory的createAopProxy方法来生成代理类
大忽悠爱学习
2022/05/10
1.3K0
Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义
Spring Aop详细介绍
对于我们使用者而言十分简单便利,然而,其背后所做的事,却远远比一个注解复杂的多了,本篇只是简略的介绍一下@EnableAspectJAutoProxy背后所发生的那些事,了解其工作原理,才能更好的运用,并从中领略大师的智慧.
SerMs
2022/03/30
6230
Spring Aop详细介绍
Spring中RequestScope作用域Bean原理
可知上面时序图完成了对RequestScope对象定义的修改创建了代理bean,具体修改内容是修改了beanClass为ScopedProxyFactoryBean,并且保存了原来的bean定义originatingBeanDefinition。
加多
2018/09/06
2.4K0
Spring中RequestScope作用域Bean原理
Spring @Autowired npe example:Why your Spring @Autowired component is null
找原因,找了大半天, 也翻了Spring MVC的源码。。。终于,灵机一动,看到了 private :
一个会写诗的程序员
2020/09/11
1.4K0
Spring @Autowired npe example:Why your Spring @Autowired component is null
深入理解Spring之源码剖析AOP(XML配置方式)
Spring 的两大核心,一是IOC,我们之前已经学习过,并且已经自己动手实现了一个,而另一个则是大名鼎鼎的 AOP,AOP的具体概念我就不介绍了。
Bug开发工程师
2018/09/21
5750
深入理解Spring之源码剖析AOP(XML配置方式)
1.4.SpringBoot核心注解 @EnableAspectJAutoProxy背后的那些事(spring AOP源码赏析)
在这个注解比较流行的年代里,当我们想要使用spring 的某些功能时只需要加上一行代码就可以了,比如:
itjim
2019/11/19
2.9K0
1.4.SpringBoot核心注解 @EnableAspectJAutoProxy背后的那些事(spring AOP源码赏析)
Spring AOP实现原理简介[通俗易懂]
AOP联盟将AOP体系分为三层,从三层结构可以看出,AOP实现方式有很多种,包括反射、元数据处理、程序处理、拦截器处理等,通过本节学习,你就会看到Spring AOP的实现使用的是Java语言本身的特性,即Java Proxy代理类、拦截器技术实现。
全栈程序员站长
2022/09/22
4390
Spring AOP实现原理简介[通俗易懂]
相关推荐
Spring AOP 创建代理的源码解析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档