Spring AOP深入理解之拦截器调用

Spring AOP代理对象生成回想

上一篇博客中:深入理解Spring AOP之二代理对象生成介绍了Spring代理对象是怎样生成的,当中重点介绍了JDK动态代理方式,简单回想下代理对象生成过程:

1、上面讲到了两种生成代理对象的方法,一种是通过ProxyFactory,一种是通过ProxyFactoryBean。

第一种获取比較简单,可是须要手工的进行写代码。而另外一种是通过Spring的IOC机制来控制Bean的生成。

2、不管是ProxyFactory或者ProxyFactoryBean都是要通过createAopProxy().getProxy()来获取对应的代理对象,而通过Proxyfactory比較直接,上面重点介绍的是通过ProxyFactoryBean获得proxy。

3、首先,找到ProxyFactoryBean的getObject方法,为什么?(主要是跟Bean容器中getObject能返回代理对象)

4、其次调用getSingletonInstance(),在getSingletonInstance方法中引入了super中的方法,super是指ProxyCreatorSupport。这里ProxyCreatorSupport是ProxyFactoryBean和ProxyFactory的父类。已经做了非常多工作,仅仅需在ProxyFactoryBean的getObject()方法中通过父类的createAopProxy()取得对应的AopProxy。

5、跟踪createAopProxy方法,追踪到了ProxyCreatorSupport中,然后,借助了AopProxyFactory。此时得到的aopProxyFactory。在构造函数中已经定义为DefaultAopProxyFactory

6、进入DefaultAopProxyFactory中,找到createAopProxy方法,在这里推断是调用JDK动态或者CGlib动态中的一种。

既然代理对象已经生成,那么拦截器是怎样被调用的呢

回想下JdkDynamicAopProxy中生成proxy方法

@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
看最后一句return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)。这个地方的三个參数在博客动态代理中做过具体介绍。再回想下

  • classloader类载入器,定义了由哪个ClassLoader对象来对生成的代理对象进行载入

  • proxiedInterfaces,一个Interface对象的数组,表示的是我将要给我须要代理的对象提供一组什么接口

  • this,表示JdkDynamicAopProxy自身,由于JdkDynamicAopProxy实现了InvocationHandler接口

动态代理这篇博客中我们分析过。生成的proxy代理类被调用时。会调用super.h.method()方法,这里的super一般指的是Proxy。而Proxy中有一个InvocationHandler,即h。所以InvocationHandler的invoke方法会被作为回调函数调用

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null; try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
//目标对象未实现equals方法
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
//目标对象未实现hashcode方法
return hashCode();
}
if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
//这里就是目标对象方法的调用
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
} Object retVal; if (this.advised.exposeProxy) {
// 获得当前的对象
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);
// proceed内部实现了递归调用遍历拦截器链
retVal = invocation.proceed();
} Class<? > returnType = method.getReturnType();
if (retVal != null && retVal == target && 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);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// 释放target对象
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 替换回原来的proxy
AopContext.setCurrentProxy(oldProxy);
}
}
}

上面的invoke()主要分为三部分

  • 拦截器链的获取, this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
  • 目标对象方法的调用,即invokeJoinpointUsingReflection()方法
  • 拦截器对象方法的调用,即ReflectiveMethodInvocation中proceed()

    首先看拦截器链是如获得的。

    进入AdvisedSupport(advised为AdvisedSupport实例)的getInterceptorsAndDynamicInterceptionAdvice()方法

    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.getInterceptorsAndDynamicInterceptionAdvice(
    this, method, targetClass);
    this.methodCache.put(cacheKey, cached);
    }
    return cached;
    }
    能够看出上面方法用到缓存的, 如果如今缓存没有对应的拦截器, 则到 AdvisorChainFactory 的对应方法中获取,继续跟踪AdvisorChainFactory,发现定义为new DefaultAdvisorChainFactory(),这里是不是有一点眼熟,对的,在上一篇中讲到动态代理是也有一个DefaultAopProxy。进入DefaultAdvisorChainFactory中的对应方法。比較长

    /**
    * 从提供的配置实例config中获取advisor列表,遍历处理这些advisor.假设是IntroductionAdvisor,
    * 则推断此Advisor是否能应用到目标类targetClass上.假设是PointcutAdvisor,则推断
    * 此Advisor是否能应用到目标方法method上.将满足条件的Advisor通过AdvisorAdaptor转化成Interceptor列表返回.
    */
        public List getInterceptorsAndDynamicInterceptionAdvice(Advised config, Methodmethod, Class targetClass) {
    
           List interceptorList = new ArrayList(config.getAdvisors().length);
    
           //查看是否包括IntroductionAdvisor
    boolean hasIntroductions = hasMatchingIntroductions(config,targetClass); //这里实际上注冊一系列AdvisorAdapter,用于将Advisor转化成MethodInterceptor
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); Advisor[] advisors = config.getAdvisors();
    for (int i = 0; i <advisors.length; i++) {
    Advisor advisor = advisors[i];
    if (advisor instanceof PointcutAdvisor) {
    // Add it conditionally.
    PointcutAdvisor pointcutAdvisor= (PointcutAdvisor) advisor;
    if(config.isPreFiltered() ||pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
    //TODO: 这个地方这两个方法的位置能够互换下
    //将Advisor转化成Interceptor
    MethodInterceptor[]interceptors = registry.getInterceptors(advisor); //检查当前advisor的pointcut能否够匹配当前方法
    MethodMatcher mm =pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm,method, targetClass, hasIntroductions)) {
    if(mm.isRuntime()) {
    // Creating a newobject instance in the getInterceptors() method
    // isn't a problemas we normally cache created chains.
    for (intj = 0; j < interceptors.length; j++) {
    interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptors[j],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;
    }
    注意上面代码中的一行,注冊一系列AdvisorAdapter。找到GlobalAdvisorAdapterRegistry,事实上定义为 new DefaultAdvisorAdapterRegistry(),又是default~~~

    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    
    instance = new DefaultAdvisorAdapterRegistry();
    
    public DefaultAdvisorAdapterRegistry() {
    registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
    registerAdvisorAdapter(new AfterReturningAdviceAdapter());
    registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }
    所以registry事实上为调用了DefaultAdvisorAdapterRegistry的构造函数,然后才干在将Advisor转化成Interceptor时。调用DefaultAdvisorAdapterRegistry的getInterceptors()方法。

        @Override
    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()]);
    }
    这里的MethodInterceptor[]返回值,正好能够匹配上面代码中的 MethodInterceptor[]interceptors = registry.getInterceptors(advisor);

    目标对象方法的调用

    来看看invokeJoinpointUsingReflection()。即上面所说的目标对象方法的调用,事实上是通过AopUtils的方法调用。使用反射机制来对目标对象的方法进行的:

        public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
    throws Throwable { // 通过反射机制来获得对应的方法。并调用invoke
    try {
    ReflectionUtils.makeAccessible(method);
    return method.invoke(target, args);
    }
    catch (InvocationTargetException ex) { throw ex.getTargetException();
    }
    catch (IllegalArgumentException ex) {
    throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
    method + "] on target [" + target + "]", ex);
    }
    catch (IllegalAccessException ex) {
    throw new AopInvocationException("Could not access method [" + method + "]", ex);
    }
    }

    拦截器方法运行

    看看拦截器对象,即ReflectiveMethodInvocation中proceed()方法的调用

    invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    
    retVal = invocation.proceed();
    
    
    invocation是一个new ReflectiveMethodInvocation()实例,找到ReflectiveMethodInvocation的proceed()方法


    private int currentInterceptorIndex = -1; @Override
    public Object proceed() throws Throwable {
    // currentInterceptorIndex初始化的长度为-1,以下就就是推断 //interceptorsAndDynamicMethodMatchers长度是否为0
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    return invokeJoinpoint();
    } Object interceptorOrInterceptionAdvice =
    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
    //匹配是否为正确的方法逻辑,(MethodMatcher)能够看出为匹配假设不是就调用下一个
    InterceptorAndDynamicMethodMatcher dm =
    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
    return dm.interceptor.invoke(this);
    }
    else {
    //匹配失败,跳过这个拦截器,继续下一个
    return proceed();
    }
    }
    else {
    // 假设是interceptor。则调用invoke方法。这是为了兼容 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
    }


  • Spring AOP深入理解之拦截器调用的更多相关文章

    1. Spring AOP 源码分析 - 拦截器链的执行过程

      1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

    2. Spring Boot实践——三种拦截器的创建

      引用:https://blog.csdn.net/hongxingxiaonan/article/details/48090075 Spring中的拦截器 在web开发中,拦截器是经常用到的功能.它可 ...

    3. 通过spring抽象路由数据源+MyBatis拦截器实现数据库自动读写分离

      前言 之前使用的读写分离的方案是在mybatis中配置两个数据源,然后生成两个不同的SqlSessionTemplate然后手动去识别执行sql语句是操作主库还是从库.如下图所示: 好处是,你可以人为 ...

    4. spring自定义注解实现登陆拦截器

      1.spring自定义注解实现登陆拦截器 原理:定义一个注解和一个拦截器,拦截器拦截所有方法请求,判断该方法有没有该注解.没有,放行:有,要进行验证.从而实现方法加注解就需要验证是否登陆. 2.自定义 ...

    5. Spring的AOP,Struts2的拦截器(Interceptor),以及springMVC的(interceptor)

      参考外链:http://www.ibm.com/developerworks/cn/java/j-lo-springaopfilter/ 1.首先,spring的AOP作用范围很广,可以使用Aspec ...

    6. Spring Boot使用过滤器和拦截器分别实现REST接口简易安全认证

      本文通过一个简易安全认证示例的开发实践,理解过滤器和拦截器的工作原理. 很多文章都将过滤器(Filter).拦截器(Interceptor)和监听器(Listener)这三者和Spring关联起来讲解 ...

    7. .net core 3.1 过滤器(Filter) 与中间件与AOP面向切面 与拦截器及其应用

      Filter(过滤器) 总共有五种,Authorization Filter,Resource Filter,Exception Filter,Action Filter,Result Filter ...

    8. Spring MVC全局异常处理与拦截器校检

      在使用Spring MVC进行开发时,总是要对系统异常和用户的异常行为进行处理,以提供给用户友好的提示,也可以提高系统的安全性. 拦截系统响应错误 首先是拦截系统响应错误,这个可以在web.xml中配 ...

    9. Spring AOP 简单理解

      AOP技术即(面向切面编程)技术是在面向对象编程基础上的发展,AOP技术是对所有对象或一类对象编程.核心是在不增加代码的基础上,还增加了新的功能.AOP编程在开发框架本身用的比较多,而实际项目中,用的 ...

    随机推荐

    1. IntelliJ IDEA 查看继承关系

      在 IntelliJ IDEA 中这个查看一个类也就是当前类的所有继承关系,包括实现的所有的接口和继承的类, 这个继承,不仅仅是一级的继承关系,包括好几层的继承.父类的父类的父类.直到最后.可以很清楚 ...

    2. oracle开发学习篇之集合函数

      集合函数; declare type list_nested ) not null; v_all list_nested := list_nested('changan','hubei','shang ...

    3. C#中汉字排序简单示例(拼音/笔划)

      可以按照区域语言修改排序规则. class Program { static void Main(string[] args) { string[] arr = { "趙(ZHAO)&quo ...

    4. CNZZ站点流量统计原理简析

      这是我的域名www.iyizhan.com.暂无内容,当中仅仅有一个页面index.html. 在index.html上放置了例如以下的 js 脚本: <script  src="ht ...

    5. [翻译] FlatUIKit

      FlatUIKit FlatUIKit is a collection of iOS components styled with the "Flat UI" aesthetic ...

    6. MySQL Workbench update语句错误Error Code: 1175.

      rom:http://www.tuicool.com/articles/NJ3QRz MySQL update error: Error Code: 1175. You are using safe ...

    7. 一直困扰设计师多年的Android 单位 dp

      轻松理解Android开发单位DP ,让设计与开发高度匹配,整合了网上各大资料汇总一个通俗易懂的. 一直困扰设计师多年的Android 单位 dp 设计这么多年了,相信很多设计师,一直被DP搞得晕头转 ...

    8. Cocos2dx 3.0 过渡篇(二十七)C++11多线程std::thread的简单使用(下)

      本篇接上篇继续讲:上篇传送门:http://blog.csdn.net/star530/article/details/24186783 简单的东西我都说的几乎相同了,想挖点深的差点把自己给填进去. ...

    9. UVA 10026 Shoemaker&#39;s Problem

      Shoemaker's Problem Shoemaker has N jobs (orders from customers) which he must make. Shoemaker can w ...

    10. 数学图形(1.2)Sin曲线

      相关软件参见:数学图形可视化工具,使用自己定义语法的脚本代码生成数学图形.该软件免费开源.QQ交流群: 367752815 Sin曲线 vertices = x = *PI) to (*PI) y = ...