Spring AOP原理之拦截器调用的实现

el/2024/3/2 12:26:31

接上文 Spring AOP原理之建立AopProxy代理对象

在Spring AOP通过JDK的Proxy方式或CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。如果使用JDK的Proxy来生成代理对象,那么需要通过InvocationHandler来设置拦截器回调.而如果使用CGLIB来生成代理对象,就需要根据CGLIB的使用要求.通过DynamicAdvisedlnterceptor来完成回调。

JdkDynamicAopProxy的invoke拦截

上篇文章中,在JdkDynamicAopProxy生成代理对象的时候,我们可以看到这样的源码:

//调用JDK生成代理对象return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

这里的this参数对应的是InvocationHandler对象,InvocationHandlerJDK定义的反射类的一个接口,这个接口定义了invoke方法。

public interface InvocationHandler {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}

而这个invoke方法是作为JDK Proxy代理对象进行拦截的回调入口出现的。在JdkDynamicAopProxy中实现TlnvocationHandler接口,也就是说当Proxy对象的代理方法被调用时.JdkDynamicAopProxyinvoke方法作为Proxy对象的回调函数被触发,从而通过invoke的其体实现。来完成对目标对象方法调用的拦截或者说功能增强的工作。

JdkDynamicAopProxy实现的该方法如下:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;TargetSource targetSource = this.advised.targetSource;Object target = null;Object var13;try {if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {//如果目标对象没有实现Object类的基本方法:equalsBoolean var19 = this.equals(args[0]);return var19;}if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {//如果目标对象没有实现Object类的基本方法:hashCodeInteger var18 = this.hashCode();return var18;}if (method.getDeclaringClass() == DecoratingProxy.class) {//Class var17 = AopProxyUtils.ultimateTargetClass(this.advised);return var17;}Object retVal;if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {//根据代理对象的配置来调用服务retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);return retVal;}if (this.advised.exposeProxy) {oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}//得到目标对象target = targetSource.getTarget();Class<?> targetClass = target != null ? target.getClass() : null;//获得定义好的拦截器链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);//如果没有设置拦截器,那么久直接调用target的对应方法if (chain.isEmpty()) {Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);} else {//如果有定义拦截器,就先调用拦截器之后,再调用目标对象的对应方法MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);//沿着拦截器继续前进retVal = invocation.proceed();}Class<?> returnType = method.getReturnType();if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {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);}var13 = retVal;} finally {if (target != null && !targetSource.isStatic()) {targetSource.releaseTarget(target);}if (setProxyContext) {AopContext.setCurrentProxy(oldProxy);}}return var13;}

Proxy对象的代理设里是在invoke方法中完成的.这些设里包括获取目标对象、拦截器链.同时把这些对象作为愉入,创建了ReflectiveMethodlnvocation对象,通过这个ReflectiveMethodlnvocation对象来完成对AOP功能实现的封装。在这个invoke方法中,包含了一个完整的拦截器链对目标对象的拦截过程。比如获得拦截器链并对拦截器链中的拦截器进行配置,逐个运行拦截器链里的拦截增强,直到最后对目标对象方法的运行等。

CglibAopProxy的intercept拦截

CgIibAopProxyintercept回调方法的实现和JdkDynamicAopProxy的回调实现是非常类似的,只是在CghibAopProxy中构造DynamicAdvisedInterceptor对象来完成拦截器链的调用,而在JdkDynamicAopProxy中是通过构造ReflectiveMethodInvocation对象来完成这个功能的。

DynamicAdvisedInterceptor通过实现MethodInterceptor接口来完成:

import java.lang.reflect.Method;public interface MethodInterceptor extends Callback {Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
}

其实现如下:

  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();Object var16;try {if (this.advised.exposeProxy) {oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}//得到目标对象target = targetSource.getTarget();Class<?> targetClass = target != null ? target.getClass() : null;//从advised中取得配置好的AOP通知List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;//如果没有AOP遨知配里。那么直接调用target对象的调用方法if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = methodProxy.invoke(target, argsToUse);} else {//通过CglibMethodlnvocation来启动advice通知retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();}retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);var16 = retVal;} finally {if (target != null && !targetSource.isStatic()) {targetSource.releaseTarget(target);}if (setProxyContext) {AopContext.setCurrentProxy(oldProxy);}}return var16;}

从上面可以看出,拦截器的实现逻辑是一样的。包括目标对象的调用,AOP拦截器链的调用以及配置通知器等。


http://www.ngui.cc/el/4466047.html

相关文章

Spring MVC原理之Spring应用上下文(IoC容器)在Web容器中的启动分析

Spring IoC是一个独立的模块&#xff0c;它并不是直接在Web容器中发挥作用的。如果要在Web环境中使用IoC容器&#xff0c;需要Spring为IoC设计一个启动过程&#xff0c;把IoC容器导人&#xff0c;并在Web容器中建立起来。具体说来&#xff0c;这个启动过程是和Web容器的启动过程…

Spring MVC原理之Spring MVC的设计与实现

接上文 SpringMVC原理之Spring应用上下文&#xff08;Ioc容器&#xff09;在Web容器中的启动分析。 在前文的分析过程中&#xff0c;了解了 Spring的上下文体系通过ContextLoader和DispatcherServiet建立并初始化的过程。在完成对ContextLoaderListener的初始化以后&#xff0c…

Spring JDBC的设计与实现

设计原理 在Spring JDBC中&#xff0c;JdbcTemplate 是一个主要的模板类&#xff0c;它的类继承关系如图&#xff1a; 从类继承关系上来看&#xff0c;JdbcTemplate继承了基类JdbcAccessor和接口类JdbcOperation。在基类JdbcAccessor的设计中&#xff0c;对DataSource数据源…

Spring事务处理浅析

类层次结构 在Spring的事务处理模块中.可以看到的类层次结构如图&#xff1a; 可以看到&#xff0c;Spring事务处理模块是通过AOP功能来实现声明式事务处理的&#xff0c;比如事务属性的配置和读取&#xff0c;事务对象的抽象等。因此&#xff0c;在Spring事务处理中&#xff…

dubbo管理控制台dubbo-admin安装

资源&#xff1a; dubbo源码 和 中文文档 下载源码 下载dubbo-admin模块代码&#xff0c;这个还真不太好找&#xff0c;可能是因为dubbo迁移至Apache 维护后&#xff0c;代码还没迁移好&#xff1f;&#xff1f;&#xff1f; 我是在 https://github.com/apache/incubator-du…

React Native 项目环境配置、调试以及打包

去年在做React Native混合开发的时候&#xff0c;写过几篇笔记&#xff1a; react-native对android物理返回键back的监听以及基类封装 react native导航navigator react-native 与安卓端通信 android 端集成react native Fetch 网络请求简单封装&#xff0c;支持超时入口 …

Rest 概要

REST RESTful Representational State Transfer。是在因特网上提供计算机系统之间的互操作性的一种方式。基于Http协议的资源传递&#xff0c;包括JSON、XML和文本等。 统一接口 资源识别&#xff08;Identification of resources&#xff09; URI&#xff08;Uniform Resou…

构建一个REST风格的Web服务

你需要什么 大约15分钟IntelliJ IDEA或其他编辑器JDK 1.8或更高版本Maven 3.2 你会建立什么 您将在以下地址构建一个将接受HTTP GET请求的服务&#xff1a; http://localhost:8080/greeting 会返回一个JSON 格式的数据&#xff1a; {"id":1,"content"…

调度任务Scheduling Tasks

你需要什么 大约15分钟IntelliJ IDEA或其他编辑器JDK 1.8或更高版本Maven 3.2 你会建立什么 您将构建一个应用程序&#xff0c;该应用程序使用Spring的 Scheduled 注解&#xff0c;每5秒打印一次当前时间。 构建步骤 1、添加maven依赖 <dependency><groupId>…

消费RESTful Web服务

你需要什么 大约15分钟IntelliJ IDEA或其他编辑器JDK 1.8或更高版本Maven 3.2 你会建立什么 您将构建一个使用Spring RestTemplate的应用程序来获取 http://gturnquist-quoters.cfapps.io/api/random 中的随机Spring Boot数据。 构建步骤 1、添加maven依赖&#xff1a; &l…