使用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; } }
<!-- 拦截器 demo --> <bean id="methodinvokeinterceptor" class="com.paic.phssp.springtest.interceptor.method.methodinvokeinterceptor"/> <aop:config> <!--切入点,controlller --> <aop:pointcut id="pointcut_test" expression="execution(* com.paic.phssp.springtest.controller..*.*(..))" /> <!--在该切入点使用自定义拦截器 ,按照先后顺序执行 --> <aop:advisor pointcut-ref="pointcut_test" advice-ref="methodinvokeinterceptor" /> </aop:config> <!-- 自动扫描使用了aspectj注解的类 --> <aop:aspectj-autoproxy/>
执行:
aspectj的注解
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; } }
运行结果:
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)); } } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
上一篇: python基础技巧综合训练题1
下一篇: 上海银行发布智慧金融暨手机银行5.0产品
推荐阅读
-
spring-retry简单使用方法
-
Spring boot redis cache的key的使用方法
-
spring cloud 使用Hystrix 实现断路器进行服务容错保护的方法
-
spring cloud 使用Eureka 进行服务治理方法
-
Spring Boot 与 Kotlin 使用JdbcTemplate连接MySQL数据库的方法
-
Spring Boot使用yml格式进行配置的方法
-
在spring中使用自定义注解注册监听器的方法
-
Spring Boot 与 Kotlin 使用Redis数据库的配置方法
-
spring boot使用thymeleaf模板的方法详解
-
使用spring的IOC解决程序耦合的方法