From e13cdd424a65dc30fca9612dbd211aaa984e5014 Mon Sep 17 00:00:00 2001 From: godotg Date: Mon, 1 Jul 2024 15:12:35 +0800 Subject: [PATCH] ref[IEntityWrapper]: wrap entity method --- .../java/com/zfoo/orm/cache/EntityCache.java | 59 +++++----- .../orm/cache/version/VersionDefault.java | 39 ------- .../orm/cache/version/VersionReflect.java | 68 ----------- .../{version => wrapper}/EnhanceUtils.java | 54 ++++++--- .../zfoo/orm/cache/wrapper/EntityWrapper.java | 106 ++++++++++++++++++ .../IEntityWrapper.java} | 8 +- .../com/zfoo/orm/cache/EntityCachesTest.java | 14 ++- 7 files changed, 186 insertions(+), 162 deletions(-) delete mode 100644 orm/src/main/java/com/zfoo/orm/cache/version/VersionDefault.java delete mode 100644 orm/src/main/java/com/zfoo/orm/cache/version/VersionReflect.java rename orm/src/main/java/com/zfoo/orm/cache/{version => wrapper}/EnhanceUtils.java (51%) create mode 100644 orm/src/main/java/com/zfoo/orm/cache/wrapper/EntityWrapper.java rename orm/src/main/java/com/zfoo/orm/cache/{version/IVersion.java => wrapper/IEntityWrapper.java} (94%) diff --git a/orm/src/main/java/com/zfoo/orm/cache/EntityCache.java b/orm/src/main/java/com/zfoo/orm/cache/EntityCache.java index fb265b5a..411cfa9b 100644 --- a/orm/src/main/java/com/zfoo/orm/cache/EntityCache.java +++ b/orm/src/main/java/com/zfoo/orm/cache/EntityCache.java @@ -18,21 +18,20 @@ import com.mongodb.client.model.Filters; import com.mongodb.client.model.ReplaceOneModel; import com.zfoo.event.manager.EventBus; 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.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.cache.wrapper.EnhanceUtils; +import com.zfoo.orm.cache.wrapper.EntityWrapper; +import com.zfoo.orm.cache.wrapper.IEntityWrapper; import com.zfoo.orm.model.EntityDef; import com.zfoo.orm.model.IEntity; import com.zfoo.orm.query.Page; -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.*; +import com.zfoo.protocol.util.AssertionUtils; +import com.zfoo.protocol.util.GraalVmUtils; +import com.zfoo.protocol.util.ThreadUtils; import com.zfoo.scheduler.manager.SchedulerBus; import com.zfoo.scheduler.util.LazyCache; import com.zfoo.scheduler.util.TimeUtils; @@ -59,29 +58,23 @@ public class EntityCache, E extends IEntity> imple private final LazyCache> cache; - private IVersion version = VersionDefault.DEFAULT; + private IEntityWrapper wrapper; public EntityCache(EntityDef entityDef) { - var clazz = entityDef.getClazz(); // 创建CacheVersion - var versionFields = ReflectionUtils.getFieldsByAnnoInPOJOClass(clazz, Version.class); - if (ArrayUtils.isNotEmpty(versionFields)) { - var filed = versionFields[0]; - var getMethod = ReflectionUtils.getMethodByNameInPOJOClass(clazz, FieldUtils.fieldToGetMethod(clazz, filed)); - var setMethod = ReflectionUtils.getMethodByNameInPOJOClass(clazz, FieldUtils.fieldToSetMethod(clazz, filed), filed.getType()); - var cacheVersionReflect = new VersionReflect(clazz, getMethod, setMethod, filed.getName()); - if (GraalVmUtils.isGraalVM()) { - version = cacheVersionReflect; - } else { - try { - version = EnhanceUtils.createVersion(cacheVersionReflect); - } catch (Exception e) { - throw new RuntimeException(e); - } + var entityWrapper = new EntityWrapper(entityDef.getClazz()); + if (GraalVmUtils.isGraalVM()) { + wrapper = entityWrapper; + } else { + try { + wrapper = EnhanceUtils.createEntityWrapper(entityWrapper); + } catch (Exception e) { + throw new RuntimeException(e); } } + var removeCallback = new BiConsumer>, LazyCache.RemovalCause>() { @Override public void accept(Pair> pair, LazyCache.RemovalCause removalCause) { @@ -104,11 +97,11 @@ public class EntityCache, E extends IEntity> imple public void run() { var collection = OrmContext.getOrmManager().getCollection(entityClass); - var currentVersion = version.gvs(entity); - version.svs(entity, currentVersion + 1); + var version = wrapper.gvs(entity); + wrapper.svs(entity, version + 1); - var filter = version.gvs(entity) > 0 - ? Filters.and(Filters.eq("_id", entity.id()), Filters.eq(version.name(), currentVersion)) + var filter = wrapper.gvs(entity) > 0 + ? Filters.and(Filters.eq("_id", entity.id()), Filters.eq(wrapper.versionFieldName(), version)) : Filters.eq("_id", entity.id()); var result = collection.replaceOne(filter, entity); if (result.getModifiedCount() <= 0) { @@ -342,11 +335,11 @@ public class EntityCache, E extends IEntity> imple var batchList = currentUpdateList.stream() .map(it -> { - var currentVersion = version.gvs(it); - version.svs(it, currentVersion + 1); + var version = wrapper.gvs(it); + wrapper.svs(it, version + 1); - var filter = version.gvs(it) > 0 - ? Filters.and(Filters.eq("_id", it.id()), Filters.eq(version.name(), currentVersion)) + var filter = wrapper.gvs(it) > 0 + ? Filters.and(Filters.eq("_id", it.id()), Filters.eq(wrapper.versionFieldName(), version)) : Filters.eq("_id", it.id()); return new ReplaceOneModel<>(filter, it); @@ -393,8 +386,8 @@ public class EntityCache, E extends IEntity> imple } // 如果没有版本号,则直接更新数据库 - var entityVersion = version.gvs(entity); - var dbEntityVersion = version.gvs(dbEntity); + var entityVersion = wrapper.gvs(entity); + var dbEntityVersion = wrapper.gvs(dbEntity); if (entityVersion <= 0) { OrmContext.getAccessor().update(entity); continue; diff --git a/orm/src/main/java/com/zfoo/orm/cache/version/VersionDefault.java b/orm/src/main/java/com/zfoo/orm/cache/version/VersionDefault.java deleted file mode 100644 index 36810ac5..00000000 --- a/orm/src/main/java/com/zfoo/orm/cache/version/VersionDefault.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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; - -/** - * @author godotg - */ -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) { - - } -} diff --git a/orm/src/main/java/com/zfoo/orm/cache/version/VersionReflect.java b/orm/src/main/java/com/zfoo/orm/cache/version/VersionReflect.java deleted file mode 100644 index 47a324e0..00000000 --- a/orm/src/main/java/com/zfoo/orm/cache/version/VersionReflect.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.ReflectionUtils; - -import java.lang.reflect.Method; - -/** - * @author godotg - */ -public class VersionReflect implements IVersion { - - private Class> entityClass; - private Method getVersionMethod; - private Method setVersionMethod; - private String versionFiled; - - public VersionReflect(Class> entityClass, Method getVersionMethod, Method setVersionMethod, String versionFiled) { - this.entityClass = entityClass; - this.getVersionMethod = getVersionMethod; - this.setVersionMethod = setVersionMethod; - this.versionFiled = versionFiled; - } - - @Override - public String name() { - return versionFiled; - } - - @Override - public long gvs(IEntity entity) { - return (long) ReflectionUtils.invokeMethod(entity, getVersionMethod); - } - - @Override - public void svs(IEntity entity, long vs) { - ReflectionUtils.invokeMethod(entity, setVersionMethod, vs); - } - - - public Class> getEntityClass() { - return entityClass; - } - - public Method getGetVersionMethod() { - return getVersionMethod; - } - - public Method getSetVersionMethod() { - return setVersionMethod; - } - - public String getVersionFiled() { - return versionFiled; - } -} diff --git a/orm/src/main/java/com/zfoo/orm/cache/version/EnhanceUtils.java b/orm/src/main/java/com/zfoo/orm/cache/wrapper/EnhanceUtils.java similarity index 51% rename from orm/src/main/java/com/zfoo/orm/cache/version/EnhanceUtils.java rename to orm/src/main/java/com/zfoo/orm/cache/wrapper/EnhanceUtils.java index 7047033e..40a38529 100644 --- a/orm/src/main/java/com/zfoo/orm/cache/version/EnhanceUtils.java +++ b/orm/src/main/java/com/zfoo/orm/cache/wrapper/EnhanceUtils.java @@ -10,14 +10,16 @@ * See the License for the specific language governing permissions and limitations under the License. */ -package com.zfoo.orm.cache.version; +package com.zfoo.orm.cache.wrapper; import com.zfoo.orm.model.IEntity; import com.zfoo.orm.schema.NamespaceHandler; import com.zfoo.protocol.util.StringUtils; import com.zfoo.protocol.util.UuidUtils; import javassist.*; +import org.bson.types.ObjectId; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -30,7 +32,7 @@ public abstract class EnhanceUtils { static { // 适配Tomcat,因为Tomcat不是用的默认的类加载器,而Javassist用的是默认的加载器 var classArray = new Class[]{ - IVersion.class + IEntityWrapper.class }; var classPool = ClassPool.getDefault(); @@ -43,42 +45,68 @@ public abstract class EnhanceUtils { } } - public static IVersion createVersion(VersionReflect cacheVersion) throws NotFoundException, CannotCompileException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { + public static String rawObjectId(Field idField) { + var idType = idField.getType(); + if (idType == int.class || idType == Integer.class) { + return "((Integer)$1).intValue()"; + } else if (idType == long.class || idType == Long.class) { + return "((Long)$1).longValue()"; + } else if (idType == float.class || idType == Float.class) { + return "((Float)$1).floatValue()"; + } else if (idType == double.class || idType == Double.class) { + return "((Double)$1).floatValue()"; + } else if (idType == String.class) { + return "(String)$1"; + } else { + return StringUtils.format("({})$1", ObjectId.class.getName()); + } + } + + public static IEntityWrapper createEntityWrapper(EntityWrapper entityWrapper) throws NotFoundException, CannotCompileException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { var classPool = ClassPool.getDefault(); - Class clazz = cacheVersion.getEntityClass(); - Method getVersionMethod = cacheVersion.getGetVersionMethod(); - Method setVersionMethod = cacheVersion.getSetVersionMethod(); + Class clazz = entityWrapper.getEntityClass(); + Field idField = entityWrapper.getIdField(); + Method setIdMethod = entityWrapper.getSetIdMethod(); + Method getVersionMethod = entityWrapper.getGetVersionMethod(); + Method setVersionMethod = entityWrapper.getSetVersionMethod(); // 定义类名称 CtClass enhanceClazz = classPool.makeClass(EnhanceUtils.class.getName() + StringUtils.capitalize(NamespaceHandler.ORM) + UuidUtils.getLocalIntId()); - enhanceClazz.addInterface(classPool.get(IVersion.class.getName())); + enhanceClazz.addInterface(classPool.get(IEntityWrapper.class.getName())); // 定义类实现的接口方法name - CtMethod nameMethod = new CtMethod(classPool.get(String.class.getName()), "name", null, enhanceClazz); + CtMethod newEntityMethod = new CtMethod(classPool.get(IEntity.class.getName()), "newEntity", classPool.get(new String[]{Object.class.getName()}), enhanceClazz); + newEntityMethod.setModifiers(Modifier.PUBLIC + Modifier.FINAL); + String newEntityMethodBody = StringUtils.format("{ {} entity = new {}(); entity.{}({}); return entity; }", clazz.getName(), clazz.getName(), setIdMethod.getName(), rawObjectId(idField)); + newEntityMethod.setBody(newEntityMethodBody); + enhanceClazz.addMethod(newEntityMethod); + + // 定义类实现的接口方法name + CtMethod nameMethod = new CtMethod(classPool.get(String.class.getName()), "versionFieldName", null, enhanceClazz); nameMethod.setModifiers(Modifier.PUBLIC + Modifier.FINAL); - String nameMethodBody = StringUtils.format("{ return \"{}\"; }", cacheVersion.name()); + String nameMethodBody = StringUtils.format("{ return \"{}\"; }", entityWrapper.versionFieldName()); 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()); + String gvsMethodBody = getVersionMethod == null ? "{ return 0L; }" : 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()); + String svsMethodBody = setVersionMethod == null ? "{}" : 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(); + Class resultClazz = enhanceClazz.toClass(IEntityWrapper.class); + return (IEntityWrapper) resultClazz.newInstance(); } } diff --git a/orm/src/main/java/com/zfoo/orm/cache/wrapper/EntityWrapper.java b/orm/src/main/java/com/zfoo/orm/cache/wrapper/EntityWrapper.java new file mode 100644 index 00000000..6463dac7 --- /dev/null +++ b/orm/src/main/java/com/zfoo/orm/cache/wrapper/EntityWrapper.java @@ -0,0 +1,106 @@ +/* + * 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.wrapper; + +import com.zfoo.orm.anno.Id; +import com.zfoo.orm.anno.Version; +import com.zfoo.orm.model.IEntity; +import com.zfoo.protocol.collection.ArrayUtils; +import com.zfoo.protocol.util.FieldUtils; +import com.zfoo.protocol.util.ReflectionUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * @author godotg + */ +public class EntityWrapper implements IEntityWrapper { + + private Class> entityClass; + private Field idField; + private Field versionField; + private Method setIdMethod; + private Method getVersionMethod; + private Method setVersionMethod; + + public EntityWrapper(Class> entityClass) { + this.entityClass = entityClass; + + var idFields = ReflectionUtils.getFieldsByAnnoInPOJOClass(entityClass, Id.class); + ReflectionUtils.makeAccessible(idFields[0]); + this.idField = idFields[0]; + this.setIdMethod = ReflectionUtils.getMethodByNameInPOJOClass(entityClass, FieldUtils.fieldToSetMethod(entityClass, idField), idField.getType()); + + var versionFields = ReflectionUtils.getFieldsByAnnoInPOJOClass(entityClass, Version.class); + if (ArrayUtils.isNotEmpty(versionFields)) { + this.versionField = versionFields[0]; + var getMethod = ReflectionUtils.getMethodByNameInPOJOClass(entityClass, FieldUtils.fieldToGetMethod(entityClass, versionField)); + var setMethod = ReflectionUtils.getMethodByNameInPOJOClass(entityClass, FieldUtils.fieldToSetMethod(entityClass, versionField), versionField.getType()); + this.getVersionMethod = getMethod; + this.setVersionMethod = setMethod; + } + } + + @Override + public IEntity newEntity(Object id) { + var entity = ReflectionUtils.newInstance(entityClass); + ReflectionUtils.invokeMethod(entity, setIdMethod, id); + return entity; + } + + @Override + public String versionFieldName() { + return idField.getName(); + } + + @Override + public long gvs(IEntity entity) { + if (getVersionMethod == null) { + return 0; + } + return (long) ReflectionUtils.invokeMethod(entity, getVersionMethod); + } + + @Override + public void svs(IEntity entity, long vs) { + if (setVersionMethod == null) { + return; + } + ReflectionUtils.invokeMethod(entity, setVersionMethod, vs); + } + + public Class> getEntityClass() { + return entityClass; + } + + public Field getIdField() { + return idField; + } + + public Field getVersionField() { + return versionField; + } + + public Method getSetIdMethod() { + return setIdMethod; + } + + public Method getGetVersionMethod() { + return getVersionMethod; + } + + public Method getSetVersionMethod() { + return setVersionMethod; + } +} diff --git a/orm/src/main/java/com/zfoo/orm/cache/version/IVersion.java b/orm/src/main/java/com/zfoo/orm/cache/wrapper/IEntityWrapper.java similarity index 94% rename from orm/src/main/java/com/zfoo/orm/cache/version/IVersion.java rename to orm/src/main/java/com/zfoo/orm/cache/wrapper/IEntityWrapper.java index 8b2638d3..83fffb74 100644 --- a/orm/src/main/java/com/zfoo/orm/cache/version/IVersion.java +++ b/orm/src/main/java/com/zfoo/orm/cache/wrapper/IEntityWrapper.java @@ -10,7 +10,7 @@ * See the License for the specific language governing permissions and limitations under the License. */ -package com.zfoo.orm.cache.version; +package com.zfoo.orm.cache.wrapper; import com.zfoo.orm.model.IEntity; @@ -18,12 +18,14 @@ import com.zfoo.orm.model.IEntity; /** * @author godotg */ -public interface IVersion { +public interface IEntityWrapper { + + IEntity newEntity(Object id); /** * version field的名称 */ - String name(); + String versionFieldName(); /** * 一个文档的写入到数据库的version版本,version的get和set方法 diff --git a/orm/src/test/java/com/zfoo/orm/cache/EntityCachesTest.java b/orm/src/test/java/com/zfoo/orm/cache/EntityCachesTest.java index 9c14754b..e07301fe 100644 --- a/orm/src/test/java/com/zfoo/orm/cache/EntityCachesTest.java +++ b/orm/src/test/java/com/zfoo/orm/cache/EntityCachesTest.java @@ -51,13 +51,15 @@ public class EntityCachesTest { var userEntityCaches = (IEntityCache) OrmContext.getOrmManager().getEntityCaches(UserEntity.class); for (var i = 1; i <= 10; i++) { - var entity = userEntityCaches.load((long) i); - entity.setE("update" + i); - entity.setC(i); - EventBus.asyncExecute(() -> userEntityCaches.update(entity)); - } + for (var j = 1; j <= 10; j++) { + var entity = userEntityCaches.load((long) j); + entity.setE("update" + j); + entity.setC(j); + userEntityCaches.update(entity); + } - ThreadUtils.sleep(60 * TimeUtils.MILLIS_PER_SECOND); + ThreadUtils.sleep(60 * TimeUtils.MILLIS_PER_SECOND); + } userEntityCaches.load(1L); }