构造器模式,就是吃进去配置文件,经过分析,吐出一个复杂对象
动态代理的结构
这一行,是修改虚拟机的参数,把内存中的代理类保存到本地,查看代理类的源代码斜体样式
我在这里捋一下流程
1、读取配置文件
2、创建构造器
3、进入构造器
4、因为我只传了一个配置文件流,所以进入这个构造,但是它会去调用下一个构造(还可以这样玩,学会了)(这样看似形参只写了一个,但是内部确去调用了那个需要三个形参的构造方法)
5、构造完成,返回一个复杂对象,返回去的是用一个deaultSqlSessionFactor接收的
看看5里面做了什么
1、先用他自己的解析配置文件工具 XML ConfigBuild 去解析(这个名字气的真好,一眼就能看懂)
2、那个工具类又去调用了自己的构造方法
2、1这步应该是把所有的配置文件都读进去了
2、2 这三个应该依次是
配置文件流 多数据连接池的唯一id
以及外部引入的数据库连接池信息
2、3开始分析:
3、点进去分析方法
这句话的意思应该是一只读到这里
4、看看这个名字吧,解析配置文件,这起的也太好了把
点进去,这里面的东西,就算属性名,那个绿色的字,我不全认识,但我能明白这是在干什么把
5、最终要的是这两
setting 和 mappers
setting
mapper
通过这个定位映射文件位置
来了,调出新的构造器 来构造mapping 映射文件
XMLMapperBuilder
又是自己调自己的构造,好家伙,还把构造私有了
把配置文件暴风吸入,开始解析
parse()
configurationElenment 解析方法
说白了就是读取标签的值,存进去
就是读取和存的方法比较难而已
增删改查的读取方法 bulidStatementFromContext
啊,调调调,我以为递归呢,居然是调用重载方法
来了,新的构造器 XMLStatementBuilder 用于构造单个接口方法
就是这种接口方法
XMLStatementBuilder 又是老一套 读取 分析
截图太长了
看就看那些字符串的名字,应该就明白是什么属性了把
public void parseStatementNode() {
String id = this.context.getStringAttribute("id");
String databaseId = this.context.getStringAttribute("databaseId");
if (this.databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
String nodeName = this.context.getNode().getNodeName();
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = this.context.getBooleanAttribute("flushCache", !isSelect);
boolean useCache = this.context.getBooleanAttribute("useCache", isSelect);
boolean resultOrdered = this.context.getBooleanAttribute("resultOrdered", false);
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(this.configuration, this.builderAssistant);
includeParser.applyIncludes(this.context.getNode());
String parameterType = this.context.getStringAttribute("parameterType");
Class<?> parameterTypeClass = this.resolveClass(parameterType);
String lang = this.context.getStringAttribute("lang");
LanguageDriver langDriver = this.getLanguageDriver(lang);
this.processSelectKeyNodes(id, parameterTypeClass, langDriver);
String keyStatementId = id + "!selectKey";
keyStatementId = this.builderAssistant.applyCurrentNamespace(keyStatementId, true);
Object keyGenerator;
if (this.configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = this.configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = this.context.getBooleanAttribute("useGeneratedKeys", this.configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType)) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
SqlSource sqlSource = langDriver.createSqlSource(this.configuration, this.context, parameterTypeClass);
StatementType statementType = StatementType.valueOf(this.context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
Integer fetchSize = this.context.getIntAttribute("fetchSize");
Integer timeout = this.context.getIntAttribute("timeout");
String parameterMap = this.context.getStringAttribute("parameterMap");
String resultType = this.context.getStringAttribute("resultType");
Class<?> resultTypeClass = this.resolveClass(resultType);
String resultMap = this.context.getStringAttribute("resultMap");
String resultSetType = this.context.getStringAttribute("resultSetType");
ResultSetType resultSetTypeEnum = this.resolveResultSetType(resultSetType);
if (resultSetTypeEnum == null) {
resultSetTypeEnum = this.configuration.getDefaultResultSetType();
}
String keyProperty = this.context.getStringAttribute("keyProperty");
String keyColumn = this.context.getStringAttribute("keyColumn");
String resultSets = this.context.getStringAttribute("resultSets");
this.builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, (KeyGenerator)keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
}
最后把这个单个接口的所有信息,添加进全局变量 configuratin里面,是小添加
大添加
没了
这里是昨天晚上捋的,就当是细节把
判断子标签是不是 package标签
老师说不让用包映射??说是只能是注解才能用
可以有多种方法指定
现在只有resource 属性
resource url 和 class 只能指定一个
检测文件有没有错,语法之类的,原来可以写一个方法,我要学习一下
得到映射文件的流
又来个构造器,对映射文件解析的XMLMapperBuilder
try {
mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
mapperParser.parse();
把包含从总配置文件里面的读取的comfiguration对象的 传进 XMLMapperBuilder里面了
看好了,我要的是总配置文件里面的值
protected Properties variables 我忘了里面是什么东西了,但应该是所有的配置把;
内部的parse()方法进行解析
resouce应该是这个
XMLMapperBuilder 构造器的出生
XmlConfigBuilder 调用得来的,就是解析完总配置文件,然后去解析映射文件
映射文件 调用 构造器
又他妈的去调 父类的configuration了
这个configuration是从父类里面调用的
跳到这里
我懂了!@!!然后回来开始构造xmlMapperBuilder
public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()), configuration, resource, sqlFragments);
}
private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
super(configuration);
this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
this.parser = parser;
this.sqlFragments = sqlFragments;
this.resource = resource;
}
注意看好了,圆形的那个里面调用的是 父类构造!!! 不是什么赋值,我@@了
这个值相当于在这里走了一圈,难道是更新了值吗?? 贯穿了全局
这句话是解析里面的mapper跟标签,就是里面有很多子标签,这个是外面最大 的根标签
上面那个boolean判断
它为啥用过/ 线啊
点进去看一眼
我懂他是什么意思,但为什么要用 / 啊
搞不懂
拿到了接口的包名类名
上面那些标签不去考虑实现 ,说破了天也不过是赋值,主要看最后一个
最后一个属性
太乱了 bulidStatemetFromContext方法
方法详情
感觉好像传进来了,出了sql语句的mybatis标签,应该就是那些接口实现方法
进到这个方法里面
第三个构造器对象???XMLStatementBulider
用来解析 select insert update delete 四类标签的
那14个增删改查标签,用他来解析
遍历一个一个的解析
辅助建造器对象
里面放一些变量值,比较咋说呢,是个临时的,辅助的《configrutaron对象也在里面???到底要干嘛啊》
context是那个正在遍历的select 标签
进这个方法
获得映射文件里面的方法名字
得到可select标签里面乱起八早的属性
把别名解析成类对象
点进去
类型别名注册器 解析 并返回
sql语句是在这这一步解析的
最后,调用辅助器对象,把单个sql语句映射文件的值赋进去
映射文件方法的参数
这个拼接字符串,不知道干嘛用的
又有构建器
他把那些标签的所有属性
全部传到了构建器里面,通过这些属性,调用build方法,建立了一个对象
这个对象,叫做mappedStatement statement
里面有那个标签方法的全部属性
可以把它也理解成一个容器
存了好的数据啊
构建出来的这个东西
mappedStatement statement 就是这个标签的一切
老师说 mappedStatement statement 是增删改查标签 在内存里面的一个 完整对照
有一个标签,就有一个这个玩意
把标签statement对象 add 进 全局configutation 里面
add 方法
现在知道拼接的那个字符串是干什么的了,原来是用来当做key,NB
’
存到了configuration 这个对象里面了
对不起,我又无知了,我收回我之前说的这个对象简单,只不过是一堆值的集合的那句话,太尼玛复杂了
看看configuration 里面的那个成员变量的值
从头找
从头找
因为不知道,为什么上面那个0那个key 对应的东西有什么用 所以,14*2=28个statement都进来了
这个/ 原来是这个意思
这一行,解析增删改标签的终于走完了,就这一行代码,里面的东西居然这么多
mapping的解析走完了
这个配置文件就,解析完成了
这个if走完是这里
终于走到尽头了
那个build方法,看下面
让DefaultSqlSessionFactory持有 config 就是configuration
这样sqlSessionFactor就有 值了
所有的努力就是为了这一个东西
说白了,就是把所有的配置文件信息都塞到 configuration里面了
总结
构建器 模式
只是一种思想
把对象的构建过程 ,放在这个方法里面来玩了
这个build就是为了构建
就是为了构建这个实现类对象,说白了就是这个成员变量
这种设计模式,老师居然觉得他简单,我真的哭死,23个设计模式,哈哈哈,还架构师呢,我真的,我连增删改查的框架都有点玩不明白了。。。。
加了参数的反编译 代码
这个object数组和我之前弄的好像挺像的
那里像了,这不是一模一样吗,不是这个尚硅谷的老师也太牛逼了吧,学了个springMvc框架,我倒现在都收益呢
Object paraObj = null;
if (name.equals("session")) {
paraObj = req.getSession();
} else if (name.equals("req")) {
paraObj = req;
} else if (name.equals("resp")) {
paraObj = resp;
} else {
para[j] = paraObj;
能看懂这个方法的参数了,就是大反射
toString他重写了
proxy 英 [ˈprɒksi] 他是一个工具类,还是什么
看不懂
我就是想说这个Proxy 不是我创建的,对啊,动态代理不是jdk的功能实现吗,当然不是我NEW出来的类啊
这个Proxy就是JDK自动帮我生成的
居然不能调用proxy的toString方法,会转起来
这玩意不能打印,不能看,可以把这个引用存起来
老师说这个proxy参数有用,但是要写连接池才有用
注意点
1、invoke方法中的proxy参数绝对不能显示调用,因为会转起来
2、被代理的对象,一定要有接口,因为,proxy已经继承了一个类了
他就只能去用Implement 去指定父类了,不能去继承类,只能跟接口,来动态代理
如果不传这个接口
传他的实现类,你猜他能创建动态代理类吗,哈哈哈
不能
我们要做到的目标是
调用eat(),run 仍然执行原对象的方法,调用sleep执行新逻辑
对对对,我就是要学这个
我的代码都归到这里面了,我执行任意代码都走的这里?
卧槽,原来是这么做到
里面的else 是调用之前的方法
因为这个方法的匿名内部类是自带返回值的,就是他必须要返回个东西
invocationHandler 只能返回一个值回去
所以要把方法的返回值返回去
卧槽,虽然这个是反射调用的,但是它居然会真的,进入那个实现类里面去
因为我没有给sleep指定返回值,所以
原来动态代理的原理这么,简单,我应该找个时间练一下的,但是因为我的内耗太严重了,所以,我还是在项目里面去练习把