SpringBoot之自定义拦截器

Advice,Advisor,Advised是什么?

参考链接:https://blog.csdn.net/yangzsirr/article/details/120915005
https://blog.csdn.net/wang489687009/article/details/121099165

1、advice
    解释为通知,表示 Aspect 在特定的 连接点(Join point)采取的操作。包括 “around”, “before” and “after 等。和切点(pointCut)组成一个切面(aspect)可以有多个通知
补充:
    ①Pointcut:切点,决定advice应该作用于那个连接点,比如根据正则等规则匹配哪些方法需要增强(Pointcut 目前有getClassFilter(类匹配),getMethodMatcher(方法匹配),Pointcut TRUE (全匹配))
    ②JoinPoint:连接点,就是spring允许你是通知(Advice)的地方,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。其他如AspectJ还可以让你在构造器或属性注入时都行
在这里插入图片描述
可以看出MethodInterceptor 是功能最强大的,它能够处理 BeforeAdvice、AroundAdvice、AfterAdvice、ThrowsAdvice

2、advisor
    解释为通知者,它持有 Advice,是Advice和PointCut的结合,它是将Advice注入程序中Pointcut位置的代码。org.springframework.aop.support.DefaultPointcutAdvisor是最通用的Advisor类,在Advisor中Advice和PointCut是一对一的只包含一个通知
在这里插入图片描述
从接口方法很容易看到Advisor就是Advice和Pointcut的组合,从中可以获取Advice和Pointcut。
3、Advised
    AOP 代理工厂配置类接口。提供了操作和管理 Advice 和 Advisor 的能力。
在这里插入图片描述
Spring提供的类org.springframework.aop.framework.ProxyFactoryBean是创建AOP的最基本的方式。它是个工厂Bean,然后我们可以自定义我们的代理实现逻辑,最终交给Spring容器管理即可。

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

    1、HandlerInterceptoer拦截的是请求地址,所以针对请求地址做一些验证、预处理等操作比较合适。当你需要统计请求的响应时间时MethodInterceptor将不太容易做到,因为它可能跨越很多方法或者只涉及到已经定义好的方法中一部分代码。
    2、MethodInterceptor是AOP项目中的拦截器(注:不是动态代理拦截器),它拦截的目标是方法
    3、另外,还有一个跟拦截器类似的东西----Filter。Filter是Servlet规范规定的,不属于spring框架,也是用于请求的拦截。但是它适合更粗粒度的拦截,在请求前后做一些编解码处理、日志记录等。
在这里插入图片描述

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

(1)MethodInterceptor接口;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class MyAdvice implements MethodInterceptor {
    /**
     * 此方法可以在目标业务方法执行之前和之后添加扩展逻辑
     */
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("start:" + System.nanoTime());
        Object result = methodInvocation.proceed();//执行目标方法
        System.out.println(result);
        System.out.println("end:" + System.nanoTime());
        return result;
    }
}

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

@Component
@Aspect
public class MyAspect {
    @Pointcut("execution(public * com.example.demo.service.impl.UserServiceImpl.*(..))")
    public void pointCut(){

    }

    @Around("pointCut()")
    public void aroundAOP(ProceedingJoinPoint joinPoint){
        try {
            System.out.println("前置通知");
            joinPoint.proceed();
            System.out.println("返回通知");
        } catch (Throwable throwable) {
            System.out.println("异常通知");
        } finally {
            System.out.println("后置通知");
        }
    }
}

自定义实现方法拦截器MethodInterceptor

方式一:
1、定义TargetAnnotation 注解,用于描述目标业务对象

/**借助此注解描述切入点方法*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TargetAnnotation {
}

2、定义MyAdvice对象,基于此对象为目标业务对象做方法增强。

public class MyAdvice implements MethodInterceptor {
    /**
     * 此方法可以在目标业务方法执行之前和之后添加扩展逻辑
     */
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("start:" + System.nanoTime());
        Object result = methodInvocation.proceed();//执行目标方法
        System.out.println(result);
        System.out.println("end:" + System.nanoTime());
        return result;
    }
}

3、创建MyAdvisor对象,在对象内部定义要切入扩展功能的点以及要应用的通知(Advice)对象。

@Component
public class MyAdvisor extends StaticMethodMatcherPointcutAdvisor {
	private static final long serialVersionUID = 7022316764822635205L;
	public MyAdvisor() {
		//在特定切入点上要执行的通知
		setAdvice(new MyAdvisor());
	}
	//Pointcut
	//方法返回值为true时,则可以为目标方法对象创建代理对象
	@Override
	public boolean matches(Method method,Class<?> targetClass) {
		try {
			Method targetMethod = targetClass.getMethod(method.getName(),
				method.getParameterTypes());
			return targetMethod.isAnnotationPresent(TargetAnnotation.class);
		} catch(Exception e) {
			return false;
		}
	}
}

4、BeanPostProcessor类型对象初始化
    在项目启动类中,添加DefaultAdvisorAutoProxyCreator对象初始化方法,基于此对象在容器启动时扫描所有Advisor对象,然后基于切入点描述的目标方法为目标对象创建代理对象,代码如下:

@SpringBootApplication
public class DemoApplication {
    //@Bean注解应用于配置类中(使用了@Configuration修饰)
    //@Bean描述的方法其返回值会交给spring管理,spring管理这个bean默认bean名字为方法名
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        //此对象会在容器启动时扫描Advisor对象,然后基于切入点为目标对象创建代理对象
        //然后再执行切入点方法时,自动执行Advice对象通知方法
        return new DefaultAdvisorAutoProxyCreator();
    }
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

5、目标对象

@Service
public class BookServiceImpl extends ServiceImpl<BookDao, Book> implements BookService {
    @TargetAnnotation
    @Override
    public Book getDataByBookId(int bookId) {
        Book book = baseMapper.getDataByBookId(bookId);
        return book;
    }
}

6、测试

	@Autowired
    private BookService bookService;
	@Test
    public void test() {
        bookService.getDataByBookId(1);
    }

方式二:
1、定义MyAdvice对象,基于此对象为目标业务对象做方法增强。

public class MyAdvice implements MethodInterceptor {
    /**
     * 此方法可以在目标业务方法执行之前和之后添加扩展逻辑
     */
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("start:" + System.nanoTime());
        Object result = methodInvocation.proceed();//执行目标方法
        System.out.println(result);
        System.out.println("end:" + System.nanoTime());
        return result;
    }
}

2、目标对象

@Service
public class BookServiceImpl extends ServiceImpl<BookDao, Book> implements BookService {
    @Override
    public String getMessage(String str) {
        return str;
    }
}

3、通过ProxyFactory 自定义代理逻辑测试

	@Autowired
    private BookService bookService;
	@Test
    public void test() {
       ProxyFactory proxyFactory = new ProxyFactory();
        //注:这里如果直接new,那么该类就不能使用@Autowired之类的注入,因此建议还是从容器中去拿
        //proxyFactory.setTarget(new BookServiceImpl());//cglib代理
        proxyFactory.setTarget(bookService);            //jdk代理

        //若没有实现接口,那就会采用cglib去代理,否则就是jdk代理
        //proxyFactory.setInterfaces(BookService.class);

        //若设置为true,强制使用cglib,默认是false的
        //proxyFactory.setProxyTargetClass(true);

        proxyFactory.addAdvice(new MyAdvice());
        Object proxy = proxyFactory.getProxy();
        BookService methodInterceptor = (BookService) proxy;
        methodInterceptor.getMessage("测试");
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 和 MyBatis 结合使用时,自定义拦截是一种强大的工具,允许开发者在执行 SQL 之前、之后或在特定业务逻辑点进行额外的操作。以下是如何使用自定义拦截的一般步骤: 1. **创建拦截接口**: 首先,你需要定义一个实现了 `org.apache.ibatis.interceptor.Interceptor` 接口的类,这个类通常是抽象的,包含你想要执行的业务逻辑方法。 ```java public interface CustomInterceptor extends Interceptor { // 自定义方法,例如预处理SQL前、后操作 Object before(Invocation invocation); // 其他可能的方法,如执行SQL后处理 Object after(Invocation invocation) throws Throwable; } ``` 2. **实现具体拦截类**: 在具体类中,你需要重写上述接口的方法,并添加你需要的业务逻辑。 ```java public class YourCustomInterceptor implements CustomInterceptor { @Override public Object before(Invocation invocation) { // 在这里执行预处理操作 Object parameter = invocation.getArgs(); // 获取参数 // ...你的代码... return parameter; // 返回处理后的参数 } @Override public Object after(Invocation invocation) { // 执行SQL后处理 // ...你的代码... } } ``` 3. **注册拦截**: 在 Spring Boot 的 MyBatis 配置中,通过 `SqlSessionFactoryBean` 或者 `SqlSessionBuilder` 注册你的拦截。可以通过 `interceptors` 属性来添加自定义拦截列表。 ```java @Configuration public class MyBatisConfig { @Bean public SqlSessionFactory sqlSessionFactory(MyBatisMapperScannerConfigurer scannerConfigurer) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setMapperScannerConfigurer(scannerConfigurer); // 添加你的拦截 factoryBean.setPlugins(Arrays.asList(new YourCustomInterceptor())); return factoryBean.getObject(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值