拦截Mybatis的mapper

jopen 10年前

一、背景

    使用mybatis-spring之后,使用的就是mapper接口,可以直接当传统的DAO来使用,如果在mapper之上又包一层dao的话,则会使开发变得繁琐,改了mapper的xml之后,又得改mapper接口,之后还得改dao,再改service,非常不便利。

 

二、拦截mapper的两种配置

1、使用@Aspect注解

     要去使用jdk的代理,否则代理不了mapper(即mybatis代理的mapper没有默认的构造器,cglib无法再给这个代理构造代理,会报如下错误org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy13]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy13)

<!-- 启动对@Aspectj的支持 true为cglib,false为jdk代理,为true的话,会导致拦截不了mybatis的mapper-->      <aop:aspectj-autoproxy proxy-target-class="false" />

    之后就是使用注解去配置拦截,进行修改记录的操作

@Aspect  @Component  public class DatalogAspect {      private static final Logger logger = LoggerFactory.getLogger(DatalogAspect.class);      @Resource      private ActionMapper actionMapper;      @Pointcut("execution(public * com.yami.infrastructure.repository.mapper.*.insert*(..)) && !execution(public * com.yami.infrastructure.repository.mapper.ActionMapper.insert*(..))")      public void insert(){      }      @Pointcut("execution(public * com.yami.infrastructure.repository.mapper.*.update*(..))")      public void update(){      }      @Pointcut("execution(public * com.yami.infrastructure.repository.mapper.*.delete*(..))")      public void delete(){      }      @Around("insert() || update() || delete()")      public Object addOperateLog(ProceedingJoinPoint pjp) throws Throwable {           ...      }      }

2、使用MethodInterceptor

      使用aopalliance的MethodInterceptor

(1)配置文件

        去掉对@Aspect注解的支持(也可以不去掉,只要不是proxy-target-class = true就可以)。然后配置aop

 <bean id="datalogInterceptor" class="com.yami.infrastructure.datalog.DatalogInterceptor" />      <aop:config>          <aop:pointcut id="datalogInsertPointCut" expression="execution(* com.yami.infrastructure.repository.mapper..insert*(..)) &amp;&amp; !execution(* com.yami.infrastructure.repository.mapper.ActionMapper.*(..))" />          <aop:pointcut id="datalogUpdatePointCut" expression="execution(* com.yami.infrastructure.repository.mapper..update*(..)) &amp;&amp; !execution(* com.yami.infrastructure.repository.mapper.ActionMapper.*(..))" />          <aop:pointcut id="datalogDeletePointCut" expression="execution(* com.yami.infrastructure.repository.mapper..delete*(..)) &amp;&amp; !execution(* com.yami.infrastructure.repository.mapper.ActionMapper.*(..))" />          <aop:advisor advice-ref="datalogInterceptor" pointcut-ref="datalogInsertPointCut" />          <aop:advisor advice-ref="datalogInterceptor" pointcut-ref="datalogUpdatePointCut" />          <aop:advisor advice-ref="datalogInterceptor" pointcut-ref="datalogDeletePointCut" />      </aop:config>

(2)实现MethodInterceptor

public class DatalogInterceptor implements MethodInterceptor{      private static final Logger logger = LoggerFactory.getLogger(DatalogInterceptor.class);      public DatalogInterceptor() {      }      @Resource      private ActionMapper actionMapper;      @Override      public Object invoke(MethodInvocation methodInvocation) throws Throwable {          Method method = methodInvocation.getMethod();          String methodName = method.getName();          Class<?> cls = method.getDeclaringClass();          Object service = methodInvocation.getThis();          Object[] args = methodInvocation.getArguments();          Integer actionType = -1;           ...      }  }

  相比较而言,使用@Aspect注解会比较好用一点(用这个注解/methodInterceptor都拦截不了被同一个类的方法内部调用的方法)

三、注意事项

    1、如果service层有实现接口(比如下载组件的接口),则在其他地方注入的时候必须使用接口声明,否则会报错

    2、拦截mapper,如果使用注解@Aspect ,必须强制使用JDK代理。

      Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理。(建议尽量使用JDK的动态代理)如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。http://www.cnblogs.com/hustyangli/archive/2008/09/01/1281319.html