cache warmup abstraction with @Preload

This commit is contained in:
Mingliang Wang 2021-03-18 22:51:52 +08:00
Родитель fbb92c5268
Коммит 95b4593bb3
4 изменённых файлов: 114 добавлений и 0 удалений

Просмотреть файл

@ -89,6 +89,10 @@
<groupId>com.microsoft.azure</groupId>
<artifactId>adal4j</artifactId>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
</dependency>
</dependencies>

Просмотреть файл

@ -0,0 +1,24 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.lib.common.cache;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* to annotate methods that should be pre-executed at background
* the annotated method should have no args and must be static or in a singleton class
*/
@Target(value = {ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Preload {
}

Просмотреть файл

@ -0,0 +1,80 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.lib.common.cache;
import lombok.extern.java.Log;
import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.util.ConfigurationBuilder;
import javax.annotation.Nullable;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
@Log
public class Preloader {
private static final String INVALID_PRELOAD_METHOD = "@Preload annotated method(%s.%s) should have (no args or only varargs) " +
"and must be (static or in a singleton class)";
public static Collection<Method> load() {
final Set<Method> methods = getPreloadingMethods();
log.log(Level.INFO, String.format("Found %d @Preload annotated methods.", methods.size()));
methods.parallelStream().forEach((m) -> {
Object instance = null;
// TODO: maybe support predefined variables, e.g. selected subscriptions
if ((m.getParameterCount() == 0 || m.isVarArgs())
&& (Modifier.isStatic(m.getModifiers()) || Objects.nonNull(instance = getSingleton(m)))) {
invoke(m, instance);
} else {
log.warning(String.format(INVALID_PRELOAD_METHOD, m.getDeclaringClass().getSimpleName(), m.getName()));
}
});
return methods;
}
private static void invoke(final Method m, final Object instance) {
try {
if (m.isVarArgs()) {
final Class<?> varargType = m.getParameterTypes()[0].getComponentType();
m.invoke(instance, Array.newInstance(varargType, 0));
} else {
m.invoke(instance);
}
} catch (final IllegalAccessException | InvocationTargetException ignored) {
// swallow all exceptions
}
}
@Nullable
private static Object getSingleton(final Method m) {
final Class<?> clazz = m.getDeclaringClass();
try {
final Method getInstance = clazz.getDeclaredMethod("getInstance");
if (Modifier.isStatic(getInstance.getModifiers()) && getInstance.getParameterCount() == 0) {
getInstance.setAccessible(true);
return getInstance.invoke(null);
}
} catch (final IllegalAccessException | InvocationTargetException | NoSuchMethodException ignored) {
// swallow all exceptions
}
return null;
}
private static Set<Method> getPreloadingMethods() {
final ConfigurationBuilder configuration = new ConfigurationBuilder()
.forPackages("com.microsoft.azure.toolkit")
.setScanners(new MethodAnnotationsScanner());
final Reflections reflections = new Reflections(configuration);
return reflections.getMethodsAnnotatedWith(Preload.class);
}
}

Просмотреть файл

@ -97,6 +97,7 @@
<google.jsr305.version>3.0.0</google.jsr305.version>
<free.port.finder.version>1.0</free.port.finder.version>
<jjwt.version>0.9.1</jjwt.version>
<reflections.version>0.9.12</reflections.version>
</properties>
<dependencyManagement>
@ -279,6 +280,11 @@
<artifactId>commons-collections4</artifactId>
<version>${commons.collections4.version}</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>${reflections.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>