Spring AOP深入理解之拦截器调用
Spring AOP深入理解之拦截器调用
Spring AOP代理对象生成回想
第一种获取比較简单,可是须要手工的进行写代码。而另外一种是通过Spring的IOC机制来控制Bean的生成。
既然代理对象已经生成,那么拦截器是怎样被调用的呢
@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);
    }
classloader类载入器,定义了由哪个ClassLoader对象来对生成的代理对象进行载入
proxiedInterfaces,一个Interface对象的数组,表示的是我将要给我须要代理的对象提供一组什么接口
this,表示JdkDynamicAopProxy自身,由于JdkDynamicAopProxy实现了InvocationHandler接口
@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()主要分为三部分
首先看拦截器链是如获得的。
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;
    }
/**
    * 从提供的配置实例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;
}
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
instance = new DefaultAdvisorAdapterRegistry();
public DefaultAdvisorAdapterRegistry() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }
    @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()]);
    }
目标对象方法的调用
    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);
        }
    }
拦截器方法运行
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.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深入理解之拦截器调用的更多相关文章
- Spring AOP 源码分析 - 拦截器链的执行过程
		
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...
 - Spring Boot实践——三种拦截器的创建
		
引用:https://blog.csdn.net/hongxingxiaonan/article/details/48090075 Spring中的拦截器 在web开发中,拦截器是经常用到的功能.它可 ...
 - 通过spring抽象路由数据源+MyBatis拦截器实现数据库自动读写分离
		
前言 之前使用的读写分离的方案是在mybatis中配置两个数据源,然后生成两个不同的SqlSessionTemplate然后手动去识别执行sql语句是操作主库还是从库.如下图所示: 好处是,你可以人为 ...
 - spring自定义注解实现登陆拦截器
		
1.spring自定义注解实现登陆拦截器 原理:定义一个注解和一个拦截器,拦截器拦截所有方法请求,判断该方法有没有该注解.没有,放行:有,要进行验证.从而实现方法加注解就需要验证是否登陆. 2.自定义 ...
 - Spring的AOP,Struts2的拦截器(Interceptor),以及springMVC的(interceptor)
		
参考外链:http://www.ibm.com/developerworks/cn/java/j-lo-springaopfilter/ 1.首先,spring的AOP作用范围很广,可以使用Aspec ...
 - Spring Boot使用过滤器和拦截器分别实现REST接口简易安全认证
		
本文通过一个简易安全认证示例的开发实践,理解过滤器和拦截器的工作原理. 很多文章都将过滤器(Filter).拦截器(Interceptor)和监听器(Listener)这三者和Spring关联起来讲解 ...
 - .net core 3.1 过滤器(Filter) 与中间件与AOP面向切面 与拦截器及其应用
		
Filter(过滤器) 总共有五种,Authorization Filter,Resource Filter,Exception Filter,Action Filter,Result Filter ...
 - Spring MVC全局异常处理与拦截器校检
		
在使用Spring MVC进行开发时,总是要对系统异常和用户的异常行为进行处理,以提供给用户友好的提示,也可以提高系统的安全性. 拦截系统响应错误 首先是拦截系统响应错误,这个可以在web.xml中配 ...
 - Spring AOP 简单理解
		
AOP技术即(面向切面编程)技术是在面向对象编程基础上的发展,AOP技术是对所有对象或一类对象编程.核心是在不增加代码的基础上,还增加了新的功能.AOP编程在开发框架本身用的比较多,而实际项目中,用的 ...
 
随机推荐
- Java线程锁&分布式锁的理解及应用
			
了解Java线程锁之前,先理解线程和进程的定义.进程是操作系统分配资源(CPU)的基本单位,线程是CPU执行的基本单位,一个进程可拥有多个线程,同进程间的多个线程共享分配给进程的资源.比如启动JVM时 ...
 - Git_Feature分支
			
软件开发中,总有无穷无尽的新的功能要不断添加进来. 添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合 ...
 - Shell中EOF内容转义
			
1.在$符号前面加反斜杠,如: cat > test.sh <<EOF \$test EOF 如果不加,将转成实际的值. 2.给EOF加个双引号,如: cat > test.s ...
 - SoC嵌入式软件架构设计之七:嵌入式文件系统设计
			
嵌入式的系统区(system disk,SD)包含操作系统.驱动.中间件.应用和字库.UI资源等文件,本文讲述SD区的文件系统设计.文件系统最基本的目标是为了实现单个文件的定位和读写.由于一般代码都是 ...
 - Kernel Newbies内核开发新手的资源
			
Jessica McKellar在Ksplice blog上的博客文章 <Linux Device Drivers> 如果你在写一个操作系统,OSDev wiki是一个不错的网站 Kern ...
 - [转载] C# matlab联合编程简介
			
原作者 文月 主要操作说明: 1. 找到matlab安装目录下的MCRInstaller.exe安装 MCRInstaller.exe 在安装目录下的 ..\MATLAB7\toolbox\comp ...
 - arcgis10.5新功能图形缓冲
			
摘要 在输入要素周围某一指定距离内创建缓冲区多边形.在要素周围生成缓冲区时,大部分制图形状对缓冲区末端(端头)和拐角(连接)可用. 插图
 - Sublime Text2安装emmet(原名Zen Coding)总结
			
首先,安装好Sublime( 我用的是版本号2),之后注冊好.Sublime Text2.0.2注冊码:http://xionggang163.blog.163.com/blog/static/376 ...
 - Shimmer辉光动画效果
			
Shimmer辉光动画效果 效果 源码 https://github.com/facebook/Shimmer https://github.com/YouXianMing/Animations // ...
 - Grunt常见问题
			
1.nodeJs 环境安装?进入官网:http://www.nodejs.org/ 根据操作系统,下载相应的安装包,直接安装即可. 2.npm 安装?a) 如果系统没有安装过Git,可以直接到http ...