mirror of
https://gitee.com/devlive-community/datacap.git
synced 2024-11-29 18:48:23 +08:00
feat(plugin): support annotation service
This commit is contained in:
parent
fd8f3112ee
commit
a9ce7e989c
@ -160,6 +160,10 @@ public abstract class Plugin
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置服务
|
||||
* Configure services
|
||||
*/
|
||||
/**
|
||||
* 配置服务
|
||||
* Configure services
|
||||
@ -167,7 +171,20 @@ public abstract class Plugin
|
||||
private void configureServices()
|
||||
{
|
||||
getServiceTypes().forEach(serviceType -> {
|
||||
ServiceBindings bindings = ServiceSpiLoader.loadServices(serviceType, Thread.currentThread().getContextClassLoader());
|
||||
// 获取包路径,默认使用插件类所在包
|
||||
// Get package path, default to the plugin's package
|
||||
String basePackage = this.getClass().getPackage().getName();
|
||||
|
||||
// 同时使用SPI和注解两种方式加载服务
|
||||
// Load services using both SPI and annotation methods
|
||||
ServiceBindings bindings = null;
|
||||
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
if (pluginClassLoader != null) {
|
||||
bindings = ServiceSpiLoader.loadServices(serviceType, basePackage, pluginClassLoader);
|
||||
}
|
||||
else {
|
||||
bindings = ServiceSpiLoader.loadServices(serviceType, basePackage, contextClassLoader);
|
||||
}
|
||||
|
||||
// 支持多个实现
|
||||
// Support multiple implementations
|
||||
@ -305,7 +322,7 @@ public abstract class Plugin
|
||||
}
|
||||
|
||||
// 获取所有服务
|
||||
// Get all services
|
||||
// Get all services
|
||||
public <T extends Service> Set<T> getAllServices(Class<T> serviceClass)
|
||||
{
|
||||
validateInjector();
|
||||
@ -316,8 +333,11 @@ public abstract class Plugin
|
||||
if (pluginClassLoader != null) {
|
||||
return PluginContextManager.runWithClassLoader(pluginClassLoader, () -> {
|
||||
Set<T> services = Sets.newHashSet();
|
||||
// 获取包路径,默认使用插件类所在包
|
||||
// Get package path, default to the plugin's package
|
||||
String basePackage = this.getClass().getPackage().getName();
|
||||
ServiceBindings bindings = ServiceSpiLoader.loadServices(
|
||||
serviceClass, pluginClassLoader);
|
||||
serviceClass, basePackage, pluginClassLoader);
|
||||
bindings.getBindings().get(serviceClass).forEach(impl -> {
|
||||
String name = impl.getSimpleName();
|
||||
services.add(getService(serviceClass, name));
|
||||
@ -327,8 +347,11 @@ public abstract class Plugin
|
||||
}
|
||||
else {
|
||||
Set<T> services = Sets.newHashSet();
|
||||
// 获取包路径,默认使用插件类所在包
|
||||
// Get package path, default to the plugin's package
|
||||
String basePackage = this.getClass().getPackage().getName();
|
||||
ServiceBindings bindings = ServiceSpiLoader.loadServices(
|
||||
serviceClass, Thread.currentThread().getContextClassLoader());
|
||||
serviceClass, basePackage, Thread.currentThread().getContextClassLoader());
|
||||
bindings.getBindings().get(serviceClass).forEach(impl -> {
|
||||
String name = impl.getSimpleName();
|
||||
services.add(getService(serviceClass, name));
|
||||
|
@ -0,0 +1,23 @@
|
||||
package io.edurt.datacap.plugin.service;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 用于标注Service实现类的注解
|
||||
* Annotation for marking Service implementation classes
|
||||
*/
|
||||
@Documented
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface InjectService
|
||||
{
|
||||
/**
|
||||
* 指定要实现的服务接口
|
||||
* Specify the service interface to implement
|
||||
*/
|
||||
Class<?>[] value() default {};
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package io.edurt.datacap.plugin.service;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.reflect.ClassPath;
|
||||
import io.edurt.datacap.plugin.Service;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
@Slf4j
|
||||
public class ServiceAnnotationScanner
|
||||
{
|
||||
/**
|
||||
* 扫描指定包下带有 @InjectService 注解的类
|
||||
* Scan classes with @InjectService annotation in the specified package
|
||||
*
|
||||
* @param basePackage 基础包路径
|
||||
* @param basePackage base package path
|
||||
* @param classLoader 类加载器
|
||||
* @param classLoader class loader
|
||||
* @return 扫描到的服务类集合
|
||||
* @return scanned service class collection
|
||||
*/
|
||||
public static Set<Class<?>> scanServices(String basePackage, ClassLoader classLoader)
|
||||
{
|
||||
Set<Class<?>> services = Sets.newHashSet();
|
||||
try {
|
||||
ClassPath classPath = ClassPath.from(classLoader);
|
||||
for (ClassPath.ClassInfo classInfo : classPath.getTopLevelClassesRecursive(basePackage)) {
|
||||
try {
|
||||
Class<?> clazz = classInfo.load();
|
||||
if (clazz.isAnnotationPresent(InjectService.class) && Service.class.isAssignableFrom(clazz)) {
|
||||
services.add(clazz);
|
||||
log.debug("Found service implementation class: {}", clazz.getName());
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
log.warn("Failed to load class: {}", classInfo.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("Error scanning for services in package: {}", basePackage, e);
|
||||
}
|
||||
return services;
|
||||
}
|
||||
}
|
@ -15,6 +15,75 @@ import java.util.Set;
|
||||
@Slf4j
|
||||
public class ServiceSpiLoader
|
||||
{
|
||||
/**
|
||||
* 加载服务实现,同时支持SPI和注解方式
|
||||
* Load service implementations, supporting both SPI and annotation methods
|
||||
*
|
||||
* @param serviceType 服务类型(必须继承自Service)
|
||||
* @param serviceType service type (must extend Service)
|
||||
* @param basePackage 扫描注解的基础包路径
|
||||
* @param basePackage base package path for annotation scanning
|
||||
* @param classLoader 类加载器
|
||||
* @param classLoader class loader
|
||||
* @return 服务绑定
|
||||
* @return service bindings
|
||||
*/
|
||||
public static ServiceBindings loadServices(Class<? extends Service> serviceType, String basePackage, ClassLoader classLoader)
|
||||
{
|
||||
ServiceBindings bindings = loadServices(serviceType, classLoader);
|
||||
|
||||
// 扫描注解
|
||||
// Scan annotations
|
||||
Set<Class<?>> annotatedServices = ServiceAnnotationScanner.scanServices(basePackage, classLoader);
|
||||
log.info("Found {} annotated services", annotatedServices.size());
|
||||
log.info("Scanned annotated services from package: {}", basePackage);
|
||||
log.debug("Annotated services: {}", annotatedServices);
|
||||
for (Class<?> serviceImpl : annotatedServices) {
|
||||
InjectService annotation = serviceImpl.getAnnotation(InjectService.class);
|
||||
if (annotation != null) {
|
||||
Class<?>[] serviceInterfaces = annotation.value();
|
||||
if (serviceInterfaces.length == 0) {
|
||||
// 如果没有指定接口,使用类实现的所有接口
|
||||
// If no interface is specified, use all interfaces implemented by the class
|
||||
addServiceBindings(bindings, (Class<? extends Service>) serviceImpl, serviceType);
|
||||
}
|
||||
else {
|
||||
// 添加指定的接口绑定
|
||||
// Add specified interface bindings
|
||||
for (Class<?> iface : serviceInterfaces) {
|
||||
if (Service.class.isAssignableFrom(iface) && serviceType.isAssignableFrom(iface)) {
|
||||
bindings.addBinding((Class<? extends Service>) iface, (Class<? extends Service>) serviceImpl);
|
||||
log.debug("Added annotated binding: {} -> {}", iface.getName(), serviceImpl.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
private static void addServiceBindings(ServiceBindings bindings, Class<? extends Service> serviceImpl, Class<? extends Service> serviceType)
|
||||
{
|
||||
// 添加直接绑定
|
||||
// Add direct binding
|
||||
if (serviceType.isAssignableFrom(serviceImpl)) {
|
||||
bindings.addBinding(serviceType, serviceImpl);
|
||||
log.debug("Added direct binding: {} -> {}", serviceType.getName(), serviceImpl.getName());
|
||||
}
|
||||
|
||||
// 检查并添加接口绑定
|
||||
// Check and add interface bindings
|
||||
for (Class<?> iface : getAllInterfaces(serviceImpl)) {
|
||||
if (serviceType.isAssignableFrom(iface)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Service> serviceInterface = (Class<? extends Service>) iface;
|
||||
bindings.addBinding(serviceInterface, serviceImpl);
|
||||
log.debug("Added interface binding: {} -> {}", serviceInterface.getName(), serviceImpl.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载服务实现
|
||||
* Load service implementations
|
||||
|
@ -0,0 +1,16 @@
|
||||
package io.edurt.datacap.test;
|
||||
|
||||
import io.edurt.datacap.plugin.service.InjectService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@InjectService
|
||||
public class AnnotationService
|
||||
implements DataService
|
||||
{
|
||||
@Override
|
||||
public void print()
|
||||
{
|
||||
log.info("Annotation Service");
|
||||
}
|
||||
}
|
@ -48,6 +48,12 @@ public class DataServiceTest
|
||||
DataService logService = value.getService(DataService.class, "LogService");
|
||||
logService.print();
|
||||
|
||||
log.info("Found annotation Service");
|
||||
AnnotationService annotationService = value.getService(AnnotationService.class);
|
||||
annotationService.print();
|
||||
DataService annotationService2 = value.getService(DataService.class, "AnnotationService");
|
||||
annotationService2.print();
|
||||
|
||||
log.info("Get all Service");
|
||||
Set<DataService> services = value.getAllServices(DataService.class);
|
||||
services.forEach(DataService::print);
|
||||
|
Loading…
Reference in New Issue
Block a user