spring和Mybatis中的拦截器

Spring的拦截器

Spring的拦截器主要分两种,一个是HandlerInterceptor,一个是MethodInterceptor。

HandlerInterceptor拦截器

        HandlerInterceptor是springMVC项目中的拦截器,它拦截的目标是请求的地址,比MethodInterceptor先执行。实现一个HandlerInterceptor拦截器可以实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter类。

自定义拦截器:

public class CustomInterceptor implements HandlerInterceptor {  
    @Override  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
        System.out.println("在Controller方法调用之前执行:" + request.getRequestURI());  
          
        //只有返回true才会继续向下执行,返回false取消当前请求  
        return true;  
    }  
  
    @Override  
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)  
            throws Exception {  
        System.out.println("在Controller方法调用之后,视图被渲染之前执行:" + request.getRequestURI());  
    }  
      
    @Override  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)  
            throws Exception {  
        System.out.println("在视图被渲染之后执行:" + request.getRequestURI());  
    }  
}  

创建WebMvcConfigurerAdapter的子类,将自定义拦截器加入到拦截器链中。

@Configuration  
public class WebMvcConfig extends WebMvcConfigurerAdapter {  
    @Override  
    public void addInterceptors(InterceptorRegistry registry) {  
        //将自定义拦截器加入到拦截器链中  
        String[] excludes = {"/css/**", "/images/**", "/js/**"}; //忽略静态资源  
        registry.addInterceptor(new CustomInterceptor()).addPathPatterns("/**").excludePathPatterns(excludes);  
          
        super.addInterceptors(registry);  
    }  
}  

MethodInterceptor拦截器

        MethodInterceptor是AOP项目中的拦截器,它拦截的目标是方法,即使不是controller中的方法。实现MethodInterceptor拦截器大致也分为两种,一种是实现MethodInterceptor接口,另一种利用Aspect的注解或配置。

实现MethodInterceptor接口:

//自定义注解类  
@Documented  
@Retention(RetentionPolicy.RUNTIME)  
@Target({ElementType.METHOD})  
public @interface Log {  
      
}  
  
//方法拦截器  
public class CustomMethodInterceptor implements MethodInterceptor{  
    @Override  
    public Object invoke(MethodInvocation invocation) throws Throwable {  
        System.out.println("before...");  
        Object object = invocation.proceed();  
        System.out.println("after...");  
        return object;  
    }  
}  
  
  
@Configuration  
public class AspectjAutoConfig {  
    @Bean  
    public DefaultPointcutAdvisor getDefaultPointcutAdvisor() {  
        DefaultPointcutAdvisor pointcutAdvisor = new DefaultPointcutAdvisor();  
        pointcutAdvisor.setOrder(Ordered.HIGHEST_PRECEDENCE + 500);  
          
        //基于方法注解进行拦截  
        AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(null, Log.class);  
        CustomMethodInterceptor advice = new CustomMethodInterceptor();  
        pointcutAdvisor.setPointcut(pointcut);  
        pointcutAdvisor.setAdvice(advice);  
          
        return pointcutAdvisor;  
    }  
}  
  
  
public interface CountryMapper {  
    void show();  
}  
  
  
@Component  
public class CountryMapperImpl implements CountryMapper {  
    //用自定义注解类标注方法,该方法会被自定义方法拦截器进行拦截处理  
    @Log  
    @Override  
    public void show(){  
        System.out.println("invoke show...");  
    }  
}  
  
@SpringBootApplication()  
@RestController  
public class Main{  
    @Autowired  
    private CountryMapper countryMapper;  
      
    public static void main(String[] args){  
        SpringApplication.run(Main.class, args);  
    }  
      
    @GetMapping("/index")  
    public String index(){  
        countryMapper.show();  
        return LocalDateTime.now().toString();  
    }  
}  

Hessian服务调用: MethodInterceptor拦截器、Spring代理、工厂Bean的综合利用案例

        在Spring环境下调用Hessian服务可以通过HessianProxyFactoryBean类实现,HessianProxyFactoryBean类的继承结构如下:

BeanClassLoaderAware  
    RemotingSupport - beanClassLoader  
        RemoteAccessor - serviceInterface  
            UrlBasedRemoteAccessor+MethodInterceptor - serviceUrl  
                HessianClientInterceptor+FactoryBean  
                    HessianProxyFactoryBean  
                        |_ ProxyFactory  

1、通过HessianProxyFactoryBean获取到的对象是Spring的ProxyFactory对象

2、ProxyFactory对象对服务接口进行动态代理

3、调用服务接口的方法时,会被HessianClientInterceptor拦截器进行拦截处理

4、HessianClientInterceptor拦截器中

         通过HessianProxyFactory创建服务接口的代理对象,HessianProxyFactory底层使用JDK动态代理生成代理类

         动态代理对应的Handler类是HessianProxy,其实现InvocationHandler接口

         HessianProxy负责打开HessianConnection,获取HessianOutput,写数据到服务端;然后获取HessianInput,读数据并返回

一 Mybatis拦截器介绍


       Mybatis拦截器设计的初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。通过Mybatis拦截器我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。所以Mybatis拦截器的使用范围是非常广泛的。

       Mybatis里面的核心对象还是比较多,如下:


       Mybatis拦截器并不是每个对象里面的方法都可以被拦截的。Mybatis拦截器只能拦截Executor、ParameterHandler、StatementHandler、ResultSetHandler四个对象里面的方法。

Mybatis的拦截器是通过JDK动态代理实现的,下面通过两部分来讲解。

  • Mybatis的基本实现
  • Mybatis拦截器源码

一.首先讲述下Mybatis拦截器的基本实现

  1. 首先自定义一个拦截器类
@Intercepts(
        {
                @Signature(type= StatementHandler.class ,method = "prepare" ,args = {Connection.class,Integer.class})
        }
)
public class MyInterceptor  implements Interceptor{
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object result = invocation.proceed();
        System.out.println("Invocation.proceed()");
        return result;
    }

    @Override
    public Object plugin(Object o) {
	        return Plugin.wrap(o,this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}

2.在Mybatis的配置文件中注册拦截器(Mybatis-config.xml)

<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <plugins>
        <plugin interceptor="com.example.demo.interceptor.MyInterceptor" />
    </plugins>
</configuration>
注:这里注册的拦截器会以List结果存储


@Intercepts(
        {
                @Signature(type= StatementHandler.class ,method = "prepare" ,args = {Connection.class,Integer.class})
        }
)
注:这个标签声明了自定义拦截器所要拦截的对象方,上面声明了拦截器要拦截StatementHandler对象的prepare方法

二.源码分析Mybatis拦截器

在自定义的拦截器中,该拦截器实现了父类Interceptor的三个方法,其中setProperties

方法获取在配置文件中为该拦截器配置的属性,如果有配置的话。这里主要讲下plugin方法和

intercept方法.plugin方法是在statementHandler对象创建时被调用的,在plugin的方法实

现中,一定要调用Plugin类中的wrap方法,该方法的作用是生成并返回statementHandler

对象的代理类(因为这里要拦截的对象是statementHandler对象)。如果所要拦截对象方法被调用时,代理类会调用自定义拦截器的intercept方法,intercept方法可以实现你所要处理

的逻辑。最后该方法调用innovation.proceed()说明调用所拦截的方法。

下面根据上边所讲加上mybatis的源码加深一下理解

  1. 从statementHandler对象的创建开始

Mybatis 四大对象的创建过程都是在Configuration类中实现的,并且在创建各类对象的过程中会判断配置文件是否注册了该类对象的拦截器,如果注册了该类拦截器,生成的对象是代理对象。

 StatementHandler statementHandler1 = (StatementHandler)this.interceptorChain.pluginAll(statementHandler);
   注:这条语句判断对象是否为所要拦截对象,如果是则返回代理对象,不是则直接返回,下面看下该方法的源码实现
InterceptorChain.Java 
 public Object pluginAll(Object target) {
        Interceptor interceptor;
        for(Iterator var2 = this.interceptors.iterator(); var2.hasNext(); target = interceptor.plugin(target)) {
            interceptor = (Interceptor)var2.next();
        }

        return target;
    }

注:该方法对拦截器链(在配置文件中所注册的拦截器)进行遍历,并调用拦截器中的plugin的方法,target参数为statementHandler对象。上面讲到自定义拦截器的plugin方法在拦截对象创建时被调用的。
并且plugin方法中调用Plugin类的wrap方法。下面我们来看下wrap方法的源码实现

Plugin.java
 public static Object wrap(Object target, Interceptor interceptor) {
        Map signatureMap = getSignatureMap(interceptor);
        Class type = target.getClass();
        Class[] interfaces = getAllInterfaces(type, signatureMap);
        return interfaces.length > 0?Proxy.newProxyInstance(type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)):target;

注:这里根据@Intercepts标签所声明的信息判断statementHandler对象是否为所要拦截的目标对象,如果是,为statementHandler生成一个代理对象并返回,如果不是,则返回该对象。Mybatis是运用JDK的动态代理生成代理对象的(需理解JDK的动态代理)。当返回的是代理对象时,当调用拦截目标对象任何方法,该方法都会调用Plugin类的invoke方法,下面我们来看invoke方法的源码实现

Plugin.java
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            Set e = (Set)this.signatureMap.get(method.getDeclaringClass());
            return e != null && e.contains(method)?this.interceptor.intercept(new Invocation(this.target, method, args)):method.invoke(this.target, args);
        } catch (Exception var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }
    }
 
 注:该方法根据@Inceptors标签所声明的信息判断当前调用的方法是否是所要拦截的方法(这里是prepare方法),如果是,调用自定义拦截器的intercept方法,如果不是,则继续执行该方法(prepare方法)。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot使用Mybatis拦截器,需要进行以下步骤: 1.定义拦截器类,实现MybatisInterceptor接口。 ```java @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}) }) public class MyInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { //拦截逻辑 return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { //设置拦截器属性 } } ``` 2.在Spring Boot的配置文件配置拦截器。 ```yaml mybatis: configuration: #配置拦截器 #注意:mybatis下的configuration属性是Mybatis的Configuration对象,不是Spring Boot的配置文件 #使用Mybatis的配置文件时需要使用mybatis.config-location属性 #使用Spring Boot的配置文件时需要使用mybatis.configuration属性 #两者不能同时使用 plugins: - com.example.MyInterceptor ``` 3.在Mybatis的Mapper接口使用@Intercepts注解指定拦截器。 ```java @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}) }) public interface UserMapper { List<User> selectAll(); } ``` 其,@Intercepts注解用于指定拦截器,@Signature注解用于指定拦截的方法。 总的来说,在Spring Boot使用Mybatis拦截器的过程和在其他环境下使用Mybatis拦截器的过程类似,只需要在Spring Boot的配置文件配置拦截器即可。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值