千家信息网

如何使用Spring方法拦截器MethodInterceptor

发表于:2025-02-12 作者:千家信息网编辑
千家信息网最后更新 2025年02月12日,本篇内容主要讲解"如何使用Spring方法拦截器MethodInterceptor",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何使用Spring方法拦
千家信息网最后更新 2025年02月12日如何使用Spring方法拦截器MethodInterceptor

本篇内容主要讲解"如何使用Spring方法拦截器MethodInterceptor",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何使用Spring方法拦截器MethodInterceptor"吧!

Spring方法拦截器MethodInterceptor

前言

实现MethodInterceptor 接口,在调用目标对象的方法时,就可以实现在调用方法之前、调用方法过程中、调用方法之后对其进行控制。

MethodInterceptor 接口可以实现MethodBeforeAdvice接口、AfterReturningAdvice接口、ThrowsAdvice接口这三个接口能够所能够实现的功能,但是应该谨慎使用MethodInterceptor 接口,很可能因为一时的疏忽忘记最重要的MethodInvocation而造成对目标对象方法调用失效,或者不能达到预期的设想。

示例代码如下

public class TestMethodInterceptor  {    public static void main(String[] args) {        ProxyFactory proxyFactory=new ProxyFactory();        proxyFactory.setTarget(new TestMethodInterceptor());        proxyFactory.addAdvice(new adviseMethodInterceptor());        Object proxy = proxyFactory.getProxy();        TestMethodInterceptor methodInterceptor = (TestMethodInterceptor) proxy;        methodInterceptor.doSomeThing("通过代理工厂设置代理对象,拦截代理方法");    }    public static class adviseMethodInterceptor implements MethodInterceptor{        @Override        public Object invoke(MethodInvocation methodInvocation) throws Throwable {            Object result=null;            try{                System.out.println("方法执行之前:"+methodInvocation.getMethod().toString());                result= methodInvocation.proceed();                System.out.println("方法执行之后:"+methodInvocation.getMethod().toString());                System.out.println("方法正常运行结果:"+result);                return result;            }catch (Exception e){                System.out.println("方法出现异常:"+e.toString());                System.out.println("方法运行Exception结果:"+result);                return result;            }        }    }    public String doSomeThing(String someThing){        //int i=5/0;        return "执行被拦截的方法:"+someThing;    }}

正常运行结果:

方法执行之前:public java.lang.String com.blog.test.aop.TestMethodInterceptor.doSomeThing(java.lang.String)

方法执行之后:public java.lang.String com.blog.test.aop.TestMethodInterceptor.doSomeThing(java.lang.String)

方法正常运行结果:执行被拦截的方法:通过代理工厂设置代理对象,拦截代理方法

异常运行结果:

方法执行之前:public java.lang.String com.blog.test.aop.TestMethodInterceptor.doSomeThing(java.lang.String)

方法出现异常:java.lang.ArithmeticException: / by zero

方法运行Exception结果:null

Spring拦截器实现+后台原理(MethodInterceptor)

MethodInterceptor

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

实现MethodInterceptor拦截器大致也分为两种:

(1)MethodInterceptor接口;

(2)利用AspectJ的注解配置;

MethodInterceptor接口
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;    }}
                                                    

执行:

AspectJ的注解
import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.springframework.stereotype.Component;@Aspect@Componentpublic 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;    }}

运行结果:

AutoAspectJInterceptor begin around......

>>>>:isAuthenticated=false

AutoAspectJInterceptor end around......

简单介绍下关键词
  • AOP=Aspect Oriented Program面向切面(方面/剖面)编程

  • Advice(通知):把各组件中公共业务逻辑抽离出来作为一个独立 的组件

  • Weave(织入):把抽离出来的组件(Advice),使用到需要使用该逻辑 地方的过程。

  • JoinPoint (连接点): Advice 组件可以weave的特征点。

  • PointCut(切入点):用来明确Advice需要织入的连接点

  • Aspect(切面):Aspect=Advice + PointCut

通知类型

  • @Before 在切点方法之前执行

  • @After 在切点方法之后执行

  • @AfterReturning 切点方法返回后执行

  • @AfterThrowing 切点方法抛异常执行

  • @Around环绕通知

执行顺序:

  • @Around环绕通知

  • @Before通知执行

  • @Before通知执行结束

  • @Around环绕通知执行结束

  • @After后置通知执行了!

  • @AfterReturning

切面设置

可以使用&&、||、!、三种运算符来组合切点表达式

execution表达式
"execution(public * com.xhx.springboot.controller.*.*(..))"
  • *只能匹配一级路径

  • ..可以匹配多级,可以是包路径,也可以匹配多个参数

  • + 只能放在类后面,表明本类及所有子类

within(类路径) 配置指定类型的类实例,同样可以使用匹配符

within(com.xhx.springboot..*)

@within(annotationType) 匹配带有指定注解的类(注:与上不同)

"@within(org.springframework.stereotype.Component)"

@annotation(annotationType) 匹配带有指定注解的方法

"@annotation(IDataSource)"

其中:IDataSource为自定义注解

import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})public @interface IDataSource {    String value() default "dataSource";}
下面分析下Spring @Aspect

1、注册

org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator

看到实现接口BeanPostProcessor,必然在初始化Bean前后,执行接口方法。

2、解析

AspectJAutoProxyBeanDefinitionParser.java#parse()方法

@Nullable    public BeanDefinition parse(Element element, ParserContext parserContext) {        AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);        this.extendBeanDefinition(element, parserContext);        return null;    }
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);        registerComponentIfNecessary(beanDefinition, parserContext);    }
@Nullable    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);    }

3、具体实现

上面提到实现接口BeanPostProcessor,必然在初始化Bean前后,执行接口方法。看下面时序图:

AbstractAutoProxyCreator的postProcessAfterInitialization()方法

DefaultAopProxyFactory.createAopProxy()方法,具体创建代理类。两种动态代理:JDK动态代理和CGLIB代理。

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {        if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {            return new JdkDynamicAopProxy(config);        } else {            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.");            } else {                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));            }        }    }

到此,相信大家对"如何使用Spring方法拦截器MethodInterceptor"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0