Mybatis自动注册TypeHandler,自动扫描、自定义注解实现自定义TypeHandler
作者:互联网
上一篇手动版https://blog.csdn.net/h785160953/article/details/103615458
自定义的TypeHandler
- 1、
JsonTypeHandler.java
import com.dreawer.domain.BaseDomain;
import com.dreawer.persistence.config.DwDaoHandler;
import com.dreawer.persistence.config.DwMybatisConfig;
import com.dreawer.util.JsonUtils;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 数据库字段string - Java对象互转handler
*
* @author Leo.Xi
* @date 2019/12/18
* @since 1.0
**/
@MappedJdbcTypes({JdbcType.VARCHAR, JdbcType.CHAR, JdbcType.NCHAR, JdbcType.LONGVARCHAR})
public class JsonTypeHandler<T extends Object> extends BaseTypeHandler<T> {
public static final String ID_TEMPLATE = "{\"id\":\"%s\"}";
private Class<? extends T> clazz;// clazz
private DwDaoHandler.Type type;// 序列化类型
public JsonTypeHandler(Class<? extends T> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.clazz = clazz;
this.type = DwMybatisConfig.getSingleType(clazz);
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (DwDaoHandler.Type.JSON.equals(type)) { // JSON
ps.setString(i, JsonUtils.toNoNullJsonStr(parameter));
} else {
ps.setString(i, ((BaseDomain) parameter).getId());
}
}
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
if (DwDaoHandler.Type.JSON.equals(type)) { // JSON
return JsonUtils.readValue(rs.getString(columnName), clazz);
} else {
return JsonUtils.readValue(String.format(ID_TEMPLATE, rs.getString(columnName)), clazz);
}
}
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
if (DwDaoHandler.Type.JSON.equals(type)) { // JSON
return JsonUtils.readValue(rs.getString(columnIndex), clazz);
} else {
return JsonUtils.readValue(String.format(ID_TEMPLATE, rs.getString(columnIndex)), clazz);
}
}
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
if (DwDaoHandler.Type.JSON.equals(type)) { // JSON
return JsonUtils.readValue(cs.getString(columnIndex), clazz);
} else {
return JsonUtils.readValue(String.format(ID_TEMPLATE, cs.getString(columnIndex)), clazz);
}
}
}
- 2、
JsonListTypeHandler.java
import com.dreawer.domain.BaseDomain;
import com.dreawer.persistence.config.DwDaoHandler;
import com.dreawer.persistence.config.DwMybatisConfig;
import com.dreawer.util.JsonUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 数据库字段string - Java对象互转handler
*
* @author Leo.Xi
* @date 2019/12/18
* @since 1.0
**/
@MappedJdbcTypes({JdbcType.VARCHAR, JdbcType.CHAR, JdbcType.NCHAR, JdbcType.LONGVARCHAR})
public class JsonListTypeHandler<T extends Object> extends BaseTypeHandler<List<T>> {
private Class<? extends T> clazz;// clazz
private DwDaoHandler.Type type;// 序列化类型
public JsonListTypeHandler(Class<? extends T> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.clazz = clazz;
this.type = DwMybatisConfig.getCollectionType(clazz);
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<T> parameter, JdbcType jdbcType) throws SQLException {
if (DwDaoHandler.Type.JSON.equals(type)) { // JSON
ps.setString(i, JsonUtils.toNoNullJsonStr(parameter));
} else {
String value = parameter.stream().map(x -> (BaseDomain) x).map(BaseDomain::getId).collect(Collectors.joining(
","));
ps.setString(i, value);
}
}
@Override
public List<T> getNullableResult(ResultSet rs, String columnName) throws SQLException {
String value = rs.getString(columnName);
if (value == null) {
return null;
}
List<T> result = new LinkedList<>();
if (DwDaoHandler.Type.JSON.equals(type)) { // JSON
List<T> ts = JsonUtils.readValue(value, new TypeReference<List<T>>() {
});
if (ts != null) {
ts.forEach(x -> {
T t = JsonUtils.convertValue(x, clazz);
if(null == t){
// throw RuntimeException
} else {
result.add(t);
}
});
return result;
}
} else {
String[] ids = value.split(",");
for (int i = 0, l = ids.length; i < l; i++) {
result.add(JsonUtils.readValue(String.format(JsonTypeHandler.ID_TEMPLATE, ids[i]), clazz));
}
return result;
}
return null;
}
@Override
public List<T> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String value = rs.getString(columnIndex);
if (value == null) {
return null;
}
List<T> result = new LinkedList<>();
if (DwDaoHandler.Type.JSON.equals(type)) { // JSON
List<T> ts = JsonUtils.readValue(value, new TypeReference<List<T>>() {
});
if (ts != null) {
ts.forEach(x -> {
T t = JsonUtils.convertValue(x, clazz);
if(null == t){
// throw RuntimeException
} else {
result.add(t);
}
});
return result;
}
} else {
String[] ids = value.split(",");
for (int i = 0, l = ids.length; i < l; i++) {
result.add(JsonUtils.readValue(String.format(JsonTypeHandler.ID_TEMPLATE, ids[i]), clazz));
}
return result;
}
return null;
}
@Override
public List<T> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String value = cs.getString(columnIndex);
if (value == null) {
return null;
}
List<T> result = new LinkedList<>();
if (DwDaoHandler.Type.JSON.equals(type)) { // JSON
List<T> ts = JsonUtils.readValue(value, new TypeReference<List<T>>() {
});
if (ts != null) {
ts.forEach(x -> {
T t = JsonUtils.convertValue(x, clazz);
if(null == t){
// throw RuntimeException
} else {
result.add(t);
}
});
return result;
}
} else {
String[] ids = value.split(",");
for (int i = 0, l = ids.length; i < l; i++) {
result.add(JsonUtils.readValue(String.format(JsonTypeHandler.ID_TEMPLATE, ids[i]), clazz));
}
return result;
}
return null;
}
}
是否启用该序列化方式注解@EnableDwDaoHandler
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 是否启用dreawerDaoHandler序列化到数据库
* 使用该注解后即启用成功。
* 默认扫描Mybatis.typeAliasesPackage别名包旗下所有使用@DwDaoHandler的属性。
*
* @author Leo.Xi
* @date 2020/1/10
* @since 1.0
**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({DwMybatisConfig.class})
public @interface EnableDwDaoHandler {
}
声名式注解@DwDaoHandler
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* mybatis - DAO,Handler
*
* <p>使用须知:<p/> 2020-01-13
* 1、使用注解时Type = ID的类必须继承BaseDomain
* 2、适用该注解的类,不能单独储存到数据库,一般是作为其他对象的属性存在的
* 3、需要单独存储的,则需要转为Map,Insert。或者List批量插入也是可以的。<code>insert("add", obj2Map(user)) OR insert("addBatchList", users)</code>
*
* @author Leo.Xi
* @date 2020/1/9
* @since 1.0
**/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DwDaoHandler {
/** 序列化类型 */
Type value() default Type.JSON;
enum Type {
/** 只保留ID */
ID,
/** 对象Json */
JSON;
}
}
自动扫描、自动注册配置DwMybatisConfig.java
import com.dreawer.domain.BaseDomain;
import com.dreawer.persistence.handler.JsonListTypeHandler;
import com.dreawer.persistence.handler.JsonTypeHandler;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import javax.sql.DataSource;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.LinkedHashMap;
/**
* MybatisConfig - 配置类
*
* @author Leo.Xi
* @date 2019/12/19
* @since 1.0
**/
@Configuration
public class DwMybatisConfig {
private static final PathMatchingResourcePatternResolver RESOLVER = new PathMatchingResourcePatternResolver();
private static final SimpleMetadataReaderFactory REGISTER = new SimpleMetadataReaderFactory();
private static final StandardEnvironment ENVIRONMENT = new StandardEnvironment();
/** 需要使用JsonTypeHandle转换的 - 单个 */
private static final LinkedHashMap<Class<?>, DwDaoHandler.Type> SINGLE = new LinkedHashMap<>();
/** 需要使用JsonListTypeHandle转换的 - 集合 List */
private static final LinkedHashMap<Class<?>, DwDaoHandler.Type> COLLECTIONS = new LinkedHashMap<>();
@Autowired
private MybatisProperties mybatisProperties;
/**
* 根据包路径,获取Class的资源路径
*
* @param packagePath 包路径
* @return
*/
private static String getResourcePath(String packagePath) {
if (StringUtils.isEmpty(packagePath)) {
packagePath = "./";
}
return ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(ENVIRONMENT.resolveRequiredPlaceholders(packagePath))
+ '/' + "**/*.class";
}
/**
* 获取单个类型
*
* @param clazz clazz
* @return @link DwDaoHandler.Type
* @author Leo.Xi
* @date 2020/1/10
* @since 0.0.1
*/
public static DwDaoHandler.Type getSingleType(Class<?> clazz) {
return SINGLE.get(clazz);
}
/**
* 获取集合类型
*
* @param clazz clazz
* @return @link DwDaoHandler.Type
* @author Leo.Xi
* @date 2020/1/10
* @since 0.0.1
*/
public static DwDaoHandler.Type getCollectionType(Class<?> clazz) {
return COLLECTIONS.get(clazz);
}
/**
* 获取列表字段的真实类型,非集合的返回null
*
* @param f 字段属性
* @return 非集合的返回null
* @author Leo.Xi
* @date 2020/1/13
* @since 0.0.1
*/
public static Class<?> getCollectionFieldType(Field f) {
Class<?> fieldClass = f.getType();
if (Collection.class.isAssignableFrom(fieldClass)) {
Type genericType = f.getGenericType();
Type actualTypeArgument = ((ParameterizedType) genericType).getActualTypeArguments()[0];
if (actualTypeArgument instanceof Class) {
return (Class<?>) actualTypeArgument;
}
}
return null;
}
/**
* 获取指定路径下的类
*
* @param pkgPath 包路径
*/
private static void scanMybatisHandler(String pkgPath) {
//获取spring的包路径
String pathPackage = getResourcePath(pkgPath);
Resource[] resources = new Resource[0];
try {
//加载路径
resources = RESOLVER.getResources(pathPackage);
} catch (IOException e) {
// ignore
}
MetadataReader metadataReader = null;
Field[] fields;
String className;
for (int i = 0; i < resources.length; i++) {
Resource resource = resources[i];
try {
//读取资源
metadataReader = REGISTER.getMetadataReader(resource);
//读取资源的注解配置
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
className = annotationMetadata.getClassName();
fields = ClassUtils.forName(className, RESOLVER.getClassLoader()).getDeclaredFields();
} catch (IOException | ClassNotFoundException e) {
continue;
}
for (Field field : fields) {
field.setAccessible(true);
DwDaoHandler annotation = field.getAnnotation(DwDaoHandler.class);
if (null != annotation) {
DwDaoHandler.Type type = annotation.value();
Class<?> fieldClass = field.getType();
if (Collection.class.isAssignableFrom(fieldClass)) {
Type genericType = field.getGenericType();
Type actualTypeArgument = ((ParameterizedType) genericType).getActualTypeArguments()[0];
if (actualTypeArgument instanceof Class) {
Class<?> aClass = (Class<?>) actualTypeArgument;
// 校验规则
if (DwDaoHandler.Type.ID.equals(type) && !BaseDomain.class.isAssignableFrom(aClass)) {
throw new RuntimeException(String.format("ID的序列化方式对象[%s]必须是BaseDomain的子类", aClass));
}
if (COLLECTIONS.containsKey(aClass)) {
// 比对类型是否一致
if (COLLECTIONS.get(aClass).equals(type)) {
throw new RuntimeException(String.format("%s.%s的序列化方式存在不一致,请核实", className,
field.getName()));
}
} else {
COLLECTIONS.put(aClass, type);
}
}
} else {
// 校验规则
if (DwDaoHandler.Type.ID.equals(type) && !BaseDomain.class.isAssignableFrom(fieldClass)) {
throw new RuntimeException(String.format("ID的序列化方式对象[%s]必须是BaseDomain的子类", fieldClass));
}
if (SINGLE.containsKey(fieldClass)) {
// 比对类型是否一致
if (SINGLE.get(fieldClass).equals(type)) {
throw new RuntimeException(String.format("%s.%s的序列化方式存在不一致,请核实", className,
field.getName()));
}
} else {
SINGLE.put(fieldClass, type);
}
}
}
}
}
}
/**
* 自定义sqlSession 配置
*
* @param dataSource 数据源
* @return SqlSessionFactory
* @author Leo.Xi
* @date 2019/12/19
* @since 0.0.1
*/
@Bean
public SqlSessionFactory sqlSessionFactory(@Autowired DataSource dataSource) throws Exception {
// 先扫描项目下的所有需要TypeHandler的类
String typeAliasesPackage = mybatisProperties.getTypeAliasesPackage();
if (typeAliasesPackage != null) {
String[] split = typeAliasesPackage.split(",; \t\n");
for (String pkg : split) {
scanMybatisHandler(pkg);
}
}
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
for (Class<?> clazz : SINGLE.keySet()) {
configuration.getTypeHandlerRegistry().register(clazz, JsonTypeHandler.class);
}
for (Class<?> clazz : COLLECTIONS.keySet()) {
configuration.getTypeHandlerRegistry().register(new JsonListTypeHandler<>(clazz));
}
// 控制台打印sql
configuration.setLogImpl(org.apache.ibatis.logging.stdout.StdOutImpl.class);
sessionFactory.setConfiguration(configuration);
sessionFactory.setPlugins(new Interceptor[]{new DwDaoHandlerPlugin()});
// System.err.println("mybatisProperties.getTypeAliasesPackage():" + mybatisProperties.getTypeAliasesPackage());
sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
//解决myBatis下 不能嵌套jar文件的问题
VFS.addImplClass(SpringBootVFS.class);
// VFS.addImplClass(JBoss6VFS.class);
String[] mapperLocations = mybatisProperties.getMapperLocations();
for (String mapperLocation : mapperLocations) {
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocation));
}
return sessionFactory.getObject();
}
}
Mybatis插件DwDaoHandlerPlugin.java
实现动态修正泛型对应的TypeHandler
import com.dreawer.persistence.handler.JsonListTypeHandler;
import com.dreawer.persistence.handler.JsonTypeHandler;
import com.dreawer.persistence.utils.GenericsUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.defaults.DefaultSqlSession;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.*;
/**
* @author Leo.Xi
* @Intercepts 拦截器注解,包括一个或多个 @Signature
* @Signature 拦截的目标类信息,包括 type、method、args
* type 要拦截的接口类型
* method 接口中的方法名
* args 方法的所有入参类型
* @date 2020/1/11
* @since 1.0
*/
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class DwDaoHandlerPlugin implements Interceptor {
/** 用户缓存对象的所有字段 */
private static final LruCache<Class, List<Field>> CACHE_CLASS_FIELDS = new LruCache<>(256);
/**
* 反射获取类的所有字段,包含继承的字段
*
* @author Leo.Xi
* @date 2020/1/13
* @since 0.0.1
*/
private static List<Field> getAllFields(Class clazz) {
if (CACHE_CLASS_FIELDS.containsKey(clazz)) {
return CACHE_CLASS_FIELDS.get(clazz);
}
List<Field> allFields = GenericsUtils.getAllFields(clazz, false, false);
CACHE_CLASS_FIELDS.put(clazz, allFields);
return allFields;
}
/**
* 拦截目标对象的目标方法的执行,将自定义逻辑写在该方法中
*/
@SuppressWarnings("unchecked")
@Override
public Object intercept(Invocation invocation) throws Throwable {
// System.out.println("ExamplePlugin...intercept:" + invocation.getMethod());
// MetaObject 是 Mybatis 提供的一个用于访问对象属性的对象
MetaObject metaObject = SystemMetaObject.forObject(invocation);
// System.out.println("当前拦截到的对象:" + metaObject.getValue("target"));
// System.out.println("SQL语句:" + metaObject.getValue("target.delegate.boundSql.sql"));
// System.out.println("SQL语句类型:" + metaObject.getValue("target.delegate.parameterHandler.mappedStatement.sqlCommandType"));
Object value = metaObject.getValue("target.delegate.parameterHandler.mappedStatement.sqlCommandType");
String sqlType = null;
if (null != value) {
sqlType = value.toString();
}
if (null == sqlType) { // 不做任何处理
// 返回执行结果
return invocation.proceed();
}
// Configuration configuration = (Configuration) metaObject.getValue("target.delegate.configuration");
BoundSql boundSql = (BoundSql) metaObject.getValue("target.delegate.boundSql");
Object parameterObject = boundSql.getParameterObject();
Class<?> parameterObjectClass = parameterObject.getClass();
List<Field> allFields = getAllFields(parameterObjectClass);
for (int i = 0; i < boundSql.getParameterMappings().size(); i++) {
ParameterMapping parameterMapping = boundSql.getParameterMappings().get(i);
if (parameterMapping.getTypeHandler() instanceof JsonTypeHandler) {// 单个对象的
allFields.stream().filter(x -> x.getName().equals(parameterMapping.getProperty())).findFirst().ifPresent(c -> {
if (!parameterMapping.getJavaType().equals(c.getType())) {// 如果解析的类型不一致的话,自己设置
throw new RuntimeException("类型%s定制了JSON序列化方式故不能拥有自己的实体表结构,只能作为其他对象的属性,如若需要请转为Map插入或者List" +
"批量插入即可。");
}
});
} else if (parameterMapping.getTypeHandler() instanceof JsonListTypeHandler) { // 处理列表Json序列化的
Class clazz = null;
if (DefaultSqlSession.StrictMap.class.isAssignableFrom(parameterObjectClass)) {
// TODO 后期在处理
Object val = ((Map) parameterObject).get("collection");
if (GenericsUtils.isCollection(val) && ((List) val).size() > 0) {
// clazz = ((List)val).get(0).getClass();
}
} else if (Map.class.isAssignableFrom(parameterObjectClass)) {
// TODO 后期在处理
} else {
Optional<Field> first = allFields.stream().filter(x -> x.getName().equals(parameterMapping.getProperty())).findFirst();
if (!first.isPresent()) {
continue;
}
Field f = first.get();
f.setAccessible(true);
clazz = DwMybatisConfig.getCollectionFieldType(f);
}
DwDaoHandler.Type type = DwMybatisConfig.getCollectionType(clazz);
if (type != null) {
metaObject.setValue("target.delegate.boundSql.parameterMappings[" + i + "].typeHandler",
new JsonListTypeHandler<>(clazz));
}
}
}
// System.out.println("SQL语句入参:" + boundSql.getParameterObject());
if (SqlCommandType.SELECT.name().equalsIgnoreCase(sqlType)) {// 查询语句需要处理入参、出参
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("target.delegate.parameterHandler.mappedStatement");
List<ResultMap> resultMaps = mappedStatement.getResultMaps(); // mapperXML 的resultMap映射表
for (int i = 0; i < resultMaps.size(); i++) {
final int row = i;
ResultMap resultMap = resultMaps.get(i);
allFields = getAllFields(resultMap.getType());
for (int j = 0; j < resultMap.getResultMappings().size(); j++) {
final int index = j;
ResultMapping resultMapping = resultMap.getResultMappings().get(j);
if (resultMapping.getTypeHandler() instanceof JsonListTypeHandler) {
allFields.stream().filter(x -> x.getName().equals(resultMapping.getProperty())).findFirst().ifPresent(c -> {
Class clazz = DwMybatisConfig.getCollectionFieldType(c);
DwDaoHandler.Type type = DwMybatisConfig.getCollectionType(clazz);
if (type != null) {
metaObject.setValue("target.delegate.parameterHandler.mappedStatement.resultMaps[" + row + "]" +
".resultMappings[" + index + "].typeHandler",
new JsonListTypeHandler<>(clazz));
}
});
}
}
}
}
// System.out.println("Mapper方法全路径名:" + metaObject.getValue("target.delegate.parameterHandler.mappedStatement.id"));
// 返回执行结果
return invocation.proceed();
}
/**
* 为目标对象创建一个代理对象,使用 Plugin.wrap(target,this) 即可
*
* @param target 上次包装的代理对象
* @return 本次包装过的代理对象
*/
@Override
public Object plugin(Object target) {
// System.out.println("ExamplePlugin...plugin:" + target);
return Plugin.wrap(target, this);
}
/**
* 获取自定义配置参数
*
* @param properties
*/
@Override
public void setProperties(Properties properties) {
// System.out.println("插件配置信息:" + properties);
// System.out.println("someProperty:" + properties.get("someProperty"));
}
/**
* LRU为Least Recently Used的缩写,意思也就是近期最少使用算法。
*
* @author Leo.Xi
* @date 2020/1/13
* @since 0.0.1
*/
public static class LruCache<K, V> extends LinkedHashMap<K, V> {
int capacity = 256; // 最大容量 - 不能超过它
public LruCache(int capacity) {
super(capacity, 0.75f, true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
if (size() > this.capacity) {
return true;
}
return false;
}
}
}
后期需要的,只需要在这基础上修改一下,即可使用。
记录一下最近的实现。2020-01-13写
也希望能够帮助到你。
标签:return,自定义,TypeHandler,Type,clazz,自动,org,import,type 来源: https://blog.csdn.net/h785160953/article/details/103962069