mybatis源码阅读-初始化六个工具(六)
六个基本工具图集
图片来源:https://my.oschina.net/zudajun/blog/668596

ObjectFactory
类图

接口定义
public interface ObjectFactory {
void setProperties(Properties var1);
<T> T create(Class<T> var1);
<T> T create(Class<T> var1, List<Class<?>> var2, List<Object> var3);
<T> boolean isCollection(Class<T> var1);
}
使用方式
ObjectFactory objectFactory=new DefaultObjectFactory();
List<Classes> classesList=objectFactory.create(ArrayList.class);
Classes classes = objectFactory.create(Classes.class);
classes.setName("一年级");
classesList.add(classes);
DefaultObjectFactory
比较简单 我们可以直接拿来自己使用
public class DefaultObjectFactory implements ObjectFactory, Serializable {
private static final long serialVersionUID = -8855120656740914948L;
public DefaultObjectFactory() {
}
/**
* 创建指定类型的对象 不使用构造函数创建
* @param type 类型
* @param <T>
* @return
*/
public <T> T create(Class<T> type) {
return this.create(type, (List)null, (List)null);
}
/**
* 创建指定类型的对象
* @param type 类型
* @param constructorArgTypes 构造函数参数类型列表
* @param constructorArgs 构造函数参数列表
* @param <T>
* @return
*/
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
Class<?> classToCreate = this.resolveInterface(type);
return this.instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
}
public void setProperties(Properties properties) {
}
<T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
try {
Constructor constructor;
//判断是否指定了构造函数初始化
if (constructorArgTypes != null && constructorArgs != null) {
//获得private或public指定参数类型列表的构造函数 注:getConstructor和getDeclaredConstructor的区别是只能获得public
constructor = type.getDeclaredConstructor((Class[])constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
//如果是私有的 设置可以访问
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
} else {
constructor = type.getDeclaredConstructor();
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance();
}
} catch (Exception var9) {
StringBuilder argTypes = new StringBuilder();
if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) {
Iterator i$ = constructorArgTypes.iterator();
while(i$.hasNext()) {
Class<?> argType = (Class)i$.next();
argTypes.append(argType.getSimpleName());
argTypes.append(",");
}
argTypes.deleteCharAt(argTypes.length() - 1);
}
StringBuilder argValues = new StringBuilder();
if (constructorArgs != null && !constructorArgs.isEmpty()) {
Iterator i$ = constructorArgs.iterator();
while(i$.hasNext()) {
Object argValue = i$.next();
argValues.append(String.valueOf(argValue));
argValues.append(",");
}
argValues.deleteCharAt(argValues.length() - 1);
}
throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + var9, var9);
}
}
/**
* 如果是定义结合类型 类型改为实现类
* @param type
* @return
*/
protected Class<?> resolveInterface(Class<?> type) {
Class classToCreate;
if (type != List.class && type != Collection.class && type != Iterable.class) {
if (type == Map.class) {
classToCreate = HashMap.class;
} else if (type == SortedSet.class) {
classToCreate = TreeSet.class;
} else if (type == Set.class) {
classToCreate = HashSet.class;
} else {
classToCreate = type;
}
} else {
classToCreate = ArrayList.class;
}
return classToCreate;
}
public <T> boolean isCollection(Class<T> type) {
return Collection.class.isAssignableFrom(type);
}
}
ReflectorFactory
作用
创建reflector并缓存起来
类图

接口定义
public interface ReflectorFactory {
boolean isClassCacheEnabled();
void setClassCacheEnabled(boolean var1);
Reflector findForClass(Class<?> var1);
}
DefaultReflectorFactory
public class DefaultReflectorFactory implements ReflectorFactory {
private boolean classCacheEnabled = true;
//将反射的元数据信息封装保存到Reflector 大大提交了性能
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap();
public DefaultReflectorFactory() {
}
public boolean isClassCacheEnabled() {
return this.classCacheEnabled;
}
public void setClassCacheEnabled(boolean classCacheEnabled) {
this.classCacheEnabled = classCacheEnabled;
}
/**
* 获得指定类型反射元数据信息
* @param type
* @return
*/
public Reflector findForClass(Class<?> type) {
if (this.classCacheEnabled) {
Reflector cached = (Reflector)this.reflectorMap.get(type);
//如果没有缓存则从缓存里面拿
if (cached == null) {
cached = new Reflector(type);
this.reflectorMap.put(type, cached);
}
return cached;
} else {
return new Reflector(type);
}
}
}
Reflector
作用
封装反射的元数据信息
源码
public class Reflector {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private Class<?> type;
private String[] readablePropertyNames;
private String[] writeablePropertyNames;
private Map<String, Invoker> setMethods;
private Map<String, Invoker> getMethods;
private Map<String, Class<?>> setTypes;
private Map<String, Class<?>> getTypes;
private Constructor<?> defaultConstructor;
private Map<String, String> caseInsensitivePropertyMap;
/**
* 初始化并将对应的元数据信息封装起来
* @param clazz
*/
public Reflector(Class<?> clazz) {
this.readablePropertyNames = EMPTY_STRING_ARRAY;
this.writeablePropertyNames = EMPTY_STRING_ARRAY;
//初始化几个map
this.setMethods = new HashMap();
this.getMethods = new HashMap();
this.setTypes = new HashMap();
this.getTypes = new HashMap();
this.caseInsensitivePropertyMap = new HashMap();
this.type = clazz;
//反射查找默认构造函数到defaultConstructor
this.addDefaultConstructor(clazz);
//反射获得所有的get方法元数据保存到以Invoker保存getMethods
this.addGetMethods(clazz);
//反射获得所有的set方法元数据以invokersetMethods
this.addSetMethods(clazz);
//反射获得所有的Fields元数据
this.addFields(clazz);
this.readablePropertyNames = (String[])this.getMethods.keySet().toArray(new String[this.getMethods.keySet().size()]);
this.writeablePropertyNames = (String[])this.setMethods.keySet().toArray(new String[this.setMethods.keySet().size()]);
String[] arr$ = this.readablePropertyNames;
int len$ = arr$.length;
int i$;
String propName;
for(i$ = 0; i$ < len$; ++i$) {
propName = arr$[i$];
this.caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
arr$ = this.writeablePropertyNames;
len$ = arr$.length;
for(i$ = 0; i$ < len$; ++i$) {
propName = arr$[i$];
this.caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
private void addDefaultConstructor(Class<?> clazz) {
Constructor<?>[] consts = clazz.getDeclaredConstructors();
Constructor[] arr$ = consts;
int len$ = consts.length;
for(int i$ = 0; i$ < len$; ++i$) {
Constructor<?> constructor = arr$[i$];
if (constructor.getParameterTypes().length == 0) {
if (canAccessPrivateMethods()) {
try {
constructor.setAccessible(true);
} catch (Exception var8) {
;
}
}
if (constructor.isAccessible()) {
this.defaultConstructor = constructor;
}
}
}
}
private void addGetMethods(Class<?> cls) {
Map<String, List<Method>> conflictingGetters = new HashMap();
Method[] methods = this.getClassMethods(cls);
Method[] arr$ = methods;
int len$ = methods.length;
for(int i$ = 0; i$ < len$; ++i$) {
Method method = arr$[i$];
String name = method.getName();
if (name.startsWith("get") && name.length() > 3) {
if (method.getParameterTypes().length == 0) {
name = PropertyNamer.methodToProperty(name);
this.addMethodConflict(conflictingGetters, name, method);
}
} else if (name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0) {
name = PropertyNamer.methodToProperty(name);
this.addMethodConflict(conflictingGetters, name, method);
}
}
this.resolveGetterConflicts(conflictingGetters);
}
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
Iterator i$ = conflictingGetters.keySet().iterator();
while(true) {
while(i$.hasNext()) {
String propName = (String)i$.next();
List<Method> getters = (List)conflictingGetters.get(propName);
Iterator<Method> iterator = getters.iterator();
Method firstMethod = (Method)iterator.next();
if (getters.size() == 1) {
this.addGetMethod(propName, firstMethod);
} else {
Method getter = firstMethod;
Class getterType = firstMethod.getReturnType();
while(iterator.hasNext()) {
Method method = (Method)iterator.next();
Class<?> methodType = method.getReturnType();
if (methodType.equals(getterType)) {
throw new ReflectionException("Illegal overloaded getter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ". This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
}
if (!methodType.isAssignableFrom(getterType)) {
if (!getterType.isAssignableFrom(methodType)) {
throw new ReflectionException("Illegal overloaded getter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ". This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
}
getter = method;
getterType = methodType;
}
}
this.addGetMethod(propName, getter);
}
}
return;
}
}
private void addGetMethod(String name, Method method) {
if (this.isValidPropertyName(name)) {
this.getMethods.put(name, new MethodInvoker(method));
Type returnType = TypeParameterResolver.resolveReturnType(method, this.type);
this.getTypes.put(name, this.typeToClass(returnType));
}
}
private void addSetMethods(Class<?> cls) {
Map<String, List<Method>> conflictingSetters = new HashMap();
Method[] methods = this.getClassMethods(cls);
Method[] arr$ = methods;
int len$ = methods.length;
for(int i$ = 0; i$ < len$; ++i$) {
Method method = arr$[i$];
String name = method.getName();
if (name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) {
name = PropertyNamer.methodToProperty(name);
this.addMethodConflict(conflictingSetters, name, method);
}
}
this.resolveSetterConflicts(conflictingSetters);
}
private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method) {
List<Method> list = (List)conflictingMethods.get(name);
if (list == null) {
list = new ArrayList();
conflictingMethods.put(name, list);
}
((List)list).add(method);
}
private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {
Iterator i$ = conflictingSetters.keySet().iterator();
while(true) {
while(i$.hasNext()) {
String propName = (String)i$.next();
List<Method> setters = (List)conflictingSetters.get(propName);
Method firstMethod = (Method)setters.get(0);
if (setters.size() == 1) {
this.addSetMethod(propName, firstMethod);
} else {
Class<?> expectedType = (Class)this.getTypes.get(propName);
if (expectedType == null) {
throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ". This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
}
Iterator<Method> methods = setters.iterator();
Method setter = null;
while(methods.hasNext()) {
Method method = (Method)methods.next();
if (method.getParameterTypes().length == 1 && expectedType.equals(method.getParameterTypes()[0])) {
setter = method;
break;
}
}
if (setter == null) {
throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ". This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
}
this.addSetMethod(propName, setter);
}
}
return;
}
}
private void addSetMethod(String name, Method method) {
if (this.isValidPropertyName(name)) {
this.setMethods.put(name, new MethodInvoker(method));
Type[] paramTypes = TypeParameterResolver.resolveParamTypes(method, this.type);
this.setTypes.put(name, this.typeToClass(paramTypes[0]));
}
}
private Class<?> typeToClass(Type src) {
Class<?> result = null;
if (src instanceof Class) {
result = (Class)src;
} else if (src instanceof ParameterizedType) {
result = (Class)((ParameterizedType)src).getRawType();
} else if (src instanceof GenericArrayType) {
Type componentType = ((GenericArrayType)src).getGenericComponentType();
if (componentType instanceof Class) {
result = Array.newInstance((Class)componentType, 0).getClass();
} else {
Class<?> componentClass = this.typeToClass(componentType);
result = Array.newInstance(componentClass, 0).getClass();
}
}
if (result == null) {
result = Object.class;
}
return result;
}
private void addFields(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
Field[] arr$ = fields;
int len$ = fields.length;
for(int i$ = 0; i$ < len$; ++i$) {
Field field = arr$[i$];
if (canAccessPrivateMethods()) {
try {
field.setAccessible(true);
} catch (Exception var8) {
;
}
}
if (field.isAccessible()) {
if (!this.setMethods.containsKey(field.getName())) {
int modifiers = field.getModifiers();
if (!Modifier.isFinal(modifiers) || !Modifier.isStatic(modifiers)) {
this.addSetField(field);
}
}
if (!this.getMethods.containsKey(field.getName())) {
this.addGetField(field);
}
}
}
if (clazz.getSuperclass() != null) {
this.addFields(clazz.getSuperclass());
}
}
private void addSetField(Field field) {
if (this.isValidPropertyName(field.getName())) {
this.setMethods.put(field.getName(), new SetFieldInvoker(field));
Type fieldType = TypeParameterResolver.resolveFieldType(field, this.type);
this.setTypes.put(field.getName(), this.typeToClass(fieldType));
}
}
private void addGetField(Field field) {
if (this.isValidPropertyName(field.getName())) {
this.getMethods.put(field.getName(), new GetFieldInvoker(field));
Type fieldType = TypeParameterResolver.resolveFieldType(field, this.type);
this.getTypes.put(field.getName(), this.typeToClass(fieldType));
}
}
private boolean isValidPropertyName(String name) {
return !name.startsWith("$") && !"serialVersionUID".equals(name) && !"class".equals(name);
}
private Method[] getClassMethods(Class<?> cls) {
Map<String, Method> uniqueMethods = new HashMap();
for(Class currentClass = cls; currentClass != null; currentClass = currentClass.getSuperclass()) {
this.addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());
Class<?>[] interfaces = currentClass.getInterfaces();
Class[] arr$ = interfaces;
int len$ = interfaces.length;
for(int i$ = 0; i$ < len$; ++i$) {
Class<?> anInterface = arr$[i$];
this.addUniqueMethods(uniqueMethods, anInterface.getMethods());
}
}
Collection<Method> methods = uniqueMethods.values();
return (Method[])methods.toArray(new Method[methods.size()]);
}
private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {
Method[] arr$ = methods;
int len$ = methods.length;
for(int i$ = 0; i$ < len$; ++i$) {
Method currentMethod = arr$[i$];
if (!currentMethod.isBridge()) {
String signature = this.getSignature(currentMethod);
if (!uniqueMethods.containsKey(signature)) {
if (canAccessPrivateMethods()) {
try {
currentMethod.setAccessible(true);
} catch (Exception var9) {
;
}
}
uniqueMethods.put(signature, currentMethod);
}
}
}
}
private String getSignature(Method method) {
StringBuilder sb = new StringBuilder();
Class<?> returnType = method.getReturnType();
if (returnType != null) {
sb.append(returnType.getName()).append('#');
}
sb.append(method.getName());
Class<?>[] parameters = method.getParameterTypes();
for(int i = 0; i < parameters.length; ++i) {
if (i == 0) {
sb.append(':');
} else {
sb.append(',');
}
sb.append(parameters[i].getName());
}
return sb.toString();
}
private static boolean canAccessPrivateMethods() {
try {
SecurityManager securityManager = System.getSecurityManager();
if (null != securityManager) {
securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));
}
return true;
} catch (SecurityException var1) {
return false;
}
}
public Class<?> getType() {
return this.type;
}
public Constructor<?> getDefaultConstructor() {
if (this.defaultConstructor != null) {
return this.defaultConstructor;
} else {
throw new ReflectionException("There is no default constructor for " + this.type);
}
}
public boolean hasDefaultConstructor() {
return this.defaultConstructor != null;
}
public Invoker getSetInvoker(String propertyName) {
Invoker method = (Invoker)this.setMethods.get(propertyName);
if (method == null) {
throw new ReflectionException("There is no setter for property named '" + propertyName + "' in '" + this.type + "'");
} else {
return method;
}
}
public Invoker getGetInvoker(String propertyName) {
Invoker method = (Invoker)this.getMethods.get(propertyName);
if (method == null) {
throw new ReflectionException("There is no getter for property named '" + propertyName + "' in '" + this.type + "'");
} else {
return method;
}
}
public Class<?> getSetterType(String propertyName) {
Class<?> clazz = (Class)this.setTypes.get(propertyName);
if (clazz == null) {
throw new ReflectionException("There is no setter for property named '" + propertyName + "' in '" + this.type + "'");
} else {
return clazz;
}
}
public Class<?> getGetterType(String propertyName) {
Class<?> clazz = (Class)this.getTypes.get(propertyName);
if (clazz == null) {
throw new ReflectionException("There is no getter for property named '" + propertyName + "' in '" + this.type + "'");
} else {
return clazz;
}
}
public String[] getGetablePropertyNames() {
return this.readablePropertyNames;
}
public String[] getSetablePropertyNames() {
return this.writeablePropertyNames;
}
public boolean hasSetter(String propertyName) {
return this.setMethods.keySet().contains(propertyName);
}
public boolean hasGetter(String propertyName) {
return this.getMethods.keySet().contains(propertyName);
}
public String findPropertyName(String name) {
return (String)this.caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));
}
}
Invoker
作用
用于封装方法filed设置的值的动作
类图

接口定义
public interface Invoker {
Object invoke(Object var1, Object[] var2) throws IllegalAccessException, InvocationTargetException;
Class<?> getType();
}
SetFieldInvoker
/**
* 封装filed元数据信息
*/
public class SetFieldInvoker implements Invoker {
private Field field; public SetFieldInvoker(Field field) {
this.field = field;
} //给指定对象的当前属性设置值
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
this.field.set(target, args[0]);
return null;
} public Class<?> getType() {
return this.field.getType();
}
}
GetFieldInvoker
/**
* 封装Filed信息 提供getfiled的调用实现
*/
public class GetFieldInvoker implements Invoker {
private Field field; public GetFieldInvoker(Field field) {
this.field = field;
} public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
return this.field.get(target);
} public Class<?> getType() {
return this.field.getType();
}
}
MethodInvoker
/**
* 方法元数据封装 以及提供调用的方法
*/
public class MethodInvoker implements Invoker {
private Class<?> type;
private Method method; public MethodInvoker(Method method) {
this.method = method;
if (method.getParameterTypes().length == 1) {
this.type = method.getParameterTypes()[0];
} else {
this.type = method.getReturnType();
} } public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
return this.method.invoke(target, args);
} public Class<?> getType() {
return this.type;
}
}
反射工具的使用
//对象创建工厂
ObjectFactory objectFactory=new DefaultObjectFactory();
//反射创建ArrayList
List<Classes> classesList=objectFactory.create(ArrayList.class);
//反射类创建工厂 必须单例哟
ReflectorFactory reflectorFactory= new DefaultReflectorFactory();
Classes classes = objectFactory.create(Classes.class);
//获得Classes所有filed和get的元数据封装信息 并缓存 下次再次获取就是使用缓存
Reflector classesReflector= reflectorFactory.findForClass(Classes.class);
//获得对应Filed或者setMethod的Invoker封装并调用设置值
classesReflector.getSetInvoker("name").invoke(classes,new Object[]{"一年级"});
classesList.add(classes);
for (Classes item:
classesList) {
System.out.print(item.getName()); }
XPath、EntityResolver
说明
解析xml使用非mybatis内部工具类 就不贴源码了
使用方式
1.解析如下xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="classes">
<select id="selectAll" resultType="com.liqiang.entity.Classes">
select * from classes
</select>
<insert id="insert" useGeneratedKeys="true" keyProperty="id" parameterType="com.liqiang.entity.Classes">
insert INTO classes(name) VALUES (#{name});
</insert>
<update id="update" parameterType="com.liqiang.entity.Classes">
UPDATE classes set name=#{name} where id=#{id};
</update>
<delete id="delete" parameterType="int">
delete from classes where id=#{id};
</delete>
</mapper>
2.代码
public static void parseXml() throws IOException, ParserConfigurationException, SAXException, XPathExpressionException {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setValidating(false);
DocumentBuilder builder = builderFactory.newDocumentBuilder();
//不加这句话默认会去http://mybatis.org/dtd/mybatis-3-config.dtd 加上的话 会从本地dtd查找
builder.setEntityResolver(new XMLMapperEntityResolver());
InputSource inputSource = new InputSource(Resources.getResourceAsStream("ClassesMapper.xml"));
Document document = builder.parse(inputSource);
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
//获得mapper节点的namespace的值
String value = (String) xpath.evaluate("/mapper/@namespace", document, XPathConstants.STRING);
System.out.println("namespace=\"" + value + "\"");
//获得mapper节点
Node mapperNode = (Node) xpath.evaluate("/mapper", document, XPathConstants.NODE);
NodeList nodeList= mapperNode.getChildNodes();
System.out.println(nodeList.getLength());
for(int i=0;i<nodeList.getLength();i++){
Node node= nodeList.item(i+1);
//因为换行符也是一个节点所以只处理Element节点
if(node instanceof Element) {
System.out.print("text" + node.getTextContent());
System.out.println("属性值:");
NamedNodeMap attributeNodes = node.getAttributes();
for (int j = 0; j < attributeNodes.getLength(); j++) {
Node n = attributeNodes.item(j);
System.out.println(n.getNodeName() + "=\"" + n.getNodeValue() + "\"");
}
}
}
}
mybatis源码阅读-初始化六个工具(六)的更多相关文章
- mybatis源码阅读-初始化过程(七)
说明 mybatis初始化过程 就是解析xml到封装成Configuration对象 供后续使用 SqlSessionFactoryBuilder 代码例子 SqlSessionFactoryBuil ...
- Mybatis源码阅读-配置文件及映射文件解析
Mybatis源码分析: 1.配置文件解析: 1.1源码阅读入口: org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(); 功能:解析全局配置文 ...
- mybatis源码阅读心得
第一天阅读源码及创建时序图.(第一次用prosson画时序图,挺丑..) 1. 调用 SqlSessionFactoryBuilder 对象的 build(inputStream) 方法: 2. ...
- mybatis源码阅读(动态代理)
这一篇文章主要是记录Mybatis的动态代理学习成果,如果对源码感兴趣,可以看一下上篇文章 https://www.cnblogs.com/ChoviWu/p/10118051.html 阅读本篇的 ...
- mybatis源码阅读-Transaction和TransactionFactory(四)
Transaction 类图 接口定义 public interface Transaction { Connection getConnection() throws SQLException; v ...
- mybatis源码阅读-SqlSessionFactory和SqlSession(三)
说明 读了3遍:https://my.oschina.net/zudajun/blog/665956 现在统一整理成笔记 并跟着源码一行一行调试 统一整理起来 SqlSession 接口定义 publ ...
- Mybatis源码阅读 之 玩转Executor
承接上篇博客, 本文探究MyBatis中的Executor, 如下图: 是Executor体系图 本片博客的目的就是探究如上图中从顶级接口Executor中拓展出来的各个子执行器的功能,以及进一步了解 ...
- Mybatis源码之Statement处理器CallableStatementHandler(六)
CallableStatementHandler实际就是使用CallableStatement来执行SQL语句,当然它执行的是存储过程. 源码如下: /** * @author Clinton Beg ...
- mybatis源码阅读-MappedStatement各个属性解析过程(八)
调用方 类org.apache.ibatis.builder.xml.XMLMapperBuilder private void configurationElement(XNode context) ...
随机推荐
- hdu 6115(LCA 暴力)
Factory Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)Total ...
- B1297 [SCOI2009]迷路 矩阵
这个题我觉得很有必要写一篇博客.首先,我们需要知道,假如一个邻接矩阵只有0/1构成,那么它自己的n次方就是走n步之后的方案数.但这个题还有2~9咋办呢.我们观察发现,这个题只有10个点,而且边权< ...
- bzoj1227
离散化+树状数组+排列组合 很久以前就看到过这道题,现在依然不会做...看完题解发现思路很简单,就是有点难写 我们先将坐标离散化,x和y最大是w,然后我们就有了一个暴力做法, 枚举每块墓地,统计,因为 ...
- php的类型转换
转自:http://www.tianzhigang.com/article.asp?id=280 PHP的数据类型转换属于强制转换,允许转换的PHP数据类型有: (int).(integer):转换成 ...
- 牛客小白月赛15 C 表单 ( map 使用)
链接:https://ac.nowcoder.com/acm/contest/917/C来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言52428 ...
- Activity启动模式(GIF 动态演示)
本文首发在我的个人微信公众号:Android开发圈 引言 关于Activity的启动模式是面试高频问题,在平时开发中,作用也不小,所以还是很有必要搞懂这一块的知识.其实之前也有写过这个主题的文章,但是 ...
- jdk1.8 api 下载
链接: https://pan.baidu.com/s/1Wmf2vzXxclVcBPUfPp_g_A 提取码: dpwu 希望那些CSDN的不要借此収积分,行行好吧你,小众程序员就是为了方便 凑字数 ...
- 上传Android代码到gerrit服务器
1. 配置default.xml default.xml是跟Android代码配套的,可参考google Android源码下的default.xml(.repo/manifests/default. ...
- NHibernate系列学习(一)-看看用NH怎么做增速改查
1.本次所有代码是在一下环境下运行的 学习系统:win8 64bit 开发环境:VS2013,MSSQL2012 NHibernate版本:NHibernate-4.0.3.GA [文章结尾有本次笔记 ...
- iOS动画——UIKit动画
iOS动画 iOS有很多动画技术,API主要分布在两个库中,一个是UIKit,另一个是CoreAnimation,先对UIKit动画做一下总结. UIKit动画 在UIKit中,很多API都可以看到a ...