feat[graalvm]: orm graalvm support

This commit is contained in:
godotg
2023-09-02 18:46:02 +08:00
parent 02ae50ea10
commit 9bc3df8537
12 changed files with 146 additions and 33 deletions
@@ -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<Class<?>>();
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);
}
}
}
}
@@ -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<Class<?>>();
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);
}
}
}
@@ -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<Class<? extends IEntity<?>>, EntityDef> scanEntityClass() {
var cacheDefMap = new HashMap<Class<? extends IEntity<?>>, EntityDef>();
private Map<Class<? extends IEntity<?>>, 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<? extends IEntity<?>> entityClazz;
try {
entityClazz = (Class<? extends IEntity<?>>) 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<Class<? extends IEntity<?>>, EntityDef>();
for (var clazz : classSet) {
var cacheDef = parserEntityDef((Class<? extends IEntity<?>>) clazz);
cacheDefMap.putIfAbsent((Class<? extends IEntity<?>>) clazz, cacheDef);
}
return cacheDefMap;
}
private Set<String> scanEntityCacheAnno(String scanLocation) {
private Set<Class<?>> 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<String> result = new HashSet<>();
var result = new HashSet<Class<?>>();
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<? extends IEntity<?>> clazz) {
analyze(clazz);
if (!GraalVmUtils.isGraalVM()) {
analyze(clazz);
}
var cacheStrategies = ormConfig.getCaches();
var persisterStrategies = ormConfig.getPersisters();
@@ -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";
@@ -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;
@@ -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 {
}
@@ -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 {
}
@@ -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 {
}
@@ -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();
@@ -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 {
}
@@ -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";
@@ -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<Long> {