攔截Mybatis的mapper
一、背景
使用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*(..)) && !execution(* com.yami.infrastructure.repository.mapper.ActionMapper.*(..))" /> <aop:pointcut id="datalogUpdatePointCut" expression="execution(* com.yami.infrastructure.repository.mapper..update*(..)) && !execution(* com.yami.infrastructure.repository.mapper.ActionMapper.*(..))" /> <aop:pointcut id="datalogDeletePointCut" expression="execution(* com.yami.infrastructure.repository.mapper..delete*(..)) && !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