mirror of
https://github.com/tiennm99/zfoo.git
synced 2026-10-12 20:16:07 +00:00
feat[version]: use javassist to enhance version interface
This commit is contained in:
1 parent
1b4626e033
commit
1cb440a5f6
5 files changed
+158
-36
No files matched your search
+26
-19
@@ -21,9 +21,10 @@ import com.zfoo.orm.OrmContext;
|
||||
import com.zfoo.orm.anno.Version;
|
||||
import com.zfoo.orm.cache.persister.IOrmPersister;
|
||||
import com.zfoo.orm.cache.persister.PNode;
|
||||
import com.zfoo.orm.cache.version.CacheVersion;
|
||||
import com.zfoo.orm.cache.version.CacheVersionDefault;
|
||||
import com.zfoo.orm.cache.version.ICacheVersion;
|
||||
import com.zfoo.orm.cache.version.VersionDefault;
|
||||
import com.zfoo.orm.cache.version.VersionReflect;
|
||||
import com.zfoo.orm.cache.version.EnhanceUtils;
|
||||
import com.zfoo.orm.cache.version.IVersion;
|
||||
import com.zfoo.orm.model.EntityDef;
|
||||
import com.zfoo.orm.model.IEntity;
|
||||
import com.zfoo.orm.query.Page;
|
||||
@@ -31,10 +32,7 @@ import com.zfoo.protocol.collection.ArrayUtils;
|
||||
import com.zfoo.protocol.collection.CollectionUtils;
|
||||
import com.zfoo.protocol.exception.RunException;
|
||||
import com.zfoo.protocol.model.Pair;
|
||||
import com.zfoo.protocol.util.AssertionUtils;
|
||||
import com.zfoo.protocol.util.FieldUtils;
|
||||
import com.zfoo.protocol.util.ReflectionUtils;
|
||||
import com.zfoo.protocol.util.ThreadUtils;
|
||||
import com.zfoo.protocol.util.*;
|
||||
import com.zfoo.scheduler.manager.SchedulerBus;
|
||||
import com.zfoo.scheduler.util.LazyCache;
|
||||
import com.zfoo.scheduler.util.TimeUtils;
|
||||
@@ -61,7 +59,7 @@ public class EntityCache<PK extends Comparable<PK>, E extends IEntity<PK>> imple
|
||||
|
||||
private final LazyCache<PK, PNode<PK, E>> cache;
|
||||
|
||||
private ICacheVersion<PK, E> cacheVersion = new CacheVersionDefault<>();
|
||||
private IVersion version = VersionDefault.DEFAULT;
|
||||
|
||||
|
||||
public EntityCache(EntityDef entityDef) {
|
||||
@@ -72,7 +70,16 @@ public class EntityCache<PK extends Comparable<PK>, E extends IEntity<PK>> imple
|
||||
var filed = versionFields[0];
|
||||
var getMethod = ReflectionUtils.getMethodByNameInPOJOClass(clazz, FieldUtils.fieldToGetMethod(clazz, filed));
|
||||
var setMethod = ReflectionUtils.getMethodByNameInPOJOClass(clazz, FieldUtils.fieldToSetMethod(clazz, filed), filed.getType());
|
||||
cacheVersion = new CacheVersion<>(filed.getName(), getMethod, setMethod);
|
||||
var cacheVersionReflect = new VersionReflect(clazz, getMethod, setMethod, filed.getName());
|
||||
if (GraalVmUtils.isGraalVM()) {
|
||||
version = cacheVersionReflect;
|
||||
} else {
|
||||
try {
|
||||
version = EnhanceUtils.createEventReceiver(cacheVersionReflect);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var removeCallback = new BiConsumer<Pair<PK, PNode<PK, E>>, LazyCache.RemovalCause>() {
|
||||
@@ -97,11 +104,11 @@ public class EntityCache<PK extends Comparable<PK>, E extends IEntity<PK>> imple
|
||||
public void run() {
|
||||
var collection = OrmContext.getOrmManager().getCollection(entityClass);
|
||||
|
||||
var version = cacheVersion.gvs(entity);
|
||||
cacheVersion.svs(entity, version + 1);
|
||||
var currentVersion = version.gvs(entity);
|
||||
version.svs(entity, currentVersion + 1);
|
||||
|
||||
var filter = cacheVersion.gvs(entity) > 0
|
||||
? Filters.and(Filters.eq("_id", entity.id()), Filters.eq(cacheVersion.versionField(), version))
|
||||
var filter = version.gvs(entity) > 0
|
||||
? Filters.and(Filters.eq("_id", entity.id()), Filters.eq(version.name(), currentVersion))
|
||||
: Filters.eq("_id", entity.id());
|
||||
var result = collection.replaceOne(filter, entity);
|
||||
if (result.getModifiedCount() <= 0) {
|
||||
@@ -336,11 +343,11 @@ public class EntityCache<PK extends Comparable<PK>, E extends IEntity<PK>> imple
|
||||
|
||||
var batchList = currentUpdateList.stream()
|
||||
.map(it -> {
|
||||
var version = cacheVersion.gvs(it);
|
||||
cacheVersion.svs(it, version + 1);
|
||||
var currentVersion = version.gvs(it);
|
||||
version.svs(it, currentVersion + 1);
|
||||
|
||||
var filter = cacheVersion.gvs(it) > 0
|
||||
? Filters.and(Filters.eq("_id", it.id()), Filters.eq(cacheVersion.versionField(), version))
|
||||
var filter = version.gvs(it) > 0
|
||||
? Filters.and(Filters.eq("_id", it.id()), Filters.eq(version.name(), currentVersion))
|
||||
: Filters.eq("_id", it.id());
|
||||
|
||||
return new ReplaceOneModel<>(filter, it);
|
||||
@@ -387,8 +394,8 @@ public class EntityCache<PK extends Comparable<PK>, E extends IEntity<PK>> imple
|
||||
}
|
||||
|
||||
// 如果没有版本号,则直接更新数据库
|
||||
var entityVersion = cacheVersion.gvs(entity);
|
||||
var dbEntityVersion = cacheVersion.gvs(dbEntity);
|
||||
var entityVersion = version.gvs(entity);
|
||||
var dbEntityVersion = version.gvs(dbEntity);
|
||||
if (entityVersion <= 0) {
|
||||
OrmContext.getAccessor().update(entity);
|
||||
continue;
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.zfoo.orm.cache.version;
|
||||
|
||||
import com.zfoo.orm.model.IEntity;
|
||||
import com.zfoo.protocol.util.StringUtils;
|
||||
import com.zfoo.protocol.util.UuidUtils;
|
||||
import javassist.*;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* @author godotg
|
||||
*/
|
||||
public abstract class EnhanceUtils {
|
||||
|
||||
static {
|
||||
// 适配Tomcat,因为Tomcat不是用的默认的类加载器,而Javassist用的是默认的加载器
|
||||
var classArray = new Class<?>[]{
|
||||
IVersion.class
|
||||
};
|
||||
|
||||
var classPool = ClassPool.getDefault();
|
||||
|
||||
for (var clazz : classArray) {
|
||||
if (classPool.find(clazz.getName()) == null) {
|
||||
ClassClassPath classPath = new ClassClassPath(clazz);
|
||||
classPool.insertClassPath(classPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IVersion createEventReceiver(VersionReflect cacheVersion) throws NotFoundException, CannotCompileException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
var classPool = ClassPool.getDefault();
|
||||
|
||||
Class<?> clazz = cacheVersion.getEntityClass();
|
||||
Method getVersionMethod = cacheVersion.getGetVersionMethod();
|
||||
Method setVersionMethod = cacheVersion.getSetVersionMethod();
|
||||
|
||||
// 定义类名称
|
||||
CtClass enhanceClazz = classPool.makeClass(EnhanceUtils.class.getName() + UuidUtils.getLocalIntId());
|
||||
enhanceClazz.addInterface(classPool.get(IVersion.class.getName()));
|
||||
|
||||
// 定义类实现的接口方法name
|
||||
CtMethod nameMethod = new CtMethod(classPool.get(String.class.getName()), "name", null, enhanceClazz);
|
||||
nameMethod.setModifiers(Modifier.PUBLIC + Modifier.FINAL);
|
||||
String nameMethodBody = StringUtils.format("{ return \"{}\"; }", cacheVersion.name());
|
||||
nameMethod.setBody(nameMethodBody);
|
||||
enhanceClazz.addMethod(nameMethod);
|
||||
|
||||
// 定义类实现的接口方法gvs
|
||||
CtMethod gvsMethod = new CtMethod(classPool.get(long.class.getName()), "gvs", classPool.get(new String[]{IEntity.class.getName()}), enhanceClazz);
|
||||
gvsMethod.setModifiers(Modifier.PUBLIC + Modifier.FINAL);
|
||||
String gvsMethodBody = StringUtils.format("{ return (({})$1).{}(); }", clazz.getName(), getVersionMethod.getName());
|
||||
gvsMethod.setBody(gvsMethodBody);
|
||||
enhanceClazz.addMethod(gvsMethod);
|
||||
|
||||
// 定义类实现的接口方法svs
|
||||
CtMethod svsMethod = new CtMethod(classPool.get(void.class.getName()), "svs", classPool.get(new String[]{IEntity.class.getName(), long.class.getName()}), enhanceClazz);
|
||||
svsMethod.setModifiers(Modifier.PUBLIC + Modifier.FINAL);
|
||||
String svsMethodBody = StringUtils.format("{ (({})$1).{}($2); }", clazz.getName(), setVersionMethod.getName());
|
||||
svsMethod.setBody(svsMethodBody);
|
||||
enhanceClazz.addMethod(svsMethod);
|
||||
|
||||
// 释放缓存
|
||||
enhanceClazz.detach();
|
||||
|
||||
Class<?> resultClazz = enhanceClazz.toClass(IVersion.class);
|
||||
return (IVersion) resultClazz.newInstance();
|
||||
}
|
||||
}
|
||||
+7
-9
@@ -18,11 +18,12 @@ import com.zfoo.orm.model.IEntity;
|
||||
/**
|
||||
* @author godotg
|
||||
*/
|
||||
public interface ICacheVersion<PK extends Comparable<PK>, E extends IEntity<PK>> {
|
||||
public interface IVersion {
|
||||
|
||||
default String versionField() {
|
||||
return "version";
|
||||
}
|
||||
/**
|
||||
* version field的名称
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* 一个文档的写入到数据库的version版本,version的get和set方法
|
||||
@@ -38,11 +39,8 @@ public interface ICacheVersion<PK extends Comparable<PK>, E extends IEntity<PK>>
|
||||
* <p>
|
||||
* 分布式环境下,要想服务器性能好,就要做成有状态的,有状态就要遇到这种多服对同一条数据写入问题,这是一个千古难以解决的问题,进退两难。
|
||||
*/
|
||||
default long gvs(E entity) {
|
||||
return 0L;
|
||||
}
|
||||
long gvs(IEntity<?> entity);
|
||||
|
||||
default void svs(E entity, long vs) {
|
||||
}
|
||||
void svs(IEntity<?> entity, long vs);
|
||||
|
||||
}
|
||||
+17
-1
@@ -12,12 +12,28 @@
|
||||
|
||||
package com.zfoo.orm.cache.version;
|
||||
|
||||
|
||||
import com.zfoo.orm.model.IEntity;
|
||||
|
||||
/**
|
||||
* @author godotg
|
||||
*/
|
||||
public class CacheVersionDefault<PK extends Comparable<PK>, E extends IEntity<PK>> implements ICacheVersion<PK, E> {
|
||||
public class VersionDefault implements IVersion {
|
||||
|
||||
public static final VersionDefault DEFAULT = new VersionDefault();
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "version";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long gvs(IEntity<?> entity) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void svs(IEntity<?> entity, long vs) {
|
||||
|
||||
}
|
||||
}
|
||||
+25
-7
@@ -20,31 +20,49 @@ import java.lang.reflect.Method;
|
||||
/**
|
||||
* @author godotg
|
||||
*/
|
||||
public class CacheVersion<PK extends Comparable<PK>, E extends IEntity<PK>> implements ICacheVersion<PK, E> {
|
||||
public class VersionReflect implements IVersion {
|
||||
|
||||
private String versionFiled;
|
||||
private Class<? extends IEntity<?>> entityClass;
|
||||
private Method getVersionMethod;
|
||||
private Method setVersionMethod;
|
||||
private String versionFiled;
|
||||
|
||||
public CacheVersion(String versionFiled, Method getVersionMethod, Method setVersionMethod) {
|
||||
this.versionFiled = versionFiled;
|
||||
public VersionReflect(Class<? extends IEntity<?>> entityClass, Method getVersionMethod, Method setVersionMethod, String versionFiled) {
|
||||
this.entityClass = entityClass;
|
||||
this.getVersionMethod = getVersionMethod;
|
||||
this.setVersionMethod = setVersionMethod;
|
||||
this.versionFiled = versionFiled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String versionField() {
|
||||
public String name() {
|
||||
return versionFiled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long gvs(E entity) {
|
||||
public long gvs(IEntity<?> entity) {
|
||||
return (long) ReflectionUtils.invokeMethod(entity, getVersionMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void svs(E entity, long vs) {
|
||||
public void svs(IEntity<?> entity, long vs) {
|
||||
ReflectionUtils.invokeMethod(entity, setVersionMethod, vs);
|
||||
}
|
||||
|
||||
|
||||
public Class<? extends IEntity<?>> getEntityClass() {
|
||||
return entityClass;
|
||||
}
|
||||
|
||||
public Method getGetVersionMethod() {
|
||||
return getVersionMethod;
|
||||
}
|
||||
|
||||
public Method getSetVersionMethod() {
|
||||
return setVersionMethod;
|
||||
}
|
||||
|
||||
public String getVersionFiled() {
|
||||
return versionFiled;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user