欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

mybatis的Interceptor機制

 更新時間:2023年09月06日 08:34:47   作者:codecraft  
這篇文章主要為大家介紹了mybatis的Interceptor機制源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

本文主要研究一下mybatis的Interceptor機制

Interceptor

org/apache/ibatis/plugin/Interceptor.java

public interface Interceptor {
  Object intercept(Invocation invocation) throws Throwable;
  default Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
  default void setProperties(Properties properties) {
    // NOP
  }
}
Interceptor定義了intercept方法,其參數(shù)為Invocation類型,同時默認提供了plugin方法,通過Plugin.wrap(target, this)進行包裝

Invocation

org/apache/ibatis/plugin/Invocation.java

public class Invocation {
  private final Object target;
  private final Method method;
  private final Object[] args;
  public Invocation(Object target, Method method, Object[] args) {
    this.target = target;
    this.method = method;
    this.args = args;
  }
  public Object getTarget() {
    return target;
  }
  public Method getMethod() {
    return method;
  }
  public Object[] getArgs() {
    return args;
  }
  public Object proceed() throws InvocationTargetException, IllegalAccessException {
    return method.invoke(target, args);
  }
}
Invocation定義了target、method、args屬性,提供了proceed方法則是反射執(zhí)行method方法

Plugin

org/apache/ibatis/plugin/Plugin.java

public class Plugin implements InvocationHandler {
  private final Object target;
  private final Interceptor interceptor;
  private final Map<Class<?>, Set<Method>> signatureMap;
  private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
    this.target = target;
    this.interceptor = interceptor;
    this.signatureMap = signatureMap;
  }
  public static Object wrap(Object target, Interceptor interceptor) {
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    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;
  }
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      Set<Method> methods = signatureMap.get(method.getDeclaringClass());
      if (methods != null && methods.contains(method)) {
        return interceptor.intercept(new Invocation(target, method, args));
      }
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }
  //......
}
Plugin實現(xiàn)了java.lang.reflect.InvocationHandler方法,其invoke方法主要是多了一層判斷,判斷interceptor的signatureMap有沒有包含對應的方法,有則執(zhí)行interceptor.intercept,同時包裝了Invocation參數(shù)傳遞過去
而Plugin的wrap方法則是判斷interceptor有沒有攔截target對應的接口,如果有則通過Proxy.newProxyInstance返回代理對象方便后續(xù)進行攔截

InterceptorChain

org/apache/ibatis/plugin/InterceptorChain.java

public class InterceptorChain {
  private final List<Interceptor> interceptors = new ArrayList<>();
  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }
  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }
  public List<Interceptor> getInterceptors() {
    return Collections.unmodifiableList(interceptors);
  }
}
InterceptorChain定義了interceptors,它提供了pluginAll方法對target代理所有的interceptor

Configuration

org/apache/ibatis/session/Configuration.java

protected final InterceptorChain interceptorChain = new InterceptorChain();
  public void addInterceptor(Interceptor interceptor) {
    interceptorChain.addInterceptor(interceptor);
  }
Configuration定義了interceptorChain,它通過addInterceptor方法往interceptorChain添加interceptor

XMLConfigBuilder

org/apache/ibatis/builder/xml/XMLConfigBuilder.java

private void pluginElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        String interceptor = child.getStringAttribute("interceptor");
        Properties properties = child.getChildrenAsProperties();
        Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor()
            .newInstance();
        interceptorInstance.setProperties(properties);
        configuration.addInterceptor(interceptorInstance);
      }
    }
  }
XMLConfigBuilder在解析xml的plugin的時候,會獲取定義的interceptor,實例化之后通過configuration.addInterceptor添加進去

SqlSessionFactoryBean

org/mybatis/spring/SqlSessionFactoryBean.java

private Interceptor[] plugins;
  public void addPlugins(Interceptor... plugins) {
    setPlugins(appendArrays(this.plugins, plugins, Interceptor[]::new));
  }
  public void setPlugins(Interceptor... plugins) {
    this.plugins = plugins;
  }
  protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
    final Configuration targetConfiguration;
    XMLConfigBuilder xmlConfigBuilder = null;
    if (this.configuration != null) {
      targetConfiguration = this.configuration;
      if (targetConfiguration.getVariables() == null) {
        targetConfiguration.setVariables(this.configurationProperties);
      } else if (this.configurationProperties != null) {
        targetConfiguration.getVariables().putAll(this.configurationProperties);
      }
    } else if (this.configLocation != null) {
      xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
      targetConfiguration = xmlConfigBuilder.getConfiguration();
    } else {
      LOGGER.debug(
          () -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
      targetConfiguration = new Configuration();
      Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
    }
    Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);
    Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);
    Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);
    //......
    if (!isEmpty(this.plugins)) {
      Stream.of(this.plugins).forEach(plugin -> {
        targetConfiguration.addInterceptor(plugin);
        LOGGER.debug(() -> "Registered plugin: '" + plugin + "'");
      });
    }
    if (hasLength(this.typeHandlersPackage)) {
      scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass())
          .filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
          .forEach(targetConfiguration.getTypeHandlerRegistry()::register);
    }
    if (!isEmpty(this.typeHandlers)) {
      Stream.of(this.typeHandlers).forEach(typeHandler -> {
        targetConfiguration.getTypeHandlerRegistry().register(typeHandler);
        LOGGER.debug(() -> "Registered type handler: '" + typeHandler + "'");
      });
    }
    targetConfiguration.setDefaultEnumTypeHandler(defaultEnumTypeHandler);
    //......
    return this.sqlSessionFactoryBuilder.build(targetConfiguration);
  }
SqlSessionFactoryBean的buildSqlSessionFactory方法在判斷plugins不為空時,通過targetConfiguration.addInterceptor(plugin)將interceptor注冊進去

MybatisAutoConfiguration

org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.java

@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {
  private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);
  private final MybatisProperties properties;
  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;
    this.interceptors = interceptorsProvider.getIfAvailable();
    this.typeHandlers = typeHandlersProvider.getIfAvailable();
    this.languageDrivers = languageDriversProvider.getIfAvailable();
    this.resourceLoader = resourceLoader;
    this.databaseIdProvider = databaseIdProvider.getIfAvailable();
    this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
    this.sqlSessionFactoryBeanCustomizers = sqlSessionFactoryBeanCustomizers.getIfAvailable();
  }
  @Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setVfs(SpringBootVFS.class);
    if (StringUtils.hasText(this.properties.getConfigLocation())) {
      factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
    }
    applyConfiguration(factory);
    if (this.properties.getConfigurationProperties() != null) {
      factory.setConfigurationProperties(this.properties.getConfigurationProperties());
    }
    if (!ObjectUtils.isEmpty(this.interceptors)) {
      factory.setPlugins(this.interceptors);
    }
    //......
  }
MybatisAutoConfiguration的sqlSessionFactory方法,在判斷interceptors不為空時,通過SqlSessionFactory的setPlugins方法把interceptors添加進去;MybatisAutoConfiguration標注了@Configuration注解,該注解標注了@Component,因而這些interceptors則是通過構造器從spring中注入的

Configuration.pluginAll

org/apache/ibatis/session/Configuration.java

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject,
      BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,
        parameterObject, boundSql);
    return (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
  }
  public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds,
      ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) {
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler,
        resultHandler, boundSql, rowBounds);
    return (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
  }
  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,
      Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject,
        rowBounds, resultHandler, boundSql);
    return (StatementHandler) interceptorChain.pluginAll(statementHandler);
  }
  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    return (Executor) interceptorChain.pluginAll(executor);
  }

Configuration提供了newParameterHandler、newResultSetHandler、newStatementHandler、newExecutor方法,這些方法會對ParameterHandler、ResultSetHandler、StatementHandler、Executor執(zhí)行interceptorChain.pluginAll方法,則創(chuàng)建作用了所有interceptor的代理對象,從而實現(xiàn)對這些對象的攔截效果

小結

  • mybatis的Interceptor機制使用的是jdk的Proxy.newProxyInstance的方式
  • 在掃描xml的時候把interceptor注冊到configuration中,針對spring的場景,在MybatisAutoConfiguration中注入所有托管的interceptor,之后在構造SqlSessionFactory的時候把interceptor注冊到configuration中
  • 最后Configuration提供了newParameterHandler、newResultSetHandler、newStatementHandler、newExecutor方法,創(chuàng)建作用了所有interceptor的代理對象,從而實現(xiàn)對這些對象的攔截效果

以上就是mybatis的Interceptor機制的詳細內(nèi)容,更多關于mybatis的Interceptor機制的資料請關注腳本之家其它相關文章!

相關文章

  • java獲取日期之間天數(shù)的方法

    java獲取日期之間天數(shù)的方法

    這篇文章主要介紹了java獲取日期之間天數(shù)的方法,涉及java針對日期的轉換與數(shù)學運算相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • Eclipse中配置Maven的圖文教程

    Eclipse中配置Maven的圖文教程

    這篇文章主要介紹了Eclipse中配置Maven的圖文教程,需要的朋友可以參考下
    2020-12-12
  • springboot + swagger 實例代碼

    springboot + swagger 實例代碼

    本篇文章主要介紹了springboot + swagger 實例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Simple Java Mail郵件發(fā)送實現(xiàn)過程解析

    Simple Java Mail郵件發(fā)送實現(xiàn)過程解析

    這篇文章主要介紹了Simple Java Mail郵件發(fā)送實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • javaWeb自定義標簽用法實例詳解

    javaWeb自定義標簽用法實例詳解

    這篇文章主要介紹了javaWeb自定義標簽用法,結合實例形式分析了javaweb自定義標簽的功能、定義方法及執(zhí)行原理,需要的朋友可以參考下
    2017-04-04
  • java實現(xiàn)銀行家算法

    java實現(xiàn)銀行家算法

    這篇文章主要為大家詳細介紹了java實現(xiàn)銀行家算法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • Springboot JPA打印SQL語句及參數(shù)的實現(xiàn)

    Springboot JPA打印SQL語句及參數(shù)的實現(xiàn)

    在SpringBoot項目中調(diào)試和優(yōu)化數(shù)據(jù)庫操作是很常見的需求,本文主要介紹了Springboot JPA打印SQL語句及參數(shù)的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2024-06-06
  • springboot在idea下debug調(diào)試熱部署問題

    springboot在idea下debug調(diào)試熱部署問題

    這篇文章主要介紹了springboot在idea下debug調(diào)試熱部署問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • SpringBoot應用中出現(xiàn)的Full GC問題的場景與解決

    SpringBoot應用中出現(xiàn)的Full GC問題的場景與解決

    這篇文章主要為大家詳細介紹了SpringBoot應用中出現(xiàn)的Full GC問題的場景與解決方法,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-04-04
  • Spring?Cloud?Feign?使用對象參數(shù)的操作

    Spring?Cloud?Feign?使用對象參數(shù)的操作

    這篇文章主要介紹了Spring?Cloud?Feign?如何使用對象參數(shù)的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02

最新評論