MyBatis源码解析(九)——Type类型模块之类型处理器注册器(TypeHandlerRegistry)
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6709157.html
1、回顾
上一篇研究的是类型别名注册器TypeAliasRegister,它主要用于将基本类型和用户自定义的类型进行别名注册,将别名及其对应类类型保存在一个HashMap中,方便存取,是映射器映射功能实现的基础,本篇所研究的类型处理器注册器TypeHandlerReister是用来统筹管理类型处理器的,类型处理器是真正用于进行java类型与数据库类型映射的工具。
这一篇我们还是重点研究类型处理器的注册器,有关具体类型处理器的研究放到之后进行。
2、类型处理器
为了研究类型处理器注册器,我们需要对类型处理器有一定的基础和认识,这里简单介绍一下,具体内容可等下一篇。
类型处理器简单点说就是用于处理javaType与jdbcType之间类型转换用的处理器,MyBatis针对诸多Java类型与数据库类型进行了匹配处理。
它主要用于映射器配置文件的工作,在通过类型别名注册器获取类型别名代表的类型之后,就可以使用获取的类型通过类型处理器注册器来得到其对应的JdbcType和对应的类型处理器。
由此可见每个类型处理器都针对两个类型,一个Java类型,一个数据库类型。而类型处理器的作用就是进行二者之间的匹配、对应、转换。
3、类型处理器注册器
类型处理器注册器既能完成类型处理器的注册功能,同时也能对类型处理器进行统筹管理,其内部定义了集合来进行类型处理器的存取,同时定义了存取方法。
private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class);
private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();
private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>();
以上是TypeHandlerRegister中定义的三个Map集合,这三个集合是用来保存类型处理器的注册信息的。
第一种:JDBC_TYPE_HANDLER_MAP,这是一个枚举Map集合,其内部是以JdbcType枚举类中枚举值为键创建的一种集合,这种集合先天存在键(枚举值),它是以数据库类型为键来保存类型处理器,亦即将类型处理器注册到对应的数据库类型上。
第二种:TYPE_HANDLER_MAP,这是一个前套Map集合,内层集合是以数据库类型为键保存处理器,外层集合为以Java类型来保存对应的数据库类型及其处理器,这个集合将三者联系起来,是真正进行三者对应关系匹配的集合。
第三种:ALL_TYPE_HANDLERS_MAP,这个集合中保存着所有的类型处理器,是以类型处理器的类类型为键值保存的,它可以统筹所有的类型处理器(带有统计的效果)。
3.1 基础类型处理器
在创建类型处理器注册器的时候,在其无参构造器中会进行基础类型处理器的注册,这些注册包括三种方式,一种是将以JavaType为键的保存方式,一种是以JdbcTye为键的保存方式,还有一种就是以JavaType与JdbcType为键的保存方式,这最后一种保存方式是一种嵌套的Map集合,前面的两种只是简单的Map集合。
下面将该无参构造器源码罗列:
//构造函数里注册系统内置的类型处理器
public TypeHandlerRegistry() {
//以下是为多个类型注册到同一个handler
register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler()); register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler()); register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler()); register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler()); register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler()); register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler()); register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler()); //以下是为同一个类型的多种变种注册到多个不同的handler
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler()); register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler()); register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler()); register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler()); register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler()); register(Object.class, UNKNOWN_TYPE_HANDLER);
register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER); register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler()); register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler()); // issue #273
register(Character.class, new CharacterTypeHandler());
register(char.class, new CharacterTypeHandler());
}
通过源码可以发现:MyBatis内置注册的类型处理器很是全面,几乎囊括了所有常用的类型,所以一般情况下我们直接使用内置的类型处理器进行类型处理即可。
3.1.1 针对JavaType,MyBatis内置注册了一下类型:
| 序号 | javaType | JdbcType | TypeHandler | 入口 | 说明 |
| 1 | Boolean.class | null | BooleanTypeHandler | 入口2 | |
| 2 | boolean.class | null | BooleanTypeHandler | ||
| 3 | Byte.class | null | ByteTypeHandler | ||
| 4 | byte.class | null | ByteTypeHandler | ||
| 5 | Short.class | null | ShortTypeHandler | ||
| 6 | short.class | null | ShortTypeHandler | ||
| 7 | Integer.class | null | IntegerTypeHandler | ||
| 8 | int.class | null | IntegerTypeHandler | ||
| 9 | Long.class | null | LongTypeHandler | ||
| 10 | long.class | null | LongTypeHandler | ||
| 11 | Float.class | null | FloatTypeHandler | ||
| 12 | float.class | null | FloatTypeHandler | ||
| 13 | Double.class | null | DoubleTypeHandler | ||
| 14 | double.class | null | DoubleTypeHandler | ||
| 15 | String.class | null | StringTypeHandler | ||
| 16 | BigDecimal.class | null | BigDecimalTypeHandler | ||
| 17 | BigInteger.class | null | BigIntegerTypeHandler | ||
| 18 | Byte[].class | null | ByteObjectArrayTypeHandler | ||
| 19 | byte[].class | null | ByteArrayTypeHandler | ||
| 20 | Object.class | null | UNKNOWN_TYPE_HANDLER | ||
| 21 | Date.class | null | DateTypeHandler | ||
| 22 | java.sql.Date.class | null | SqlDateTypeHandler | ||
| 23 | java.sql.Time.class | null | SqlTimeTypeHandler | ||
| 24 | Character.class | null | CharacterTypeHandler | ||
| 25 | char.class | null | CharacterTypeHandler | ||
| 26 | java.sql.Timestamp.class | null | SqlTimestampTypeHandler |
3.1.2 针对JdbcType,MyBatis内置注册了一下类型:
| 序号 | javaType | JdbcType | TypeHandler | 入口 | 说明 |
| 1 | JdbcType.BOOLEAN | BooleanTypeHandler | 入口1 | ||
| 2 | JdbcType.BIT | BooleanTypeHandler | |||
| 3 | JdbcType.TINYINT | ByteTypeHandler | |||
| 4 | JdbcType.SMALLINT | ShortTypeHandler | |||
| 5 | JdbcType.INTEGER | IntegerTypeHandler | |||
| 6 | JdbcType.FLOAT | FloatTypeHandler | |||
| 7 | JdbcType.DOUBLE | DoubleTypeHandler | |||
| 8 | JdbcType.CHAR | StringTypeHandler | |||
| 9 | JdbcType.VARCHAR | StringTypeHandler | |||
| 10 | JdbcType.CLOB | ClobTypeHandler | |||
| 11 | JdbcType.LONGVARCHAR | ClobTypeHandler | |||
| 12 | JdbcType.NVARCHAR | NStringTypeHandler | |||
| 13 | JdbcType.NCHAR | NStringTypeHandler | |||
| 14 | JdbcType.NCLOB | NClobTypeHandler | |||
| 15 | dbcType.ARRAY | ArrayTypeHandler | |||
| 16 | JdbcType.BIGINT | LongTypeHandler | |||
| 17 | JdbcType.REAL | BigDecimalTypeHandler | |||
| 18 | JdbcType.DECIMAL | BigDecimalTypeHandler | |||
| 19 | JdbcType.NUMERIC | BigDecimalTypeHandler | |||
| 20 | JdbcType.LONGVARBINARY | BlobTypeHandler | |||
| 21 | JdbcType.BLOB | BlobTypeHandler | |||
| 22 | JdbcType.OTHER | UNKNOWN_TYPE_HANDLER | |||
| 23 | JdbcType.TIMESTAMP | DateTypeHandler | |||
| 24 | JdbcType.DATE | DateOnlyTypeHandler | |||
| 25 | JdbcType.TIME | TimeOnlyTypeHandler |
3.1.3 针对JdbcType和JavaType,MyBatis内置注册了一下类型:
| 序号 | JavaType | JdbcType | TypeHandler | 入口 | 说明 |
| 1 | Date.class | JdbcType.DATE | DateOnlyTypeHandler | 入口3 | |
| 2 | Date.class | JdbcType.TIME | TimeOnlyTypeHandler | ||
| 3 | Object.class | JdbcType.OTHER | UNKNOWN_TYPE_HANDLER | ||
| 4 | byte[].class | JdbcType.BLOB | BlobTypeHandler | ||
| 5 | byte[].class | JdbcType.LONGVARBINARY | BlobTypeHandler | ||
| 6 | Byte[].class | JdbcType.BLOB | BlobByteObjectArrayTypeHandler | ||
| 7 | Byte[].class | JdbcType.LONGVARBINARY | BlobByteObjectArrayTypeHandler | ||
| 8 | String.class | JdbcType.CHAR | StringTypeHandler | ||
| 9 | String.class | JdbcType.CLOB | ClobTypeHandler | ||
| 10 | String.class | JdbcType.VARCHAR | StringTypeHandler | ||
| 11 | String.class | JdbcType.LONGVARCHAR | ClobTypeHandler | ||
| 12 | String.class | JdbcType.NVARCHAR | NStringTypeHandler | ||
| 13 | String.class | JdbcType.NCHAR | NStringTypeHandler | ||
| 14 | String.class | JdbcType.NCLOB | NClobTypeHandler |
3.2 注册入口方法
通过观察源码我们也可以发现这三种注册方式,我在这里将这三种方式的register方法看做三个入口,分别起名为:入口1、入口2、入口3。
其中:
入口1:对应之前介绍的第一种集合(枚举集合),其入口方法为:
//入口1
public void register(JdbcType jdbcType, TypeHandler<?> handler) {
JDBC_TYPE_HANDLER_MAP.put(jdbcType, handler);
}
该入口方法用于将类型处理器注册到对应的数据库类型。
入口2:对应之前介绍的第二种嵌套集合(其中内层集合的键为null),其入口方法为:
//入口2
public <T> void register(Class<T> javaType, TypeHandler<? extends T> typeHandler) {
register((Type) javaType, typeHandler);
}
该入口方法用于将类型处理器注册到对应的Java类型。
入口3:对应之前介绍的第二种嵌套集合,其入口方法为:
//入口3
public <T> void register(Class<T> type, JdbcType jdbcType, TypeHandler<? extends T> handler) {
register((Type) type, jdbcType, handler);
}
该入口方法用于将类型处理器与Java类型和数据库类型联系起来。
上述的三个入口方法均是对内而设的入口方法,也就是说是用于注册器内部基础类型处理器(MyBatis内置的类型处理器)注册使用的。而MyBatis还提供了自定义类型处理器的功能,也就是说在该类中还提供了对外的自定义类型处理器注册入口。
这么理解:对内就是该方法被类内部调用进行注册,对外就是该方法被类外部的其他类进行调用而进行注册,这里的其他类其实就是XMLConfigBuilder类,它在构建Configuration对象时就会调用对外的注册方法,来将用户自定义的类型处理器注册到注册器中。
对外入口1:只指定包名的情况下,这种情况一般需要配合注解@MappedTypes使用,使用该注解进行JavaType的设置(即注解的value值)
//对外入口1:扫描器
public void register(String packageName) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
for (Class<?> type : handlerSet) {
//Ignore inner classes and interfaces (including package-info.java) and abstract classes
if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
register(type);
}
}
}
这个入口是一个扫描器,它会使用ResolverUtil工具类在给定包名下扫描所有类,然后进行循环注册,注册之前会进行排除操作,将内部类、接口、抽象类排除在外。这个扫描器针对的就是我们自定义的类型处理器进行注册,这个入口方法会在构建Configuration配置类时由XMLConfigBuilder进行调用,用于将用户自定义的类型处理器注册到注册器中。
上面的入口是在指定包名的情况下进行包扫描来获取包下所有类来进行类型处理器注册,一般会配合注解一起使用,但是如果不配合注解也能成功。如果配合注解指定JavaType,那么它将与对外入口2的情况一致(指定JavaType与TypeHandler),如果没有配合注解,那么就只有TypeHandler,这时候会调用另外一个注册方法,在这个方法中会再次验证是否存在注解,不存在的话,那么验证获取的类是否是TypeReference接口的实现类,如果是其实现类,说明这个类是一个类型处理器,那么再次调用另外一个注册方法,以该类型处理器的原生类型为参数进行调用,在这个方法中需要查询该类型处理器是否有注解@MappedJdbcTypes来指定JdbcType,如果有则以此JdbcType值为数据库类型,如果没有或者是Null类型,则直接将JdbcType置null再调用核心注册方法,将该类型处理器注册到TYPE_HANDLER_MAP集合中,最后还有将该注册器注册到ALL_TYPE_HANDLERS_MAP中用于统一管理。
对外入口2:指定Java类型与类型处理器的情况
//对外入口2
public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));
}
对于第二种对外入口其实在第一种的情况中已经有所描述,这个方法会调用另外一个注册方法,来使用@MappedJdbcTypes获取jdbcType类型,其余步骤同上。
对外入口3:指定JavaType、JdbcType、TypeHandler三者的情况
//对外入口3
public void register(Class<?> javaTypeClass, JdbcType jdbcType, Class<?> typeHandlerClass) {
register(javaTypeClass, jdbcType, getInstance(javaTypeClass, typeHandlerClass));
}
这种情况可以直接调用核心注册进行注册即可。
对外入口4:只指定TypeHandler的情况
//对外入口4
public void register(Class<?> typeHandlerClass) {
boolean mappedTypeFound = false;
MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
if (mappedTypes != null) {
for (Class<?> javaTypeClass : mappedTypes.value()) {
register(javaTypeClass, typeHandlerClass);
mappedTypeFound = true;
}
}
if (!mappedTypeFound) {
register(getInstance(null, typeHandlerClass));
}
}
这种情况下,需要先验证是否有@MappedType指定JavaType,再验证是否有@MappedJdbcType指定JdbcType,分各种情况进行考虑,这在第一个入口方法中已经描述。
3.3 核心注册方法
虽然拥有诸多对内对外的注册入口方法,但是几乎都会指向核心注册方法,只有对内入口1不会指向核心注册方法,因为第一种对内入口方法的执行效果是往枚举集合JDBC_TYPE_HANDLER_MAP中注册数据库类型处理器。这与其他的注册情况不同,一般我们的注册是指往TYPE_HANDLER_MAP嵌套集合和ALL_TYPE_HANDLERS_MAP集合中注册类型处理器。
private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
if (javaType != null) {
Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);
if (map == null) {
map = new HashMap<JdbcType, TypeHandler<?>>();
TYPE_HANDLER_MAP.put(javaType, map);
}
map.put(jdbcType, handler);
}
ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
}
然我来总述一下注册的过程,对上面的情况作何总结:
注册就是要三者兼备,哪三者:javaType、JdbcType、TypeHandler三者兼备,针对自定义类型处理器而言,我们可以通过继承BaseTypeHandler抽象类或者实现TypeHandler接口的方式来进行类型处理器的自定义实现。但是为了使其能在MyBatis中发挥作用,我们要将其注册到类型处理器注册器中。通过简单的配置即可实现,配置方式有两种:
<typeHandlers>
<package name="com.xx.xx"/>
<typeHandler handler="com.xx.xx.XxxTypeHandler" javaType="xxx" jdbcType="JdbcType.xxx" />
</typeHandlers>
若是用第二种方式配置即可直接进行注册,但是有时我们会省去javaType设置,而使用@MappedTypes注解来指定多个JavaType,或者省去JdbcType配置,采用@MappedJdbcTypes注解来指定多个jdbcType(毕竟配置文件只能指定一个,当需要设置多个时,就只能采用注解的方式实现),这时就需要查询目标处理器类的注解来获取类型,如果既没有在配置文件中配置,也没有通过注解配置,那么就只能置为null(这种情况毕竟,少见,一般我们要自定义类型处理器,必定是有某种类型处理器处理的不满意,我们肯定会指定对应的Java类型与数据库类型,如果听之任之的话我们又何必多此一举呢?)
极端情况就是采用包名配置或者只指定处理器类型进行注册,这时需要逐步查看类型处理器类的注解配置来获取该处理器处理的Java类型与数据库类型,最后在双方都获取到的情况下,三者齐备,调用核心注册方法,将这个类型处理器注册到TYPE_HANDLER_MAP嵌套集合和ALL_TYPE_HANDLERS_MAP集合中。
MyBatis源码解析(九)——Type类型模块之类型处理器注册器(TypeHandlerRegistry)的更多相关文章
- 【MyBatis源码解析】MyBatis一二级缓存
MyBatis缓存 我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相 ...
- mybatis源码-解析配置文件(四-1)之配置文件Mapper解析(cache)
目录 1. 简介 2. 解析 3 StrictMap 3.1 区别HashMap:键必须为String 3.2 区别HashMap:多了成员变量 name 3.3 区别HashMap:key 的处理多 ...
- mybatis源码-解析配置文件(三)之配置文件Configuration解析
目录 1. 简介 1.1 系列内容 1.2 适合对象 1.3 本文内容 2. 配置文件 2.1 mysql.properties 2.2 mybatis-config.xml 3. Configura ...
- Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码
在文章:Mybatis源码解析,一步一步从浅入深(一):创建准备工程,中我们为了解析mybatis源码创建了一个mybatis的简单工程(源码已上传github,链接在文章末尾),并实现了一个查询功能 ...
- Mybatis源码解析,一步一步从浅入深(三):实例化xml配置解析器(XMLConfigBuilder)
在上一篇文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码 ,中我们看到 代码:XMLConfigBuilder parser = new XMLConfigBuilder(read ...
- Mybatis源码解析,一步一步从浅入深(四):将configuration.xml的解析到Configuration对象实例
在Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们看到了XMLConfigBuilder(xml配置解析器)的实例化.而且这个实例化过程在文章:Mybatis源码解析,一步一步从浅 ...
- Mybatis源码解析(三) —— Mapper代理类的生成
Mybatis源码解析(三) -- Mapper代理类的生成 在本系列第一篇文章已经讲述过在Mybatis-Spring项目中,是通过 MapperFactoryBean 的 getObject( ...
- Mybatis源码解析(二) —— 加载 Configuration
Mybatis源码解析(二) -- 加载 Configuration 正如上文所看到的 Configuration 对象保存了所有Mybatis的配置信息,也就是说mybatis-config. ...
- mybatis源码-解析配置文件(四)之配置文件Mapper解析
在 mybatis源码-解析配置文件(三)之配置文件Configuration解析 中, 讲解了 Configuration 是如何解析的. 其中, mappers作为configuration节点的 ...
- Mybatis源码解析,一步一步从浅入深(一):创建准备工程
Spring SpringMVC Mybatis(简称ssm)是一个很流行的java web框架,而Mybatis作为ORM 持久层框架,因其灵活简单,深受青睐.而且现在的招聘职位中都要求应试者熟悉M ...
随机推荐
- 在windows上传一个新的项目到GitHub上
不多说,直接上步骤 1,新建GitHub的账号密码. 2,新建一个项目 点击new repository 3,选择自己项目,填写格式 点击创建 create repository,这时候一个雏形 ...
- ES6学习:两个面试题目--关于模板字符串
号称看完就能“让开发飞起来”,不过文中的两个面试题目的知识点并没包括在文中. https://www.jianshu.com/p/287e0bb867ae 文中并没有完整的知识点去完成上面的两道题,这 ...
- C++ boost.python折腾笔记
为了让当年研究生时写的图像处理系统重出江湖起到更大的作用,应研究生导师的意见,对原有的c++框架做了python扩展处理,为了避免遗忘,备注如下: 一.boost 编译 下载boost源码,这里使用b ...
- 解决windows server在关闭远程桌面后开启的服务也随之关闭的问题
首先远程登录服务器,关闭所有tomcat进程以及所有java进程,使用 netstat命令检查tomcat端口是否仍在监听状态,如仍在监听,使用taskkill杀死进程, 接下来关闭系统tomcat服 ...
- HTML5元素标记释义
HTML5元素标记释义 标记 类型 意义 介绍 文件标记 <html> ● 根文件标记 让浏览器知道这是HTML 文件 META标记 <head> ● 开头 提供文件整体信息 ...
- 黑群晖DS3617xs-DSM6.1.7up3/up2 开启ROOT用户,同时SATA改eSATA,挂载NTFS硬盘设置(二)
这两天闲来没事在某宝上搞了个黑群晖主机就j1900/4G小主机系统是DCM 6.1.7up3 15284版 网上修改的教程很多,走了好多弯路终于搞定我的黑群NAS,现分享给各位道友,有不足的地方请给位 ...
- vs编译器堆栈保护(GS选项)
参考: 安全编码实践一:GS编译选项和缓存溢出 堆栈溢出第三话--GS机制
- 一个xss漏洞到内网漫游【送多年心血打造的大礼包啦!】
i春秋作家:jasonx 原文来自:一个xss漏洞到内网漫游[送多年心血打造的大礼包啦!] 前言 渗透过程中,有时候遇某些网站,明明检测到有xss漏洞,但是盲打以后,收到的cookie还是不能登录后台 ...
- C++ 基础知识回顾总结
一.前言 为啥要写这篇博客?答:之前学习的C和C++相关的知识,早就被自己忘到一边去了.但是,随着音视频的学习的不断深入,和C/C++打交道的次数越来越多,看代码是没问题的,但是真到自己操刀去写一些代 ...
- eclipse遇到的问题
引用不了R文件,可能是导包导错了cannot be resolved or is not a field:首先检查你的XML是否保存了,再检查你的import导入的R文件是你包名+R还是android ...