本篇内容主要讲解“如何使用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
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;
}
}
<!-- 拦截器 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/>
执行:
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(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";
}
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”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。