spring mvc拦截器,spring拦截器以及AOP切面的区别和源码

SpringMVC 拦截器执行时机

对于springmvc,有两种方式配置拦截器。

一是实现HandlerInterceptor接口,如

public class MyInterceptor1 implements HandlerInterceptor {
   
    //该方法在action执行前执行,可以实现对数据的预处理,
    // 比如:编码、安全控制等。如果方法返回true,则继续执行action。
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws
            Exception {
   
        System.out.println("MyInterceptor1 action之前执行!!!");
        return true;  //继续执行action
    }
 
    该方法在action执行后,生成视图前执行。在这里,我们有机会修改视图层数据。
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView
            modelAndView) throws Exception {
   
        System.out.println("MyInterceptor1 action执行之后,生成视图之前执行!!");
    }
 
    //最后执行,通常用于释放资源,处理异常。我们可以根据ex是否为空,来进行相关的异常处理。
    //因为我们在平时处理异常时,都是从底层向上抛出异常,最后到了spring框架从而到了这个方法中。
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
   
        System.out.println("MyInterceptor1 最后执行!!!一般用于释放资源!!");
    }
}

二是extends HandlerInterceptorAdapter类(是HandlerInterceptor的子类),如

public class MyInterceptor2  extends HandlerInterceptorAdapter{
   
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws
            Exception {
   
        System.out.println("MyInterceptor2.preHandle()");
        return true;  //继续执行action
    }
}

1、执行doDispatcher做请求分发处理里getHandler() 方法 (关键类 RequestMappingHandlerMapping )
在这里插入图片描述
mappedHandler.applyPreHandle () 执行所有拦截器的前置方法 → preHandle(),
在这里插入图片描述
在applyPreHandle()方法中,将与目标处理器关联的所有拦截器进行正序遍历,遍历执行所有拦截器的preHandle()方法
在这里插入图片描述
执行完后回到dispatch()方法继续执行,然后执行所有拦截器的后置方法
在这里插入图片描述
在这里插入图片描述
applyPostHandle()方法中,倒序遍历执行所有拦截器的postHandle()方法
在这里插入图片描述
然后执行 processDispatchResult()方法 处理模型和视图
在这里插入图片描述
进入processDispatchResult()方法中,执行render()方法进行渲染
在这里插入图片描述
渲染完后,最后在render()方法的最后,执行triggerAfterCompletion()方法
在这里插入图片描述
在triggerAfterCompletion()方法中,和前面的applyPostHandle()方法一样,这里也是倒序遍历执行拦截器的afterCompletion()方法
在这里插入图片描述

spring 拦截器与Aop

spring aop功能的继承关系图
在这里插入图片描述

MethodInterceptor是AOP项目中的拦截器(注:不是动态代理拦截器),区别与HandlerInterceptor拦截目标时请求,它拦截的目标是方法。

实现MethodInterceptor拦截器大致也分为两种:
(1)MethodInterceptor接口;
(2)利用AspectJ的注解配置;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MethodInvokeInterceptor implements MethodInterceptor {
   
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
   
        System.out.println("before method invoke....");
        Object object = methodInvocation.proceed();
        System.out.println("after method invoke.....");
        return object;
    }
}

Aspect的注解

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AutoAspectJInterceptor {
   

    @Around("execution (* com.paic.phssp.springtest.controller..*.*(..))")
    public Object around(ProceedingJoinPoint point) throws Throwable{
   
        System.out.println("AutoAspectJInterceptor begin around......");
        Object object = point.proceed();
        System.out.println("AutoAspectJInterceptor end around......");
        return object;
    }
}

织入配置类

@Configuration
public class InterceptorConfig {
   
 
    public static final String traceExecution = "execution(* com.hfi.aop..*.*(..))";
 
 
    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor() {
   
        MethodInvokeInterceptor interceptor = new MethodInvokeInterceptor ();
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(traceExecution);
 
        // 配置增强类advisor
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(interceptor);
        return advisor;
    }
}

在这里插入图片描述
1.切面(Aspect):切面就是一个关注点的模块化,如事务管理、日志管理、权限管理等;

2.连接点(Joinpoint):程序执行时的某个特定的点,在Spring中就是一个方法的执行;

3.通知(Advice):通知就是在切面的某个连接点上执行的操作,也就是事务管理、日志管理等;

4.切入点(Pointcut):切入点就是描述某一类选定的连接点,也就是指定某一类要织入通知的方法;

5.目标对象(Target):就是被AOP动态代理的目标对象;

在这里插入图片描述

spring如何判断bean是否需要被代理
spring在创建完bean后,需要判断是否需要给当前bean创建代理对象。org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory类中的doCreateBean方法里

try {
   
            this.populateBean(beanName, mbd, instanceWrapper);
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
   
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
   
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }

在这里插入图片描述
进入initializeBean方法里,图上分别存在对应BeanPostProcessor的前置方法(postProcessBeforeInitialization),后置方法(postProcessAfterInitialization),然后有一个中间的初始化方法(invokeInitMethods),这个invokeInitMethods对应了实现InitializingBean的类(最前面还有个invokeAwareMethods方法,该方法可参考这篇文章aware系列接口),initializeBean方法流程如下:
在这里插入图片描述

在这里插入图片描述

然后我们再看后置方法:applyBeanPostProcessorsAfterInitialization,一直往里走该方法会调用所有BeanPostProcessor的postProcessAfterInitialization。

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
   
        Object result = existingBean;

        Object current;
        for(Iterator var4 = this.getBeanPostProcessors().iterator(); var4.hasNext(); result = current) {
   
            BeanPostProcessor processor = (BeanPostProcessor)var4.next();
            current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
   
                return result;
            }
        }

        return result;
    }

进入postProcessAfterInitialization方法:

public Object postProcessAfterInitialization(@Nullable Object bean, 
       String beanName) throws BeansException {
   
    if (bean != null) {
   
        // 获取当前bean的key:如果beanName不为空,则以beanName为key,如果为FactoryBean类型,
        // 前面还会添加&符号,如果beanName为空,则以当前bean对应的class为key
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // 判断当前bean是否正在被代理,如果正在被代理则不进行封装
        if (!this.earlyProxyReferences.contains(cacheKey)) {
   
            // 对当前bean进行封装
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

然后org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator就是一个BeanPostProcessor,该类的postProcessAfterInitialization会调用wrapIfNecessary方法,即该bean是否需要被包装成代理对象。是否需要代理原则就是该bean有没有与之相关的Advisor,有就代理。

spring如何查找所有Advisor源码及如何判断某个bean与之关联的Advisor有哪些

wrapIfNecessary部分源码

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
   
			return bean;
		}
		if 
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值