@Intercepts注解原理(mybatis拦截器)
MybatisAutoConfiguration初始化的时候,会在构造函数收集所有实现Interceptor接口的bean,在初始化SqlSessionFactory时,将Interceptor实例数组传入SqlSessionFactoryBean,再存入SqlSessionFactory的Configuration.interceptorChain,当执行mapper接口方法时,会走到Inter
大致原理
mybatis-spring-boot-autoconfigure.jar
包中,spring.factories
文件配置了MybatisAutoConfiguration
,spring会对其进行自动注入;MybatisAutoConfiguration
初始化的时候,会在构造函数通过ObjectProvider
收集所有实现Interceptor
接口的bean,并在初始化SqlSessionFactory
时(同类下@Bean
方法),将Interceptor
实例数组传入SqlSessionFactoryBean
,然后再存入对应SqlSessionFactory
的Configuration.interceptorChain
,每当有执行mapper接口方法时,都会走到InterceptorChain.pluginAll
方法,在这里形成类似责任链模式的数据结构,pluginAll
方法会遍历所有的Interceptor
实例进行对比,拿到实例修饰的@Intercepts
注解元数据,如果和类型对比一致,就将Interceptor
实例加入该责任链,不一致则不做操作,执行的时候按照责任链顺序执行。
数据结构如下图所示(通过target拿到下一责任链指向):
使用限制
仅支持type为以下类型的拦截:
-
ParameterHandler
-
ResultSetHandler
-
StatementHandler
-
Executor
关键代码
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
初始化执行链:MybatisAutoConfiguration构造函数 -> (@Bean)MybatisAutoConfiguration.sqlSessionFactory() -> SqlSessionFactoryBean.getObject() -> SqlSessionFactoryBean.afterPropertiesSet() -> SqlSessionFactoryBean.buildSqlSessionFactory()
初始化执行部分代码:
/**
* MybatisAutoConfiguration
*/
private final Interceptor[] interceptors;
public MybatisAutoConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider,
ObjectProvider<TypeHandler[]> typeHandlersProvider, ObjectProvider<LanguageDriver[]> languageDriversProvider,
ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider,
ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider,
ObjectProvider<List<SqlSessionFactoryBeanCustomizer>> sqlSessionFactoryBeanCustomizers) {
this.properties = properties;
// 拿到所有的Interceptor实例
this.interceptors = interceptorsProvider.getIfAvailable();
。。。
}
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
。。。
applyConfiguration(factory);
// 将interceptors赋值到SqlSessionFactoryBean
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
。。。
return factory.getObject();
}
/**
* SqlSessionFactoryBean
*/
@Override
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
// 手动调用afterPropertiesSet()
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
@Override
public void afterPropertiesSet() throws Exception {
。。。
// 调用同类下方法
this.sqlSessionFactory = buildSqlSessionFactory();
}
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
final Configuration targetConfiguration;
。。。
// 将Interceptor实例加入Configuration中
if (!isEmpty(this.plugins)) {
Stream.of(this.plugins).forEach(plugin -> {
targetConfiguration.addInterceptor(plugin);
LOGGER.debug(() -> "Registered plugin: '" + plugin + "'");
});
}
。。。
return this.sqlSessionFactoryBuilder.build(targetConfiguration);
}
/**
* Configuration
*/
protected final InterceptorChain interceptorChain = new InterceptorChain();
public void addInterceptor(Interceptor interceptor) {
interceptorChain.addInterceptor(interceptor);
}
/**
* InterceptorChain
*/
private final List<Interceptor> interceptors = new ArrayList<>();
public void addInterceptor(Interceptor interceptor) {
// 可以看到这里实际上就是个Interceptor的集合
interceptors.add(interceptor);
}
mapper接口执行相关代码
/**
* InterceptorChain
*/
// target的类型可能是:ParameterHandler、ResultSetHandler、StatementHandler、Executor
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
/*
* 判断拦截器是否符合注解配置,如果符合则返回一个代理对象
* 并将代理对象赋值到target,在下一次循环中将target重新传入方法
* 这样形成代理对象套代理对象的情况,形成类似责任链模式的数据结构
*/
target = interceptor.plugin(target);
}
return target;
}
/**
* Interceptor
*/
default Object plugin(Object target) {
// 将target和自身作为参数
return Plugin.wrap(target, this);
}
/**
* Plugin
*/
public static Object wrap(Object target, Interceptor interceptor) {
// 获取实例修饰的@Intercepts注解元数据
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
// 获取target的class
Class<?> type = target.getClass();
// 判断拦截器是否符合注解配置
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
// 有则返回一个代理对象
if (interfaces.length > 0) {
return Proxy.newProxyInstance(type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap));
}
// 不做操作,直接返回
return target;
}
private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
Set<Class<?>> interfaces = new HashSet<>();
while (type != null) {
// 获取type的Interface
for (Class<?> c : type.getInterfaces()) {
// 这里是过滤的重点,判断注解元数据是否配置该类型,如Executor
if (signatureMap.containsKey(c)) {
// 如果有则加入返回结果集
interfaces.add(c);
}
}
// 没有则尝试在type的父类中寻找
type = type.getSuperclass();
}
return interfaces.toArray(new Class<?>[0]);
}

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐
所有评论(0)