From 1d181cc461d3012b9c3aea35e5976e3ae0801e27 Mon Sep 17 00:00:00 2001 From: zhangzhuo Date: Mon, 25 Jan 2021 11:48:08 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9B=86=E6=88=90=E6=94=AF=E6=8C=81=20SpringDo?= =?UTF-8?q?c?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../basic-example/basic-example-main/pom.xml | 6 + .../example/main/config/PluginBeanConfig.java | 16 ++ springboot-plugin-framework/pom.xml | 8 + .../starblues/extension/ExtensionFactory.java | 12 +- ...a => PluginControllerProcessorExtend.java} | 22 ++- .../support/SpringDocControllerProcessor.java | 71 +++++++++ .../bean/PluginControllerPostProcessor.java | 141 ++++++++---------- .../post/bean/model/ControllerWrapper.java | 53 +++++++ .../com/gitee/starblues/utils/ClassUtils.java | 71 +++++++++ 9 files changed, 311 insertions(+), 89 deletions(-) rename springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/{PluginControllerProcessor.java => PluginControllerProcessorExtend.java} (33%) create mode 100644 springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/support/SpringDocControllerProcessor.java create mode 100644 springboot-plugin-framework/src/main/java/com/gitee/starblues/factory/process/post/bean/model/ControllerWrapper.java create mode 100644 springboot-plugin-framework/src/main/java/com/gitee/starblues/utils/ClassUtils.java diff --git a/example/basic-example/basic-example-main/pom.xml b/example/basic-example/basic-example-main/pom.xml index 119c86e..e82ea1e 100644 --- a/example/basic-example/basic-example-main/pom.xml +++ b/example/basic-example/basic-example-main/pom.xml @@ -61,6 +61,12 @@ ${swagger-bootstrap-ui.version} + + org.springdoc + springdoc-openapi-ui + 1.5.2 + + org.springframework.boot spring-boot-starter-test diff --git a/example/basic-example/basic-example-main/src/main/java/com/basic/example/main/config/PluginBeanConfig.java b/example/basic-example/basic-example-main/src/main/java/com/basic/example/main/config/PluginBeanConfig.java index 59a6177..4f486d3 100644 --- a/example/basic-example/basic-example-main/src/main/java/com/basic/example/main/config/PluginBeanConfig.java +++ b/example/basic-example/basic-example-main/src/main/java/com/basic/example/main/config/PluginBeanConfig.java @@ -1,8 +1,14 @@ package com.basic.example.main.config; +import com.gitee.starblues.extension.support.SpringDocControllerProcessor; import com.gitee.starblues.integration.application.PluginApplication; import com.gitee.starblues.integration.application.AutoPluginApplication; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; import org.quartz.SchedulerFactory; +import org.springdoc.core.GroupedOpenApi; +import org.springdoc.core.SpringDocUtils; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -29,4 +35,14 @@ public class PluginBeanConfig { return autoPluginApplication; } + /** + * 集成 SpringDoc 的插件刷新 + * @param applicationContext ApplicationContext + * @return SpringDocControllerProcessor + */ + @Bean + public SpringDocControllerProcessor springDocControllerProcessor(ApplicationContext applicationContext){ + return new SpringDocControllerProcessor(applicationContext); + } + } diff --git a/springboot-plugin-framework/pom.xml b/springboot-plugin-framework/pom.xml index 8007df9..8b27d1e 100644 --- a/springboot-plugin-framework/pom.xml +++ b/springboot-plugin-framework/pom.xml @@ -71,6 +71,7 @@ 5.0.7.RELEASE 2.4.1 2.10.5 + 1.5.2 4.0.1 4.11 @@ -128,6 +129,13 @@ provided + + org.springdoc + springdoc-openapi-ui + ${springdoc.version} + provided + + javax.servlet javax.servlet-api diff --git a/springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/ExtensionFactory.java b/springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/ExtensionFactory.java index 5c2f44c..90d438d 100644 --- a/springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/ExtensionFactory.java +++ b/springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/ExtensionFactory.java @@ -1,5 +1,6 @@ package com.gitee.starblues.extension; +import com.gitee.starblues.utils.PluginBeanUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; @@ -7,7 +8,6 @@ import org.springframework.util.StringUtils; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Consumer; /** * 静态的扩展工厂 @@ -40,6 +40,16 @@ public class ExtensionFactory { PLUGIN_EXTENSION_MAP.put(key, abstractExtension); } + /** + * 得到PluginControllerProcessorExtend的实现 + * @param mainApplicationContext 主程序的 ApplicationContext + * @return PluginControllerProcessorExtend 的实现对象集合 + */ + public static List getPluginControllerProcessorExtend(ApplicationContext mainApplicationContext){ + return PluginBeanUtils.getPluginBeans(mainApplicationContext, + PluginControllerProcessorExtend.class); + } + static Map getPluginExtension() { return Collections.unmodifiableMap(PLUGIN_EXTENSION_MAP); diff --git a/springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/PluginControllerProcessor.java b/springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/PluginControllerProcessorExtend.java similarity index 33% rename from springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/PluginControllerProcessor.java rename to springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/PluginControllerProcessorExtend.java index 4ee6d2d..a5738b2 100644 --- a/springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/PluginControllerProcessor.java +++ b/springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/PluginControllerProcessorExtend.java @@ -1,28 +1,36 @@ package com.gitee.starblues.extension; +import com.gitee.starblues.factory.process.post.bean.model.ControllerWrapper; + +import java.util.List; + /** - * controller 处理者(已经废弃) + * 可扩展的 controller 处理者 * * @author starBlues * @version 2.4.0 */ -@Deprecated -public interface PluginControllerProcessor { +public interface PluginControllerProcessorExtend { + + /** + * 初始化 + */ + void initialize(); /** * 注册 * @param pluginId 插件id - * @param controllerClass controller 类 + * @param controllerWrappers controller 类集合 * @throws Exception 异常 */ - void registry(String pluginId, Class controllerClass) throws Exception; + void registry(String pluginId, List controllerWrappers) throws Exception; /** * 注册 * @param pluginId 插件id - * @param controllerClass controller 类 + * @param controllerWrappers controller 类集合 * @throws Exception 异常 */ - void unRegistry(String pluginId, Class controllerClass) throws Exception; + void unRegistry(String pluginId, List controllerWrappers) throws Exception; } diff --git a/springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/support/SpringDocControllerProcessor.java b/springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/support/SpringDocControllerProcessor.java new file mode 100644 index 0000000..04337cd --- /dev/null +++ b/springboot-plugin-framework/src/main/java/com/gitee/starblues/extension/support/SpringDocControllerProcessor.java @@ -0,0 +1,71 @@ +package com.gitee.starblues.extension.support; + +import com.gitee.starblues.extension.PluginControllerProcessorExtend; +import com.gitee.starblues.factory.process.post.bean.model.ControllerWrapper; +import com.gitee.starblues.utils.ClassUtils; +import com.gitee.starblues.utils.PluginBeanUtils; +import org.springdoc.api.AbstractOpenApiResource; +import org.springdoc.core.OpenAPIService; +import org.springframework.context.ApplicationContext; + +import java.util.List; + +/** + * @author starBlues + * @version 2.4.0 + */ +public class SpringDocControllerProcessor implements PluginControllerProcessorExtend { + + private final ApplicationContext applicationContext; + + private List> restControllers; + private OpenAPIService openAPIService; + + public SpringDocControllerProcessor(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + + @Override + public void initialize() { + AbstractOpenApiResource openApiResource = PluginBeanUtils.getExistBean(applicationContext, AbstractOpenApiResource.class); + if(openApiResource == null){ + return; + } + try { + restControllers = ClassUtils.getReflectionField(openApiResource, + "ADDITIONAL_REST_CONTROLLERS"); + } catch (IllegalAccessException e) { + restControllers = null; + } + openAPIService = PluginBeanUtils.getExistBean(applicationContext, OpenAPIService.class); + } + + @Override + public void registry(String pluginId, List controllerWrappers) throws Exception { + if(restControllers != null){ + for (ControllerWrapper controllerWrapper : controllerWrappers) { + restControllers.add(controllerWrapper.getBeanClass()); + } + refresh(); + } + } + + @Override + public void unRegistry(String pluginId, List controllerWrappers) throws Exception { + if(restControllers != null && !restControllers.isEmpty()){ + for (ControllerWrapper controllerWrapper : controllerWrappers) { + restControllers.remove(controllerWrapper.getBeanClass()); + } + refresh(); + } + } + + private void refresh(){ + if(openAPIService != null){ + openAPIService.setCachedOpenAPI(null); + openAPIService.resetCalculatedOpenAPI(); + } + } + +} diff --git a/springboot-plugin-framework/src/main/java/com/gitee/starblues/factory/process/post/bean/PluginControllerPostProcessor.java b/springboot-plugin-framework/src/main/java/com/gitee/starblues/factory/process/post/bean/PluginControllerPostProcessor.java index 9d6a776..eab817f 100644 --- a/springboot-plugin-framework/src/main/java/com/gitee/starblues/factory/process/post/bean/PluginControllerPostProcessor.java +++ b/springboot-plugin-framework/src/main/java/com/gitee/starblues/factory/process/post/bean/PluginControllerPostProcessor.java @@ -1,8 +1,11 @@ package com.gitee.starblues.factory.process.post.bean; +import com.gitee.starblues.extension.ExtensionFactory; +import com.gitee.starblues.extension.PluginControllerProcessorExtend; import com.gitee.starblues.factory.PluginRegistryInfo; import com.gitee.starblues.factory.process.pipe.classs.group.ControllerGroup; import com.gitee.starblues.factory.process.post.PluginPostProcessor; +import com.gitee.starblues.factory.process.post.bean.model.ControllerWrapper; import com.gitee.starblues.integration.IntegrationConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,6 +22,7 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.*; +import java.util.function.Consumer; /** * 插件中controller处理者 @@ -35,16 +39,28 @@ public class PluginControllerPostProcessor implements PluginPostProcessor { private final RequestMappingHandlerMapping requestMappingHandlerMapping; private final IntegrationConfiguration configuration; - public PluginControllerPostProcessor(ApplicationContext applicationContext){ - Objects.requireNonNull(applicationContext); - this.requestMappingHandlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class); - this.configuration = applicationContext.getBean(IntegrationConfiguration.class); + private final List pluginControllerProcessors; + + public PluginControllerPostProcessor(ApplicationContext mainApplicationContext){ + Objects.requireNonNull(mainApplicationContext); + this.requestMappingHandlerMapping = mainApplicationContext.getBean(RequestMappingHandlerMapping.class); + this.configuration = mainApplicationContext.getBean(IntegrationConfiguration.class); + this.pluginControllerProcessors = ExtensionFactory + .getPluginControllerProcessorExtend(mainApplicationContext); } @Override public void initialize() throws Exception { - + resolveProcessExtend(extend->{ + try { + extend.initialize(); + }catch (Exception e){ + log.error("'{}' initialize error", + extend.getClass().getName(), + e); + } + }); } @Override @@ -54,19 +70,29 @@ public class PluginControllerPostProcessor implements PluginPostProcessor { if(groupClasses == null || groupClasses.isEmpty()){ continue; } - List controllerBeanWrappers = new ArrayList<>(); + String pluginId = pluginRegistryInfo.getPluginWrapper().getPluginId(); + List controllerBeanWrappers = new ArrayList<>(); for (Class groupClass : groupClasses) { if(groupClass == null){ continue; } try { - ControllerBeanWrapper controllerBeanWrapper = registry(pluginRegistryInfo, groupClass); + ControllerWrapper controllerBeanWrapper = registry(pluginRegistryInfo, groupClass); controllerBeanWrappers.add(controllerBeanWrapper); } catch (Exception e){ pluginRegistryInfo.addProcessorInfo(getKey(pluginRegistryInfo), controllerBeanWrappers); throw e; } } + resolveProcessExtend(extend->{ + try { + extend.registry(pluginId, controllerBeanWrappers); + }catch (Exception e){ + log.error("'{}' process plugin[{}] error in registry", + extend.getClass().getName(), + pluginId, e); + } + }); pluginRegistryInfo.addProcessorInfo(getKey(pluginRegistryInfo), controllerBeanWrappers); } } @@ -76,17 +102,27 @@ public class PluginControllerPostProcessor implements PluginPostProcessor { @Override public void unRegistry(List pluginRegistryInfos) { for (PluginRegistryInfo pluginRegistryInfo : pluginRegistryInfos) { - List controllerBeanWrappers = + List controllerBeanWrappers = pluginRegistryInfo.getProcessorInfo(getKey(pluginRegistryInfo)); if(controllerBeanWrappers == null || controllerBeanWrappers.isEmpty()){ continue; } - for (ControllerBeanWrapper controllerBeanWrapper : controllerBeanWrappers) { + String pluginId = pluginRegistryInfo.getPluginWrapper().getPluginId(); + for (ControllerWrapper controllerBeanWrapper : controllerBeanWrappers) { if(controllerBeanWrapper == null){ continue; } unregister(controllerBeanWrapper); } + resolveProcessExtend(extend->{ + try { + extend.unRegistry(pluginId, controllerBeanWrappers); + }catch (Exception e){ + log.error("'{}' process plugin[{}] error in unRegistry", + extend.getClass().getName(), + pluginId, e); + } + }); } } @@ -97,13 +133,13 @@ public class PluginControllerPostProcessor implements PluginPostProcessor { * @return ControllerBeanWrapper * @throws Exception Exception */ - private ControllerBeanWrapper registry(PluginRegistryInfo pluginRegistryInfo, Class aClass) + private ControllerWrapper registry(PluginRegistryInfo pluginRegistryInfo, Class aClass) throws Exception { String pluginId = pluginRegistryInfo.getPluginWrapper().getPluginId(); GenericApplicationContext pluginApplicationContext = pluginRegistryInfo.getPluginApplicationContext(); try { Object object = pluginApplicationContext.getBean(aClass); - ControllerBeanWrapper controllerBeanWrapper = new ControllerBeanWrapper(); + ControllerWrapper controllerBeanWrapper = new ControllerWrapper(); setPathPrefix(pluginId, aClass); Method getMappingForMethod = ReflectionUtils.findMethod(RequestMappingHandlerMapping.class, "getMappingForMethod", Method.class, Class.class); @@ -132,7 +168,7 @@ public class PluginControllerPostProcessor implements PluginPostProcessor { * 卸载具体的Controller操作 * @param controllerBeanWrapper controllerBean包装 */ - private void unregister(ControllerBeanWrapper controllerBeanWrapper) { + private void unregister(ControllerWrapper controllerBeanWrapper) { Set requestMappingInfos = controllerBeanWrapper.getRequestMappingInfos(); if(requestMappingInfos != null && !requestMappingInfos.isEmpty()){ for (RequestMappingInfo requestMappingInfo : requestMappingInfos) { @@ -141,6 +177,18 @@ public class PluginControllerPostProcessor implements PluginPostProcessor { } } + /** + * 调用扩展出的接口控制器 + * @param extendConsumer 扩展消费者 + */ + private void resolveProcessExtend(Consumer extendConsumer){ + if(pluginControllerProcessors == null || pluginControllerProcessors.isEmpty()){ + return; + } + for (PluginControllerProcessorExtend pluginControllerProcessor : pluginControllerProcessors) { + extendConsumer.accept(pluginControllerProcessor); + } + } /** * 得到往RegisterPluginInfo->processorInfo 保存的key @@ -203,8 +251,6 @@ public class PluginControllerPostProcessor implements PluginPostProcessor { } } - - /** * 拼接路径 * @param path1 路径1 @@ -243,74 +289,7 @@ public class PluginControllerPostProcessor implements PluginPostProcessor { } } -// private void process(int type, String pluginId, Class aClass){ -// PluginControllerProcessor pluginControllerProcessor = null; -// try { -// pluginControllerProcessor = applicationContext.getBean(PluginControllerProcessor.class); -// }catch (Exception e){ -// pluginControllerProcessor = null; -// } -// if(pluginControllerProcessor == null){ -// return; -// } -// if(type == 1){ -// try { -// pluginControllerProcessor.registry(pluginId, aClass); -// }catch (Exception e){ -// log.error("PluginControllerProcessor process {} {} error of registry", -// pluginId, aClass.getName()); -// } -// } else { -// try { -// pluginControllerProcessor.unRegistry(pluginId, aClass); -// }catch (Exception e){ -// log.error("PluginControllerProcessor process {} {} error of unRegistry", -// pluginId, aClass.getName()); -// } -// } -// -// } - - /** - * Controller Bean的包装 - */ - public static final class ControllerBeanWrapper{ - /** - * controller bean 名称 - */ - private String beanName; - - private Class beanClass; - - /** - * controller 的 RequestMappingInfo 集合 - */ - private Set requestMappingInfos; - - public Class getBeanClass() { - return beanClass; - } - - public void setBeanClass(Class beanClass) { - this.beanClass = beanClass; - } - public String getBeanName() { - return beanName; - } - - public void setBeanName(String beanName) { - this.beanName = beanName; - } - - public Set getRequestMappingInfos() { - return requestMappingInfos; - } - - public void setRequestMappingInfos(Set requestMappingInfos) { - this.requestMappingInfos = requestMappingInfos; - } - } } diff --git a/springboot-plugin-framework/src/main/java/com/gitee/starblues/factory/process/post/bean/model/ControllerWrapper.java b/springboot-plugin-framework/src/main/java/com/gitee/starblues/factory/process/post/bean/model/ControllerWrapper.java new file mode 100644 index 0000000..ffe7f9b --- /dev/null +++ b/springboot-plugin-framework/src/main/java/com/gitee/starblues/factory/process/post/bean/model/ControllerWrapper.java @@ -0,0 +1,53 @@ +package com.gitee.starblues.factory.process.post.bean.model; + +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; + +import java.util.Set; + +/** + * controller 包装 + * @author starBlues + * @version 2.4.0 + */ +public class ControllerWrapper { + + /** + * controller bean 名称 + */ + private String beanName; + + /** + * controller bean 类型 + */ + private Class beanClass; + + /** + * controller 的 RequestMappingInfo 集合 + */ + private Set requestMappingInfos; + + public Class getBeanClass() { + return beanClass; + } + + public void setBeanClass(Class beanClass) { + this.beanClass = beanClass; + } + + public String getBeanName() { + return beanName; + } + + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + public Set getRequestMappingInfos() { + return requestMappingInfos; + } + + public void setRequestMappingInfos(Set requestMappingInfos) { + this.requestMappingInfos = requestMappingInfos; + } + +} diff --git a/springboot-plugin-framework/src/main/java/com/gitee/starblues/utils/ClassUtils.java b/springboot-plugin-framework/src/main/java/com/gitee/starblues/utils/ClassUtils.java new file mode 100644 index 0000000..87be49c --- /dev/null +++ b/springboot-plugin-framework/src/main/java/com/gitee/starblues/utils/ClassUtils.java @@ -0,0 +1,71 @@ +package com.gitee.starblues.utils; + +import org.springframework.util.ReflectionUtils; + +import java.lang.reflect.Field; + +/** + * 类工具类 + * @author starBlues + * @version 2.4.0 + */ +public class ClassUtils { + + private ClassUtils(){ + + } + + /** + * 通过反射获取字段 + * @param o 对象 + * @param fieldName 字段名称 + * @param 字段类型 + * @return 字段值 + * @throws IllegalAccessException 异常信息 + */ + public static T getReflectionField(Object o, String fieldName) throws IllegalAccessException { + if(o == null){ + return null; + } + Field templateResolversField = ReflectionUtils.findField(o.getClass(), + fieldName); + return getReflectionField(templateResolversField, o); + } + + /** + * 通过反射获取字段 + * @param o 对象 + * @param fieldName 字段名称 + * @param 字段类型 + * @return 字段值 + * @throws IllegalAccessException 异常信息 + */ + public static T getReflectionField(Object o, String fieldName, Class fieldClassType) throws IllegalAccessException { + if(o == null){ + return null; + } + Field templateResolversField = ReflectionUtils.findField(o.getClass(), + fieldName, fieldClassType); + return getReflectionField(templateResolversField, o); + } + + /** + * 通过反射Field获取字段 + * @param field Field字段 + * @param o 当前对象 + * @param 字段类型 + * @return 字段值 + * @throws IllegalAccessException 异常信息 + */ + public static T getReflectionField(Field field, Object o) throws IllegalAccessException { + if (field == null) { + return null; + } + if(!field.isAccessible()){ + field.setAccessible(true); + } + Object fieldObject = field.get(o); + return (T) fieldObject; + } + +} -- Gitee