mybatis插件:2.执行源码分析

一.加载配置文件;
说明:
1.将xml配置文件转成输入流对象;
2.将输入流对象转成Doucment(其实本质也是Node)文档对象;
3.从文档对象中拿到configuration(mybatis所有的配置对象) 对象Node节点对象;
4.从configuration节点对象中解析plugins子Node节点配置;

1.将XML文件转成输入流对象

启动类
String resource = "org/apache/ibatis/Amy/mybatis-config.xml";//"mybatis-config.xml"
InputStream inputStream = Resources.getResourceAsStream(resource);

最终调用 jdk中的Url类,读取路径转成输入流对象;

Url类
public final InputStream openStream() throws java.io.IOException {
    return openConnection().getInputStream();
}

2.将输入流对象转成Doucment文档(节点)对象
SqlSessionFactoryBuilder 根据输入流对象转成Doucment对象;

SqlSessionFactoryBuilder类

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
	 //根据输入流对象去创建
  XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
  //通过 Configuration 对象 解析获取  SqlSessionFactory sql回话工厂类;
  return build(parser.parse());
} catch (Exception e) {
  throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
  ErrorContext.instance().reset();
  try {
    inputStream.close();
  } catch (IOException e) {
    // Intentionally ignore. Prefer previous error.
  }
 }
}

在new XMLConfigBuilder()构造方法中创建Doucment对象;

public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
//初始化本类的 ,因为这里的参数在构造方法的时候可以手动设置
//private boolean validation;
// private EntityResolver entityResolver;
// private Properties variables;
//private XPath xpath; 这个几个字段 
commonConstructor(validation, variables, entityResolver);
//new InputSource(inputStream) 代码将输入流类型变成字节流类型
//重点是createDocument 该方法拿到 Document 给本类赋值Document字段赋值
this.document = createDocument(new InputSource(inputStream));
}

3.从文档对象中拿到configuration(mybatis所有的配置对象) 对象Node节点对象;

SqlSessionFactory 类
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
	 //根据输入流对象去创建
  XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
  //通过 Configuration 对象 解析获取  SqlSessionFactory sql回话工厂类;
  //parser.parse() 就是去解析Doucment对象;
  return build(parser.parse());
} catch (Exception e) {
  throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
  ErrorContext.instance().reset();
  try {
    inputStream.close();
  } catch (IOException e) {
    // Intentionally ignore. Prefer previous error.
  }
}
}

XMLConfigBuilder 解析
public Configuration parse() {
  //针对  mybatis整体 的配置文件mybatis-config 只能被加载解析一次,加载多次就会抛出异常;
if (parsed) {
  throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// 特别说明:1. XNode  节点对象是mybatis 自定义的对象, XNode对象中包含了 Node 节点对象 ,也包含了 XPathParser 对象
//1. Document 也是Node节点对象的一个子类,
//从之前存储xml对应的字节流转换成了 XPathParser 对象中 Document 字段中
// 调用XPathParser类(包好了Document对象,在之前对xml的解析中转成了Document对象)evalNode根据 configuration 字符串获取到
// Document 对象中存储的  configuration 节点锁包含的所有数据, 说明configuration 节点是所有配置文件总的父节点,所以解析
// configuration  就是解析整个配置文件/解析全局的配置文件;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}

通过核心配置文件对应的Doucment对象,以及根据Document下面一级节点的名称,获取一级节点对象;这个一级节点对象被封装在XNode对象中;

public XNode evalNode(String expression) {
return evalNode(document, expression);
}

parseConfiguration方法解析 configuration 节点下面所有的配置信息(包括插件配置);

private void parseConfiguration(XNode root) {
try {
  //解析config.xml配置文件中configuration最大父节点中的configuration节点数据
  propertiesElement(root.evalNode("properties"));
  //解析和configuration节点平级的节点
  Properties settings = settingsAsProperties(root.evalNode("settings"));
  //加载VFS对象的数据
  loadCustomVfs(settings);
  loadCustomLogImpl(settings);
  typeAliasesElement(root.evalNode("typeAliases"));
  //这里就在解析插件节点对象plugins;
  pluginElement(root.evalNode("plugins"));
  objectFactoryElement(root.evalNode("objectFactory"));
  objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
  reflectorFactoryElement(root.evalNode("reflectorFactory"));
  settingsElement(settings);
  // read it after objectFactory and objectWrapperFactory issue #631
  environmentsElement(root.evalNode("environments"));
  databaseIdProviderElement(root.evalNode("databaseIdProvider"));
  typeHandlerElement(root.evalNode("typeHandlers"));
  mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
  throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}

4.从configuration节点对象中解析plugins子Node节点配置;
pluginElement(root.evalNode(“plugins”)); 拿到插件节点对象,并且解析插件节点的信息;

private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
	//因为可以配置多个plugin ,所以这里是可以循环,来解析每一个plugin 对象;
  for (XNode child : parent.getChildren()) {
	  //获取  <plugin interceptor="org.apache.ibatis.Amy.plugin.ConfigPlugin"> 标签中的  interceptor 属性的值,也就是获取
	  //插件的 相对路径
    String interceptor = child.getStringAttribute("interceptor");
    Properties properties = child.getChildrenAsProperties();
    // 通过拿到类的的路径,通过反射获取到 Interceptor 接口的实例,也就是 这里说的 plugin 对象;
    Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
    //这里给Interceptor 对象中的 Properties 字段做赋值,也就是拿到 xml配置文件中的
    //eg  <property name="someProperty" value="100"/>  配置信息,给property 字段赋值;
    interceptorInstance.setProperties(properties);
    //将所有的插件对象都存入 InterceptorChain对象中的list集合中;
    // TODO 为啥不放在 Map集合中;
    configuration.addInterceptor(interceptorInstance);
  }
}
}

此方法执行完,插件相关的信息(其实主要是插件类对象信息,已经插件类对象中封装的参数信息;这里并没有加载插件类对象上的注解相关的信息)

二.获取到相应的代理对象(Executor,ParameterHandler,ResultSetHandler,StatementHandler)
以Executor对象的"query"方法做为例子,获取代理对象;

1.通过sqlSessionFactory对象获取 Sqlsession对象;

SqlSession session = sqlSessionFactory.openSession();

2.通过DefaultSqlSessionFactory初始化DefaultSqlSession对象的时候

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
  final Environment environment = configuration.getEnvironment();
  //TransactionFactory 对象是 Environment对象
  //通过 Environment 环境对象获取  TransactionFactory 获取事物工厂类
  final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
  //建造者模式,通过 TransactionFactory 事物工厂来创建事物对象
  //通过 事物工厂类 以及 环境对象 再去创建 事物对象,
  // 这里的是否开启事物是由上层调用的方法来决定的;
  tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
  //在这一步获取 执行器对象,获取获取执行器对象的代理对象;
  final Executor executor = 
  configuration.newExecutor(tx, execType);
  return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) { // 132 4782 3106
  closeTransaction(tx); // may have fetched a connection so lets call close()
  throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
} finally {
  ErrorContext.instance().reset();
}
}

3.初始化执行器对象(获取该对象的代理对象)(因为化执行器是SqlSession对象的一个构造参数)

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : 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);
}
//1.关于这段代码为啥要执行,只能说是上一步的代码需要构建 SQL执行之前的DefaultSqlSession 对象的,
// 这段的执行就是为了构建 DefaultSqlSession 对象中的 Executor对象,构建DefaultSqlSession 的时候不用太关心Executor 是代理对象,
//还是原生对象;  
//2.当还没有走过下面这段代码的时候,executor 一定是一个原生对象,当走过下段代码的时候executor对象就有可能是代理对象;
//是否是代理对象,取决于是否自定义了插件对象;
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}

4.判断执行器对象是否需要做代理;

//遍历所有的插件对象,可能多个插件会针对同一个对象的同一个方法都做了操作
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
  target = interceptor.plugin(target);
}
return target;
}

//到了具体的plugin插件对象中,做代理的植入操作
public Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }

5.通过JDK代理拿到执行对象的代理对象;

public static Object wrap(Object target, Interceptor interceptor) {
//获取一个自定义插件对象下,@Signature数组中的数据
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
//根据目标对象,拿signatureMap对象,判断signatureMap的key是否包含了目标对象实现的接口对象;
//并返回,signatureMap中包含的目标对象的接口对象;
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
//大于0就说明需要被代理;
if (interfaces.length > 0) { 	
	//下面就是走的JDK代理;
  return Proxy.newProxyInstance(
		  //获取被代理对象的类加载器
      type.getClassLoader(),
      //传入被代理对象的接口
      interfaces,
      //Plugin 是InvocationHandler 的一个实例,代理执行任何操作的时候都会去执行InvocationHandler 类的 handler
      new Plugin(target, interceptor, signatureMap));
}
//将 @Intercepts({@Signature(type= Executor.class, 注解中其实也就是被切入对象  Executor的代理对象返回
return target;
}

6.执行器的代理对象执行Query方法;

@Override
 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
  MappedStatement ms = configuration.getMappedStatement(statement);
  logger.error(ms.toString());
  // 如果有自定义插件 刚好是对executor对象做了处理,那么这边的query 方法的调用,可能就是到代理对象Plugin对象中的方法了。
  return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  //有插件针对executor 的时候executor.对象是代理对象,和没有插件针对executor 的时候,这里就是executor原对象
} catch (Exception e) {
  throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
} finally {
  ErrorContext.instance().reset();
}
}

7.InvocationHandler类的实例会对Executor执行器对象任何方法的执行都用 invoke 方法 做拦截;

拦截到了信息都有:代理类对象,拦截时候代理类对象执行的方法;以及被拦截的方法的参数列表

 /**
 *   
 只要 代理对象执行了任意一个方法,那么就都会走到这里来;然后再根据 InvocationHandler 对象中保存的数据 signatureMap中的需要具体做处理的方法名称;看传递过    来的方法是否在这个集合中,如果在那么就做去调用
 插件的intercept方法;如果不在那么就走方法的正常流程;
 
 */
 @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
	//拿到被拦截方法所在类(也就是被代理的类)的字节码对象,
	//被代理的类的字节码对象从signatureMap获取到具体由哪些方法是需要做处理;
  Set<Method> methods = signatureMap.get(method.getDeclaringClass());
  //判断被拦截的方法是否在这个需要被处理的方法集合中。
  //如果是的:1.就去执行,这个插件对应中的 intercept方法;2.把拦截到的方法执行的参数列表也传递过去(可以有更多的
 // 功能操作);
  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);
}
}

8.执行插件的中的方法;

@Override
public Object intercept(Invocation invocation) throws Throwable {
	log.error("在具体方法之前执行");
	Object returnObject = invocation.proceed();
	log.error("在具体方法之后执行");
	return returnObject;
}

9.插件中的方法调用查询方法(在方法之前需要被处理的方法);

public Object proceed() throws InvocationTargetException, IllegalAccessException {
return method.invoke(target, args);
}

10.代理对象执行query方法做查询操作(query方法就是原对象中的方法);

@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
//以   select * from user where id = ? 为例子
//参数是{"parameterMappings":[{"javaType":"java.lang.Long","mode":"IN","property":"id","typeHandler":{"rawType":"java.lang.Long"}}],
//"parameterObject":1,"sql":"select * from user where id = ?"}
//BoundSql存储的是每个参数的隐射关系,已经这个SQL 解析之后的长字符串

logger.error("BoundSql对象中的数据是:"+MethodTest.getSting(boundSql));
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

11.方法后置逻辑处理

 执行query操作是在插件的intercept方法中,所以query方法返回的时候肯定还要再回到插件的 intercept 方法中,然后再去执行后置方法;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VR(Virtual Reality)即虚拟现实,是一种可以创建和体验虚拟世界的计算机技术。它利用计算机生成一种模拟环境,是一种多源信息融合的、交互式的三维动态视景和实体行为的系统仿真,使用户沉浸到该环境中。VR技术通过模拟人的视觉、听觉、触觉等感觉器官功能,使人能够沉浸在计算机生成的虚拟境界中,并能够通过语言、手势等自然的方式与之进行实时交互,创建了一种适人化的多维信息空间。 VR技术具有以下主要特点: 沉浸感:用户感到作为主角存在于模拟环境中的真实程度。理想的模拟环境应该使用户难以分辨真假,使用户全身心地投入到计算机创建的三维虚拟环境中,该环境中的一切看上去是真的,听上去是真的,动起来是真的,甚至闻起来、尝起来等一切感觉都是真的,如同在现实世界中的感觉一样。 交互性:用户对模拟环境内物体的可操作程度和从环境得到反馈的自然程度(包括实时性)。例如,用户可以用手去直接抓取模拟环境中虚拟的物体,这时手有握着东西的感觉,并可以感觉物体的重量,视野中被抓的物体也能立刻随着手的移动而移动。 构想性:也称想象性,指用户沉浸在多维信息空间中,依靠自己的感知和认知能力获取知识,发挥主观能动性,寻求解答,形成新的概念。此概念不仅是指观念上或语言上的创意,而且可以是指对某些客观存在事物的创造性设想和安排。 VR技术可以应用于各个领域,如游戏、娱乐、教育、医疗、军事、房地产、工业仿真等。随着VR技术的不断发展,它正在改变人们的生活和工作方式,为人们带来全新的体验。
VR(Virtual Reality)即虚拟现实,是一种可以创建和体验虚拟世界的计算机技术。它利用计算机生成一种模拟环境,是一种多源信息融合的、交互式的三维动态视景和实体行为的系统仿真,使用户沉浸到该环境中。VR技术通过模拟人的视觉、听觉、触觉等感觉器官功能,使人能够沉浸在计算机生成的虚拟境界中,并能够通过语言、手势等自然的方式与之进行实时交互,创建了一种适人化的多维信息空间。 VR技术具有以下主要特点: 沉浸感:用户感到作为主角存在于模拟环境中的真实程度。理想的模拟环境应该使用户难以分辨真假,使用户全身心地投入到计算机创建的三维虚拟环境中,该环境中的一切看上去是真的,听上去是真的,动起来是真的,甚至闻起来、尝起来等一切感觉都是真的,如同在现实世界中的感觉一样。 交互性:用户对模拟环境内物体的可操作程度和从环境得到反馈的自然程度(包括实时性)。例如,用户可以用手去直接抓取模拟环境中虚拟的物体,这时手有握着东西的感觉,并可以感觉物体的重量,视野中被抓的物体也能立刻随着手的移动而移动。 构想性:也称想象性,指用户沉浸在多维信息空间中,依靠自己的感知和认知能力获取知识,发挥主观能动性,寻求解答,形成新的概念。此概念不仅是指观念上或语言上的创意,而且可以是指对某些客观存在事物的创造性设想和安排。 VR技术可以应用于各个领域,如游戏、娱乐、教育、医疗、军事、房地产、工业仿真等。随着VR技术的不断发展,它正在改变人们的生活和工作方式,为人们带来全新的体验。
基于GPT-SoVITS的视频剪辑快捷配音工具 GPT, 通常指的是“Generative Pre-trained Transformer”(生成式预训练转换器),是一个在自然语言处理(NLP)领域非常流行的深度学习模型架构。GPT模型由OpenAI公司开发,并在多个NLP任务上取得了显著的性能提升。 GPT模型的核心是一个多层Transformer解码器结构,它通过在海量的文本数据上进行预训练来学习语言的规律。这种预训练方式使得GPT模型能够捕捉到丰富的上下文信息,并生成流畅、自然的文本。 GPT模型的训练过程可以分为两个阶段: 预训练阶段:在这个阶段,模型会接触到大量的文本数据,并通过无监督学习的方式学习语言的结构和规律。具体来说,模型会尝试预测文本序列中的下一个词或短语,从而学习到语言的语法、语义和上下文信息。 微调阶段(也称为下游任务训练):在预训练完成后,模型会被应用到具体的NLP任务中,如文本分类、机器翻译、问答系统等。在这个阶段,模型会使用有标签的数据进行微调,以适应特定任务的需求。通过微调,模型能够学习到与任务相关的特定知识,并进一步提高在该任务上的性能。 GPT模型的优势在于其强大的生成能力和对上下文信息的捕捉能力。这使得GPT模型在自然语言生成、文本摘要、对话系统等领域具有广泛的应用前景。同时,GPT模型也面临一些挑战,如计算资源消耗大、训练时间长等问题。为了解决这些问题,研究人员不断提出新的优化方法和扩展模型架构,如GPT-2、GPT-3等,以进一步提高模型的性能和效率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值