diff --git a/boot/src/main/java/com/zfoo/boot/OrmAutoConfiguration.java b/boot/src/main/java/com/zfoo/boot/OrmAutoConfiguration.java index d845477d..2911ae44 100644 --- a/boot/src/main/java/com/zfoo/boot/OrmAutoConfiguration.java +++ b/boot/src/main/java/com/zfoo/boot/OrmAutoConfiguration.java @@ -15,12 +15,22 @@ package com.zfoo.boot; import com.zfoo.orm.OrmContext; import com.zfoo.orm.accessor.MongodbAccessor; import com.zfoo.orm.manager.OrmManager; +import com.zfoo.orm.model.anno.GraalvmNativeEntityCache; import com.zfoo.orm.model.config.OrmConfig; import com.zfoo.orm.query.MongodbQuery; +import com.zfoo.protocol.util.ClassUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.aot.hint.BindingReflectionHintsRegistrar; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportRuntimeHints; + +import java.util.HashSet; /** * @author godotg @@ -28,8 +38,11 @@ import org.springframework.context.annotation.Configuration; */ @Configuration(proxyBeanMethods = false) @ConditionalOnBean(OrmConfig.class) +@ImportRuntimeHints(OrmAutoConfiguration.GraalvmOrmHints.class) public class OrmAutoConfiguration { + private static final Logger logger = LoggerFactory.getLogger(OrmAutoConfiguration.class); + // OrmConfig in the specific business // If the OrmConfig bean is not configured in the business, then the Orm automatic assembly here will not take effect. @Bean @@ -59,4 +72,39 @@ public class OrmAutoConfiguration { return new OrmContext(); } + + // Register runtime hints for the token library + public static class GraalvmOrmHints implements RuntimeHintsRegistrar { + + private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + logger.info("orm graalvm aot runtime hints register"); + + var classes = new HashSet>(); + classes.add(OrmConfig.class); + + try { + for (var className : ClassUtils.getAllClasses("")) { + try { + var clazz = Class.forName(className); + if (!clazz.isAnnotationPresent(GraalvmNativeEntityCache.class)) { + continue; + } + classes.add(clazz); + classes.addAll(ClassUtils.relevantClass(clazz)); + } catch (Throwable t) { + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + for (var clazz : classes) { + this.bindingRegistrar.registerReflectionHints(hints.reflection(), clazz); + logger.info("orm graalvm aot hints register serialization [{}]", clazz); + } + } + } } diff --git a/boot/src/main/java/com/zfoo/boot/StorageAutoConfiguration.java b/boot/src/main/java/com/zfoo/boot/StorageAutoConfiguration.java index fd621377..1fd2c6cf 100644 --- a/boot/src/main/java/com/zfoo/boot/StorageAutoConfiguration.java +++ b/boot/src/main/java/com/zfoo/boot/StorageAutoConfiguration.java @@ -22,7 +22,9 @@ import com.zfoo.storage.model.resource.ResourceData; import com.zfoo.storage.model.resource.ResourceEnum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.aot.hint.*; +import org.springframework.aot.hint.BindingReflectionHintsRegistrar; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -37,7 +39,7 @@ import java.util.HashSet; */ @Configuration(proxyBeanMethods = false) @ConditionalOnBean(StorageConfig.class) -@ImportRuntimeHints(StorageAutoConfiguration.StorageHints.class) +@ImportRuntimeHints(StorageAutoConfiguration.GraalvmStorageHints.class) public class StorageAutoConfiguration { private static final Logger logger = LoggerFactory.getLogger(StorageAutoConfiguration.class); @@ -59,16 +61,17 @@ public class StorageAutoConfiguration { // Register runtime hints for the token library - public static class StorageHints implements RuntimeHintsRegistrar { + public static class GraalvmStorageHints implements RuntimeHintsRegistrar { private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); @Override public void registerHints(RuntimeHints hints, ClassLoader classLoader) { - logger.info("storage aot runtime hints register"); + logger.info("storage graalvm aot runtime hints register"); var classes = new HashSet>(); classes.add(ResourceData.class); + classes.add(StorageConfig.class); try { for (var className : ClassUtils.getAllClasses("")) { @@ -88,13 +91,13 @@ public class StorageAutoConfiguration { for (var clazz : classes) { this.bindingRegistrar.registerReflectionHints(hints.reflection(), clazz); - logger.info("storage aot hints register serialization [{}]", clazz); + logger.info("storage graalvm aot hints register serialization [{}]", clazz); } for (var resource : ResourceEnum.values()) { var include = StringUtils.format("*.{}", resource.getType()); hints.resources().registerPattern(include); - logger.info("storage aot hints register resources [{}]", include); + logger.info("storage graalvm aot hints register resources [{}]", include); } } } diff --git a/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java b/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java index 31f5cab4..225a30fd 100644 --- a/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java +++ b/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java @@ -34,10 +34,7 @@ import com.zfoo.orm.model.vo.IndexTextDef; import com.zfoo.protocol.collection.ArrayUtils; import com.zfoo.protocol.collection.CollectionUtils; import com.zfoo.protocol.exception.RunException; -import com.zfoo.protocol.util.AssertionUtils; -import com.zfoo.protocol.util.JsonUtils; -import com.zfoo.protocol.util.ReflectionUtils; -import com.zfoo.protocol.util.StringUtils; +import com.zfoo.protocol.util.*; import com.zfoo.util.math.RandomUtils; import com.zfoo.util.net.HostAndPort; import org.bson.Document; @@ -52,7 +49,6 @@ import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.stereotype.Component; -import java.io.IOException; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -92,7 +88,7 @@ public class OrmManager implements IOrmManager { @Override public void initBefore() { - var entityDefMap = scanEntityClass(); + var entityDefMap = entityClass(); for (var entityDef : entityDefMap.values()) { var entityCaches = new EntityCaches(entityDef); @@ -187,7 +183,7 @@ public class OrmManager implements IOrmManager { @Override public void inject() { var applicationContext = OrmContext.getApplicationContext(); - var componentBeans = applicationContext.getBeansWithAnnotation(Component.class); + var componentBeans = applicationContext.getBeansWithAnnotation(Component.class); for (var bean : componentBeans.values()) { ReflectionUtils.filterFieldsInClass(bean.getClass() , field -> field.isAnnotationPresent(EntityCachesInjection.class) @@ -259,25 +255,32 @@ public class OrmManager implements IOrmManager { return mongodbDatabase.getCollection(collection); } - private Map>, EntityDef> scanEntityClass() { - var cacheDefMap = new HashMap>, EntityDef>(); + private Map>, EntityDef> entityClass() { + var classSet = new HashSet<>(); + // in graalvm environment, PathMatchingResourcePatternResolver/CachingMetadataReaderFactory unable to use, so get it directly in the spring container + if (GraalVmUtils.isGraalVM()) { + var applicationContext = OrmContext.getApplicationContext(); + var classes = applicationContext.getBeansWithAnnotation(GraalvmNativeEntityCache.class) + .values() + .stream() + .map(it -> it.getClass()) + .collect(Collectors.toList()); + classSet.addAll(classes); + } else { + var classes = scanEntityCacheAnno(); + classSet.addAll(classes); + } - var locationSet = scanEntityCacheAnno(ormConfig.getEntityPackage()); - for (var location : locationSet) { - Class> entityClazz; - try { - entityClazz = (Class>) Class.forName(location); - } catch (ClassNotFoundException e) { - throw new RunException("无法获取实体类[{}]", location); - } - var cacheDef = parserEntityDef(entityClazz); - var previousCacheDef = cacheDefMap.putIfAbsent(entityClazz, cacheDef); - AssertionUtils.isNull(previousCacheDef, "缓存实体不能包含重复的[class:{}]", entityClazz.getSimpleName()); + var cacheDefMap = new HashMap>, EntityDef>(); + for (var clazz : classSet) { + var cacheDef = parserEntityDef((Class>) clazz); + cacheDefMap.putIfAbsent((Class>) clazz, cacheDef); } return cacheDefMap; } - private Set scanEntityCacheAnno(String scanLocation) { + private Set> scanEntityCacheAnno() { + var scanLocation = ormConfig.getEntityPackage(); var prefixPattern = "classpath*:"; var suffixPattern = "**/*.class"; @@ -287,7 +290,7 @@ public class OrmManager implements IOrmManager { try { String packageSearchPath = prefixPattern + scanLocation.replace(StringUtils.PERIOD, StringUtils.SLASH) + StringUtils.SLASH + suffixPattern; Resource[] resources = resourcePatternResolver.getResources(packageSearchPath); - Set result = new HashSet<>(); + var result = new HashSet>(); String name = EntityCache.class.getName(); for (Resource resource : resources) { if (resource.isReadable()) { @@ -295,19 +298,21 @@ public class OrmManager implements IOrmManager { AnnotationMetadata annoMeta = metadataReader.getAnnotationMetadata(); if (annoMeta.hasAnnotation(name)) { ClassMetadata clazzMeta = metadataReader.getClassMetadata(); - result.add(clazzMeta.getClassName()); + result.add(Class.forName(clazzMeta.getClassName())); } } } return result; - } catch (IOException e) { + } catch (Exception e) { throw new RuntimeException("无法读取实体信息:" + e); } } public EntityDef parserEntityDef(Class> clazz) { - analyze(clazz); + if (!GraalVmUtils.isGraalVM()) { + analyze(clazz); + } var cacheStrategies = ormConfig.getCaches(); var persisterStrategies = ormConfig.getPersisters(); diff --git a/orm/src/main/java/com/zfoo/orm/model/anno/Cache.java b/orm/src/main/java/com/zfoo/orm/model/anno/Cache.java index c58d559f..521387fd 100644 --- a/orm/src/main/java/com/zfoo/orm/model/anno/Cache.java +++ b/orm/src/main/java/com/zfoo/orm/model/anno/Cache.java @@ -13,6 +13,8 @@ package com.zfoo.orm.model.anno; +import org.springframework.aot.hint.annotation.Reflective; + import java.lang.annotation.*; /** @@ -22,6 +24,7 @@ import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) +@Reflective public @interface Cache { String value() default "default"; diff --git a/orm/src/main/java/com/zfoo/orm/model/anno/EntityCache.java b/orm/src/main/java/com/zfoo/orm/model/anno/EntityCache.java index ae106c5a..23452ba5 100644 --- a/orm/src/main/java/com/zfoo/orm/model/anno/EntityCache.java +++ b/orm/src/main/java/com/zfoo/orm/model/anno/EntityCache.java @@ -13,6 +13,8 @@ package com.zfoo.orm.model.anno; +import org.springframework.aot.hint.annotation.Reflective; + import java.lang.annotation.*; /** @@ -22,6 +24,7 @@ import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) +@Reflective public @interface EntityCache { Cache cache() default @Cache; diff --git a/orm/src/main/java/com/zfoo/orm/model/anno/EntityCachesInjection.java b/orm/src/main/java/com/zfoo/orm/model/anno/EntityCachesInjection.java index 4a795ec4..b59277f1 100644 --- a/orm/src/main/java/com/zfoo/orm/model/anno/EntityCachesInjection.java +++ b/orm/src/main/java/com/zfoo/orm/model/anno/EntityCachesInjection.java @@ -13,6 +13,8 @@ package com.zfoo.orm.model.anno; +import org.springframework.aot.hint.annotation.Reflective; + import java.lang.annotation.*; /** @@ -22,5 +24,6 @@ import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) +@Reflective public @interface EntityCachesInjection { } diff --git a/orm/src/main/java/com/zfoo/orm/model/anno/GraalvmNativeEntityCache.java b/orm/src/main/java/com/zfoo/orm/model/anno/GraalvmNativeEntityCache.java new file mode 100644 index 00000000..0293853b --- /dev/null +++ b/orm/src/main/java/com/zfoo/orm/model/anno/GraalvmNativeEntityCache.java @@ -0,0 +1,32 @@ +/* + * 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.model.anno; + +import org.springframework.aot.hint.annotation.Reflective; +import org.springframework.stereotype.Component; + +import java.lang.annotation.*; + +/** + * @author godotg + * @version 3.0 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Reflective +@Component +public @interface GraalvmNativeEntityCache { + +} diff --git a/orm/src/main/java/com/zfoo/orm/model/anno/Id.java b/orm/src/main/java/com/zfoo/orm/model/anno/Id.java index 60bb494a..abca2ef4 100644 --- a/orm/src/main/java/com/zfoo/orm/model/anno/Id.java +++ b/orm/src/main/java/com/zfoo/orm/model/anno/Id.java @@ -13,6 +13,8 @@ package com.zfoo.orm.model.anno; +import org.springframework.aot.hint.annotation.Reflective; + import java.lang.annotation.*; /** @@ -22,5 +24,6 @@ import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) +@Reflective public @interface Id { } diff --git a/orm/src/main/java/com/zfoo/orm/model/anno/Index.java b/orm/src/main/java/com/zfoo/orm/model/anno/Index.java index 3731ed1a..a4eaf066 100644 --- a/orm/src/main/java/com/zfoo/orm/model/anno/Index.java +++ b/orm/src/main/java/com/zfoo/orm/model/anno/Index.java @@ -13,6 +13,8 @@ package com.zfoo.orm.model.anno; +import org.springframework.aot.hint.annotation.Reflective; + import java.lang.annotation.*; /** @@ -22,6 +24,7 @@ import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) +@Reflective public @interface Index { boolean ascending(); diff --git a/orm/src/main/java/com/zfoo/orm/model/anno/IndexText.java b/orm/src/main/java/com/zfoo/orm/model/anno/IndexText.java index 5702b433..5cfb47f7 100644 --- a/orm/src/main/java/com/zfoo/orm/model/anno/IndexText.java +++ b/orm/src/main/java/com/zfoo/orm/model/anno/IndexText.java @@ -13,6 +13,8 @@ package com.zfoo.orm.model.anno; +import org.springframework.aot.hint.annotation.Reflective; + import java.lang.annotation.*; /** @@ -24,6 +26,7 @@ import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) +@Reflective public @interface IndexText { } diff --git a/orm/src/main/java/com/zfoo/orm/model/anno/Persister.java b/orm/src/main/java/com/zfoo/orm/model/anno/Persister.java index adb3fdfd..2d90d236 100644 --- a/orm/src/main/java/com/zfoo/orm/model/anno/Persister.java +++ b/orm/src/main/java/com/zfoo/orm/model/anno/Persister.java @@ -13,6 +13,8 @@ package com.zfoo.orm.model.anno; +import org.springframework.aot.hint.annotation.Reflective; + import java.lang.annotation.*; /** @@ -22,6 +24,7 @@ import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) +@Reflective public @interface Persister { String value() default "default"; diff --git a/orm/src/test/java/com/zfoo/orm/entity/UserEntity.java b/orm/src/test/java/com/zfoo/orm/entity/UserEntity.java index c00e2017..12a49d12 100644 --- a/orm/src/test/java/com/zfoo/orm/entity/UserEntity.java +++ b/orm/src/test/java/com/zfoo/orm/entity/UserEntity.java @@ -13,15 +13,19 @@ package com.zfoo.orm.entity; -import com.zfoo.orm.model.anno.*; +import com.zfoo.orm.model.anno.EntityCache; +import com.zfoo.orm.model.anno.Id; +import com.zfoo.orm.model.anno.Index; +import com.zfoo.orm.model.anno.IndexText; import com.zfoo.orm.model.entity.IEntity; import java.util.List; /** + * @EntityCache(persister = @Persister("time30s")) * @author godotg - * @version 3.0@EntityCache(persister = @Persister("time30s")) + * @version 3.0 */ @EntityCache public class UserEntity implements IEntity {