diff --git a/pom.xml b/pom.xml index c715765c02f61c6d1161020fce158564bba6115c..0970aa19b590cfb7a29c6397b463736fc7a26190 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ com.gitee.starblues spring-brick-parent pom - 3.0.2 + 3.0.3 spring-brick-common diff --git a/spring-brick-bootstrap/pom.xml b/spring-brick-bootstrap/pom.xml index 730adc0fc110be1b5e129d048858d46bf3b76dfb..cf32d07c87bc0dc4ffc13fbc594c07a843896f0b 100644 --- a/spring-brick-bootstrap/pom.xml +++ b/spring-brick-bootstrap/pom.xml @@ -7,7 +7,7 @@ spring-brick-parent com.gitee.starblues - 3.0.2 + 3.0.3 spring-brick-bootstrap diff --git a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/EmptyMainApplicationContext.java b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/EmptyMainApplicationContext.java index 0321276c98ebb22c5e19fe62a551f7e2ff7018af..e4ddb241531c31ce5c4cac18e46fefd597cba2d3 100644 --- a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/EmptyMainApplicationContext.java +++ b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/EmptyMainApplicationContext.java @@ -25,7 +25,7 @@ import java.util.Set; /** * 空的MainApplicationContext实现 * @author starBlues - * @version 3.0.1 + * @version 3.0.3 */ public class EmptyMainApplicationContext implements MainApplicationContext { @@ -46,4 +46,14 @@ public class EmptyMainApplicationContext implements MainApplicationContext { return Collections.emptyMap(); } + @Override + public boolean isResolveDependency(String packageName) { + return false; + } + + @Override + public boolean isWebEnvironment() { + return false; + } + } diff --git a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginApplicationContext.java b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginApplicationContext.java index 2ed37d010bff52beae6cdfe2b5745d590b5a3e35..b6c9cb144c2c80fdad11572076ff3854c6235e9c 100644 --- a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginApplicationContext.java +++ b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginApplicationContext.java @@ -20,12 +20,14 @@ import com.gitee.starblues.bootstrap.processor.ProcessorContext; import com.gitee.starblues.core.descriptor.PluginDescriptor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.boot.web.context.WebServerApplicationContext; +import org.springframework.boot.web.server.WebServer; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * 插件ApplicationContext实现 * @author starBlues - * @version 3.0.0 + * @version 3.0.3 */ public class PluginApplicationContext extends AnnotationConfigApplicationContext { @@ -57,4 +59,5 @@ public class PluginApplicationContext extends AnnotationConfigApplicationContext public void close() { super.close(); } + } diff --git a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginDisableAutoConfiguration.java b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginDisableAutoConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..7c69c391c44890ee45e68ad11c41df9d666c38af --- /dev/null +++ b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginDisableAutoConfiguration.java @@ -0,0 +1,72 @@ +/** + * Copyright [2019-2022] [starBlues] + * + * 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.gitee.starblues.bootstrap; + +import com.gitee.starblues.utils.ObjectUtils; +import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter; +import org.springframework.boot.autoconfigure.AutoConfigurationMetadata; + +import java.util.ArrayList; +import java.util.List; + +/** + * 插件禁用的 AutoConfiguration + * + * @author starBlues + * @version 3.0.3 + */ +public class PluginDisableAutoConfiguration implements AutoConfigurationImportFilter { + + private static final List DISABLE_FUZZY_CLASSES = new ArrayList<>(); + + public PluginDisableAutoConfiguration(){ + addDisableFuzzyClasses(); + } + + private void addDisableFuzzyClasses() { + DISABLE_FUZZY_CLASSES.add("org.springframework.boot.autoconfigure.http"); + DISABLE_FUZZY_CLASSES.add("org.springframework.boot.autoconfigure.web"); + DISABLE_FUZZY_CLASSES.add("org.springframework.boot.autoconfigure.websocket"); + DISABLE_FUZZY_CLASSES.add("org.springframework.boot.autoconfigure.jackson"); + DISABLE_FUZZY_CLASSES.add("org.springframework.boot.autoconfigure.webservices"); + } + + public static boolean isDisabled(String className){ + if(ObjectUtils.isEmpty(className)){ + return false; + } + for (String disableFuzzyClass : DISABLE_FUZZY_CLASSES) { + if (className.contains(disableFuzzyClass)) { + return true; + } + } + return false; + } + + @Override + public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { + boolean[] match = new boolean[autoConfigurationClasses.length]; + for (int i = 0; i < autoConfigurationClasses.length; i++) { + String autoConfigurationClass = autoConfigurationClasses[i]; + if(autoConfigurationClass == null || "".equals(autoConfigurationClass)){ + continue; + } + match[i] = !isDisabled(autoConfigurationClass); + } + return match; + } +} diff --git a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginListableBeanFactory.java b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginListableBeanFactory.java index fda812953dfe96df79455ce6c412c62db5e3777f..5d1a8732f74a98926b76f87ae97be17f6df5b7d5 100644 --- a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginListableBeanFactory.java +++ b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginListableBeanFactory.java @@ -21,25 +21,35 @@ import com.gitee.starblues.spring.MainApplicationContext; import com.gitee.starblues.spring.SpringBeanFactory; import com.gitee.starblues.utils.ObjectUtils; import com.gitee.starblues.utils.ReflectionUtils; +import lombok.AllArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.TypeConverter; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.ScopeNotActiveException; +import org.springframework.core.ResolvableType; import org.springframework.lang.Nullable; +import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Stream; /** * 插件BeanFactory实现 * @author starBlues - * @version 3.0.0 + * @version 3.0.3 */ public class PluginListableBeanFactory extends DefaultListableBeanFactory { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final Logger logger = LoggerFactory.getLogger(PluginListableBeanFactory.class); private final MainApplicationContext applicationContext; @@ -47,20 +57,55 @@ public class PluginListableBeanFactory extends DefaultListableBeanFactory { this.applicationContext = applicationContext; } + @SuppressWarnings("unchecked") @Override public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { - + if(isDisabled(descriptor)){ + return resolveDependencyFromMain(descriptor, false); + } try { - return super.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); + Object object = super.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, + typeConverter); + + if(object instanceof ObjectProvider){ + return new PluginObjectProviderWrapper((ObjectProvider) object, descriptor); + } + return object; } catch (BeansException e){ - return resolveDependencyFromMain(descriptor); + if(e instanceof NoSuchBeanDefinitionException){ + Object dependencyBean = resolveDependencyFromMain(descriptor, true); + if(dependencyBean != null){ + return dependencyBean; + } + } + throw e; + } + } + + @Override + public void destroySingletons() { + String[] beanDefinitionNames = getBeanDefinitionNames(); + for (String beanDefinitionName : beanDefinitionNames) { + destroyBean(beanDefinitionName); } + super.destroySingletons(); + destroyAll(); } - private Object resolveDependencyFromMain(DependencyDescriptor descriptor){ + @Override + public ObjectProvider getBeanProvider(Class requiredType, boolean allowEagerInit) { + return super.getBeanProvider(requiredType, allowEagerInit); + } + + + private Object resolveDependencyFromMain(DependencyDescriptor descriptor, boolean isResolveDependency){ + String packageName = descriptor.getDependencyType().getPackage().getName(); + if(isResolveDependency && !applicationContext.isResolveDependency(packageName)){ + return null; + } String dependencyName = descriptor.getDependencyName(); SpringBeanFactory springBeanFactory = applicationContext.getSpringBeanFactory(); if(!ObjectUtils.isEmpty(dependencyName) && springBeanFactory.containsBean(dependencyName)){ @@ -74,16 +119,6 @@ public class PluginListableBeanFactory extends DefaultListableBeanFactory { } } - @Override - public void destroySingletons() { - String[] beanDefinitionNames = getBeanDefinitionNames(); - for (String beanDefinitionName : beanDefinitionNames) { - destroyBean(beanDefinitionName); - } - super.destroySingletons(); - destroyAll(); - } - private void destroyAll(){ ReflectionUtils.findField(this.getClass(), field -> { field.setAccessible(true); @@ -97,4 +132,125 @@ public class PluginListableBeanFactory extends DefaultListableBeanFactory { }); } + private boolean isDisabled(DependencyDescriptor descriptor){ + String className = descriptor.getDependencyType().getName(); + return PluginDisableAutoConfiguration.isDisabled(className); + } + + @AllArgsConstructor + private class PluginObjectProviderWrapper implements ObjectProvider { + + private final ObjectProvider pluginObjectProvider; + private final DependencyDescriptor descriptor; + + @Override + public Object getObject() throws BeansException { + if(isDisabled(descriptor)){ + return resolveDependencyFromMain(descriptor, false); + } + return pluginObjectProvider.getObject(); + } + + @Override + public Object getObject(final Object... args) throws BeansException { + if(isDisabled(descriptor)){ + SpringBeanFactory springBeanFactory = applicationContext.getSpringBeanFactory(); + return springBeanFactory.getBean(descriptor.getDependencyType(), args); + } + return pluginObjectProvider.getObject(args); + } + + @Override + @Nullable + public Object getIfAvailable() throws BeansException { + if(isDisabled(descriptor)){ + try { + return getObject(); + } catch (Exception e){ + return null; + } + } else { + return pluginObjectProvider.getIfAvailable(); + } + } + + @Override + public void ifAvailable(Consumer dependencyConsumer) throws BeansException { + if(isDisabled(descriptor)){ + Object dependency = getIfAvailable(); + if (dependency != null) { + try { + dependencyConsumer.accept(dependency); + } + catch (ScopeNotActiveException ex) { + // Ignore + } + } + } else { + pluginObjectProvider.ifAvailable(dependencyConsumer); + } + } + + @Override + @Nullable + public Object getIfUnique() throws BeansException { + if(isDisabled(descriptor)){ + Object dependency = getIfAvailable(); + if(dependency == null){ + return Optional.empty(); + } else { + return Optional.of(dependency); + } + } else { + return pluginObjectProvider.getIfUnique(); + } + } + + @Override + public void ifUnique(Consumer dependencyConsumer) throws BeansException { + if(isDisabled(descriptor)){ + Object dependency = getIfUnique(); + if (dependency != null) { + try { + dependencyConsumer.accept(dependency); + } catch (ScopeNotActiveException ex) { + // Ignore + } + } + } else { + pluginObjectProvider.ifUnique(dependencyConsumer); + } + } + + @Override + public Stream stream() { + if(isDisabled(descriptor)){ + return getStreamOfMain(); + } else { + return pluginObjectProvider.stream(); + } + } + + @Override + public Stream orderedStream() { + if(isDisabled(descriptor)){ + // TODO 随意排序 + return getStreamOfMain().sorted(); + } else { + return pluginObjectProvider.orderedStream(); + } + } + + @SuppressWarnings("unchecked") + private Stream getStreamOfMain(){ + SpringBeanFactory springBeanFactory = applicationContext.getSpringBeanFactory(); + Map beansOfType = springBeanFactory.getBeansOfType(descriptor.getDependencyType()); + if(beansOfType.isEmpty()){ + return Stream.empty(); + } else { + return (Stream) beansOfType.values().stream(); + } + } + } + } diff --git a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginSpringApplication.java b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginSpringApplication.java index 59a700261526741a46a6065cbf5bcf4ebe4cd30b..8ac00e976be129f17b3b10359045e7ec3bb08f89 100644 --- a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginSpringApplication.java +++ b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginSpringApplication.java @@ -34,11 +34,11 @@ import org.springframework.core.io.ResourceLoader; /** * 插件SpringApplication实现 * @author starBlues - * @version 3.0.0 + * @version 3.0.3 */ public class PluginSpringApplication extends SpringApplication { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final Logger logger = LoggerFactory.getLogger(PluginSpringApplication.class); private final ProcessorContext.RunMode runMode; @@ -68,6 +68,9 @@ public class PluginSpringApplication extends SpringApplication { protected GenericApplicationContext getApplicationContext(){ if(runMode == ProcessorContext.RunMode.ONESELF){ return (GenericApplicationContext) super.createApplicationContext(); + } + if(processorContext.getMainApplicationContext().isWebEnvironment()){ + return new PluginWebApplicationContext(beanFactory, processorContext); } else { return new PluginApplicationContext(beanFactory, processorContext); } diff --git a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginWebApplicationContext.java b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginWebApplicationContext.java new file mode 100644 index 0000000000000000000000000000000000000000..64bb67f4ea03e684e88fcb068bb2c4c6f6431067 --- /dev/null +++ b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginWebApplicationContext.java @@ -0,0 +1,96 @@ +/** + * Copyright [2019-2022] [starBlues] + * + * 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.gitee.starblues.bootstrap; + +import com.gitee.starblues.bootstrap.listener.PluginApplicationWebEventListener; +import com.gitee.starblues.bootstrap.processor.ProcessorContext; +import com.gitee.starblues.bootstrap.realize.DefaultMainEnvironmentProvider; +import com.gitee.starblues.bootstrap.realize.MainEnvironmentProvider; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.boot.web.context.WebServerApplicationContext; +import org.springframework.boot.web.server.WebServer; +import org.springframework.boot.web.server.WebServerException; + +/** + * 主程序为 web 类型时创建的插件 ApplicationContext + * + * @author starBlues + * @version 3.0.3 + */ +public class PluginWebApplicationContext extends PluginApplicationContext implements WebServerApplicationContext { + + private final WebServer webServer; + private final String serverNamespace; + + public PluginWebApplicationContext(DefaultListableBeanFactory beanFactory, ProcessorContext processorContext) { + super(beanFactory, processorContext); + MainEnvironmentProvider environmentProvider = new DefaultMainEnvironmentProvider( + processorContext.getMainApplicationContext()); + this.webServer = new PluginSimulationWebServer(environmentProvider); + this.serverNamespace = processorContext.getPluginDescriptor().getPluginId(); + addApplicationListener(new PluginApplicationWebEventListener(this)); + } + + @Override + public WebServer getWebServer() { + return webServer; + } + + @Override + public String getServerNamespace() { + return serverNamespace; + } + + + public static class PluginSimulationWebServer implements WebServer { + + private final int port; + + public PluginSimulationWebServer(MainEnvironmentProvider environmentProvider) { + Integer port = environmentProvider.getInteger("server.port"); + if(port == null){ + this.port = -1; + } else { + this.port = port; + } + } + + @Override + public void start() throws WebServerException { + throw new InvalidWebServerException(); + } + + @Override + public void stop() throws WebServerException { + throw new InvalidWebServerException(); + } + + @Override + public int getPort() { + return port; + } + + } + + public static class InvalidWebServerException extends WebServerException{ + + public InvalidWebServerException() { + super("Invalid operation", null); + } + } + +} diff --git a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/ResolveHttpMessageConvertersConfiguration.java b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/ResolveHttpMessageConvertersConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..5490027bf90da627fad94aae1ad6825628dd687e --- /dev/null +++ b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/ResolveHttpMessageConvertersConfiguration.java @@ -0,0 +1,41 @@ +/** + * Copyright [2019-2022] [starBlues] + * + * 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.gitee.starblues.bootstrap; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.context.annotation.Bean; +import org.springframework.http.converter.HttpMessageConverter; + +import java.util.stream.Collectors; + +/** + * resolve config HttpMessageConverters bean + * + * @author starBlues + * @version 3.0.3 + */ +public class ResolveHttpMessageConvertersConfiguration { + + @Bean + @ConditionalOnMissingBean + public HttpMessageConverters messageConverters(ObjectProvider> converters) { + return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList())); + } + +} diff --git a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/listener/PluginApplicationWebEventListener.java b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/listener/PluginApplicationWebEventListener.java new file mode 100644 index 0000000000000000000000000000000000000000..68654012d851656a095ff6246eb8d0f137d215b0 --- /dev/null +++ b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/listener/PluginApplicationWebEventListener.java @@ -0,0 +1,82 @@ +/** + * Copyright [2019-2022] [starBlues] + * + * 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.gitee.starblues.bootstrap.listener; + +import com.gitee.starblues.bootstrap.PluginWebApplicationContext; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.boot.web.context.WebServerApplicationContext; +import org.springframework.boot.web.context.WebServerInitializedEvent; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.core.ResolvableType; + +/** + * 插件监听器扩展 + * + * @author starBlues + * @version 3.0.3 + */ +public class PluginApplicationWebEventListener implements ApplicationListener { + + + private final PluginWebApplicationContext applicationContext; + + public PluginApplicationWebEventListener(PluginWebApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Override + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof ApplicationReadyEvent) { + callWebServerInitializedEvent(); + } + } + + @SuppressWarnings("all") + protected void callWebServerInitializedEvent(){ + String[] beanNamesForType = applicationContext.getBeanNamesForType(ResolvableType.forClassWithGenerics( + ApplicationListener.class, WebServerInitializedEvent.class + )); + PluginWebServerInitializedEvent pluginWebServerInitializedEvent = + new PluginWebServerInitializedEvent(applicationContext); + for (String beanName : beanNamesForType) { + try { + ApplicationListener applicationListener = + (ApplicationListener) applicationContext.getBean(beanName); + applicationListener.onApplicationEvent(pluginWebServerInitializedEvent); + } catch (Exception e){ + e.printStackTrace(); + } + } + } + + public static class PluginWebServerInitializedEvent extends WebServerInitializedEvent{ + + private final PluginWebApplicationContext pluginWebApplicationContext; + + protected PluginWebServerInitializedEvent(PluginWebApplicationContext pluginWebApplicationContext) { + super(pluginWebApplicationContext.getWebServer()); + this.pluginWebApplicationContext = pluginWebApplicationContext; + } + + @Override + public WebServerApplicationContext getApplicationContext() { + return pluginWebApplicationContext; + } + } + +} diff --git a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/processor/ComposeSpringPluginProcessor.java b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/processor/ComposeSpringPluginProcessor.java index 05d48476a050b42a822b4235f3971118812427c9..63e7911341c4a2154db9d88ba65842c04a5d4015 100644 --- a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/processor/ComposeSpringPluginProcessor.java +++ b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/processor/ComposeSpringPluginProcessor.java @@ -38,7 +38,7 @@ import java.util.stream.Collectors; /** * 组合的处理器 * @author starBlues - * @version 3.0.0 + * @version 3.0.3 */ public class ComposeSpringPluginProcessor implements SpringPluginProcessor { @@ -160,6 +160,10 @@ public class ComposeSpringPluginProcessor implements SpringPluginProcessor { * @param processors 处理者容器集合 */ protected void addDefaultWebEnvProcessors(ProcessorContext context, List processors){ + if(!context.getMainApplicationContext().isWebEnvironment()){ + // 主程序不是web类型, 则不进行注册 + return; + } SpringPluginBootstrap springPluginBootstrap = context.getSpringPluginBootstrap(); DisablePluginWeb disablePluginWeb = AnnotationUtils.findAnnotation(springPluginBootstrap.getClass(), DisablePluginWeb.class); diff --git a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/processor/web/PluginControllerProcessor.java b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/processor/web/PluginControllerProcessor.java index a097e6464080e15ad68257d52722886cb44d5068..a23b314936228bd4c6e4b15e54797f2e3ba21c47 100644 --- a/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/processor/web/PluginControllerProcessor.java +++ b/spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/processor/web/PluginControllerProcessor.java @@ -24,6 +24,9 @@ import com.gitee.starblues.bootstrap.utils.DestroyUtils; import com.gitee.starblues.integration.IntegrationConfiguration; import com.gitee.starblues.spring.SpringBeanFactory; import com.gitee.starblues.utils.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; @@ -43,7 +46,7 @@ import java.util.concurrent.atomic.AtomicBoolean; /** * 插件Controller处理者 * @author starBlues - * @version 3.0.0 + * @version 3.0.3 */ public class PluginControllerProcessor implements SpringPluginProcessor { @@ -53,7 +56,6 @@ public class PluginControllerProcessor implements SpringPluginProcessor { private RequestMappingHandlerMapping requestMappingHandlerMapping; - private Method getMappingForMethod; private RequestMappingHandlerAdapter handlerAdapter; private final AtomicBoolean canRegistered = new AtomicBoolean(false); @@ -65,13 +67,6 @@ public class PluginControllerProcessor implements SpringPluginProcessor { this.requestMappingHandlerMapping = mainBeanFactory.getBean(RequestMappingHandlerMapping.class); this.handlerAdapter = SpringBeanCustomUtils.getExistBean(processorContext.getMainApplicationContext(), RequestMappingHandlerAdapter.class); - this.getMappingForMethod = ReflectionUtils.findMethod(RequestMappingHandlerMapping.class, - "getMappingForMethod", Method.class, Class.class); - if(getMappingForMethod == null){ - LOG.warn("RequestMappingHandlerMapping 类中没有发现 方法, 无法注册插件接口. " + - "请检查当前环境是否为 web 环境"); - } - this.getMappingForMethod.setAccessible(true); canRegistered.set(true); } @@ -91,12 +86,6 @@ public class PluginControllerProcessor implements SpringPluginProcessor { if(!canRegistered.get()){ return; } - IntegrationConfiguration configuration = processorContext.getConfiguration(); - if(ObjectUtils.isEmpty(configuration.pluginRestPathPrefix()) - && !configuration.enablePluginIdRestPathPrefix()){ - // 如果 pluginRestPathPrefix 为空, 并且没有启用插件id作为插件前缀, 则不进行修改插件controller地址前缀 - return; - } String pluginId = processorContext.getPluginDescriptor().getPluginId(); List controllerWrappers = processorContext.getRegistryInfo(PROCESS_CONTROLLERS); if(ObjectUtils.isEmpty(controllerWrappers)){ @@ -105,21 +94,31 @@ public class PluginControllerProcessor implements SpringPluginProcessor { GenericApplicationContext applicationContext = processorContext.getApplicationContext(); Iterator iterator = controllerWrappers.iterator(); + + PluginRequestMappingHandlerMapping pluginHandlerMapping = new PluginRequestMappingHandlerMapping(); + + while (iterator.hasNext()){ ControllerWrapper controllerWrapper = iterator.next(); if(!applicationContext.containsBean(controllerWrapper.getBeanName())){ iterator.remove(); } Object controllerBean = applicationContext.getBean(controllerWrapper.getBeanName()); - Set requestMappingInfos = registry(applicationContext, controllerBean.getClass()); - if(requestMappingInfos.isEmpty()){ - iterator.remove(); - } else { - for (RequestMappingInfo requestMappingInfo : requestMappingInfos) { - LOG.info("插件[{}]注册接口: {}", pluginId, requestMappingInfo.toString()); - } - controllerWrapper.setRequestMappingInfos(requestMappingInfos); + pluginHandlerMapping.registerHandler(controllerBean); + List registerMappingInfo = pluginHandlerMapping.getAndClear(); + + Set requestMappingInfoSet = new HashSet<>(registerMappingInfo.size()); + for (RegisterMappingInfo mappingInfo : registerMappingInfo) { + RequestMappingInfo requestMappingInfo = mappingInfo.getRequestMappingInfo(); + requestMappingHandlerMapping.registerMapping( + requestMappingInfo, + mappingInfo.getHandler(), + mappingInfo.getMethod() + ); + LOG.info("插件[{}]注册接口: {}", pluginId, requestMappingInfo); + requestMappingInfoSet.add(requestMappingInfo); } + controllerWrapper.setRequestMappingInfo(requestMappingInfoSet); } } @@ -140,36 +139,14 @@ public class PluginControllerProcessor implements SpringPluginProcessor { return ProcessorContext.RunMode.PLUGIN; } - - private Set registry(GenericApplicationContext pluginApplicationContext, Class aClass) - throws ProcessorException { - Object object = pluginApplicationContext.getBean(aClass); - - Method[] methods = aClass.getDeclaredMethods(); - Set requestMappingInfos = new HashSet<>(); - for (Method method : methods) { - if (isHaveRequestMapping(method)) { - try { - RequestMappingInfo requestMappingInfo = (RequestMappingInfo) - getMappingForMethod.invoke(requestMappingHandlerMapping, method, aClass); - requestMappingHandlerMapping.registerMapping(requestMappingInfo, object, method); - requestMappingInfos.add(requestMappingInfo); - } catch (Exception e){ - throw new ProcessorException(e.getMessage()); - } - } - } - return requestMappingInfos; - } - /** * 卸载具体的Controller操作 * @param controllerBeanWrapper controllerBean包装 */ private void unregister(ControllerWrapper controllerBeanWrapper) { - Set requestMappingInfos = controllerBeanWrapper.getRequestMappingInfos(); - if(requestMappingInfos != null && !requestMappingInfos.isEmpty()){ - for (RequestMappingInfo requestMappingInfo : requestMappingInfos) { + Set requestMappingInfoSet = controllerBeanWrapper.getRequestMappingInfo(); + if(requestMappingInfoSet != null && !requestMappingInfoSet.isEmpty()){ + for (RequestMappingInfo requestMappingInfo : requestMappingInfoSet) { requestMappingHandlerMapping.unregisterMapping(requestMappingInfo); } } @@ -181,15 +158,6 @@ public class PluginControllerProcessor implements SpringPluginProcessor { } } - /** - * 方法上是否存在 @RequestMapping 注解 - * @param method method - * @return boolean - */ - private boolean isHaveRequestMapping(Method method){ - return AnnotationUtils.findAnnotation(method, RequestMapping.class) != null; - } - private static class ChangeRestPathPostProcessor implements BeanPostProcessor { private final static Logger LOG = LoggerFactory.getLogger(ChangeRestPathPostProcessor.class); @@ -201,6 +169,7 @@ public class PluginControllerProcessor implements SpringPluginProcessor { this.processorContext = processorContext; } + @SuppressWarnings("unchecked") @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { Class aClass = bean.getClass(); @@ -218,45 +187,16 @@ public class PluginControllerProcessor implements SpringPluginProcessor { String pluginId = processorContext.getPluginDescriptor().getPluginId(); IntegrationConfiguration configuration = processorContext.getConfiguration(); String pathPrefix = PluginConfigUtils.getPluginRestPrefix(configuration, pluginId); - - if(ObjectUtils.isEmpty(pathPrefix)){ - LOG.error("插件 [{}] Controller类 [{}] 未发现 path 配置, {}", - pluginId, aClass.getSimpleName(), COMMON_ERROR); - return; - } - Set definePaths = new HashSet<>(); - definePaths.addAll(Arrays.asList(requestMapping.path())); - definePaths.addAll(Arrays.asList(requestMapping.value())); try { - Map memberValues = ClassUtils.getAnnotationsUpdater(requestMapping); - if(memberValues == null){ - LOG.error("插件 [{}] Controller 类 [{}] 无法反射获取注解属性, {}", - pluginId, aClass.getSimpleName(), COMMON_ERROR); - return; + if(!ObjectUtils.isEmpty(pathPrefix)){ + resolvePathPrefix(pathPrefix, aClass, requestMapping); } - String[] newPath = new String[definePaths.size()]; - int i = 0; - for (String definePath : definePaths) { - // 解决插件启用、禁用后, 路径前缀重复的问题。 - if(definePath.contains(pathPrefix)){ - newPath[i++] = definePath; - } else { - newPath[i++] = UrlUtils.restJoiningPath(pathPrefix, definePath); - } - } - if(newPath.length == 0){ - newPath = new String[]{ pathPrefix }; - } - memberValues.put("path", newPath); - memberValues.put("value", newPath); - List controllerWrappers = processorContext.getRegistryInfo(PROCESS_CONTROLLERS); if(controllerWrappers == null){ controllerWrappers = new ArrayList<>(); processorContext.addRegistryInfo(PROCESS_CONTROLLERS, controllerWrappers); } ControllerWrapper controllerWrapper = new ControllerWrapper(); - controllerWrapper.setPathPrefix(newPath); controllerWrapper.setBeanName(beanName); controllerWrapper.setBeanClass(aClass); controllerWrappers.add(controllerWrapper); @@ -264,9 +204,41 @@ public class PluginControllerProcessor implements SpringPluginProcessor { LOG.error("插件 [{}] Controller 类[{}] 注册异常. {}", pluginId, aClass.getName(), e.getMessage(), e); } } - } + private void resolvePathPrefix(String pathPrefix, Class aClass, RequestMapping requestMapping) throws Exception{ + String pluginId = processorContext.getPluginDescriptor().getPluginId(); + + Map memberValues = ClassUtils.getAnnotationsUpdater(requestMapping); + if(memberValues == null){ + LOG.error("插件 [{}] Controller 类 [{}] 无法反射获取注解属性, {}", + pluginId, aClass.getSimpleName(), COMMON_ERROR); + return; + } + + Set definePaths = new HashSet<>(); + definePaths.addAll(Arrays.asList(requestMapping.path())); + definePaths.addAll(Arrays.asList(requestMapping.value())); + + String[] newPath = new String[definePaths.size()]; + int i = 0; + for (String definePath : definePaths) { + // 解决插件启用、禁用后, 路径前缀重复的问题。 + if(definePath.contains(pathPrefix)){ + newPath[i++] = definePath; + } else { + newPath[i++] = UrlUtils.restJoiningPath(pathPrefix, definePath); + } + } + if(newPath.length == 0){ + newPath = new String[]{ pathPrefix }; + } + memberValues.put("path", newPath); + memberValues.put("value", newPath); + } + + } + @Data static class ControllerWrapper{ /** @@ -274,11 +246,6 @@ public class PluginControllerProcessor implements SpringPluginProcessor { */ private String beanName; - /** - * controller 路径前缀 - */ - private String[] pathPrefix; - /** * controller bean 类型 */ @@ -287,39 +254,38 @@ public class PluginControllerProcessor implements SpringPluginProcessor { /** * controller 的 RequestMappingInfo 集合 */ - private Set requestMappingInfos; + private Set requestMappingInfo; + } - public Class getBeanClass() { - return beanClass; - } - public void setBeanClass(Class beanClass) { - this.beanClass = beanClass; - } + private static class PluginRequestMappingHandlerMapping extends RequestMappingHandlerMapping { - public String getBeanName() { - return beanName; - } + private final List registerMappingInfo = new ArrayList<>(); - public void setBeanName(String beanName) { - this.beanName = beanName; + public void registerHandler(Object handler){ + detectHandlerMethods(handler); } - public String[] getPathPrefix() { - return pathPrefix; + @Override + protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) { + super.registerHandlerMethod(handler, method, mapping); + registerMappingInfo.add(new RegisterMappingInfo(handler, method, mapping)); } - public void setPathPrefix(String[] pathPrefix) { - this.pathPrefix = pathPrefix; + public List getAndClear(){ + List registerMappingInfo = new ArrayList<>(this.registerMappingInfo); + this.registerMappingInfo.clear(); + return registerMappingInfo; } - public Set getRequestMappingInfos() { - return requestMappingInfos; - } + } - public void setRequestMappingInfos(Set requestMappingInfos) { - this.requestMappingInfos = requestMappingInfos; - } + @AllArgsConstructor + @Getter + private static class RegisterMappingInfo{ + private final Object handler; + private final Method method; + private final RequestMappingInfo requestMappingInfo; } } diff --git a/spring-brick-bootstrap/src/main/resources/META-INF/spring.factories b/spring-brick-bootstrap/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000000000000000000000000000000000..9d17993ae52e8e794acca3335cebd416a6291d14 --- /dev/null +++ b/spring-brick-bootstrap/src/main/resources/META-INF/spring.factories @@ -0,0 +1,7 @@ +# Auto Configuration Import Filters +org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ +com.gitee.starblues.bootstrap.PluginDisableAutoConfiguration + +# Auto Configure +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.gitee.starblues.bootstrap.ResolveHttpMessageConvertersConfiguration \ No newline at end of file diff --git a/spring-brick-common/pom.xml b/spring-brick-common/pom.xml index f5213b9e0b5e85bb6ac23dba4d71ae5ac0fbea1a..98f6c3650c6305b1494d167822473b5179668c2c 100644 --- a/spring-brick-common/pom.xml +++ b/spring-brick-common/pom.xml @@ -7,7 +7,7 @@ spring-brick-parent com.gitee.starblues - 3.0.2 + 3.0.3 spring-brick-common diff --git a/spring-brick-loader/pom.xml b/spring-brick-loader/pom.xml index 2df42130e1ba20beabfa221ab97c4c903d945313..2b61cd0496b8caaf31f9447d8a11986ca39c1b99 100644 --- a/spring-brick-loader/pom.xml +++ b/spring-brick-loader/pom.xml @@ -5,7 +5,7 @@ spring-brick-parent com.gitee.starblues - 3.0.2 + 3.0.3 4.0.0 diff --git a/spring-brick-maven-packager/pom.xml b/spring-brick-maven-packager/pom.xml index 10d4c6b7621bbea7e018886b9389165abda98a05..cb70eb68bc05abbc3b5e69b7dd200b962edfc58e 100644 --- a/spring-brick-maven-packager/pom.xml +++ b/spring-brick-maven-packager/pom.xml @@ -7,7 +7,7 @@ spring-brick-parent com.gitee.starblues - 3.0.2 + 3.0.3 spring-brick-maven-packager diff --git a/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/AbstractDependencyFilterMojo.java b/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/AbstractDependencyFilterMojo.java index 42e0e14658cb59a5baa57a439cdc78572813f02d..19505ea54d8096d971639df0c3c82253d747e5ad 100644 --- a/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/AbstractDependencyFilterMojo.java +++ b/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/AbstractDependencyFilterMojo.java @@ -95,6 +95,12 @@ public abstract class AbstractDependencyFilterMojo extends AbstractMojo { excludes.add(Exclude.get("org.springframework.boot", "spring-boot-starter-json")); excludes.add(Exclude.get("org.springframework", "spring-webmvc")); excludes.add(Exclude.get("org.springframework", "spring-web")); + + // jackson + excludes.add(Exclude.get("com.fasterxml.jackson.core", "jackson-core")); + excludes.add(Exclude.get("com.fasterxml.jackson.core", "jackson-databind")); + excludes.add(Exclude.get("com.fasterxml.jackson.core", "jackson-annotations")); + excludes.add(Exclude.get("com.fasterxml.jackson.module", "jackson-module-parameter-names")); } } diff --git a/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/BasicRepackager.java b/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/BasicRepackager.java index bb1f79012dfec24951f3ea77c9c2bd8c19fa2ce6..44bc3a54c40647db02c7a3aeb5aee8e4a05e8135 100644 --- a/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/BasicRepackager.java +++ b/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/BasicRepackager.java @@ -32,6 +32,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.*; import java.util.jar.Attributes; import java.util.jar.Manifest; @@ -237,7 +238,7 @@ public class BasicRepackager implements Repackager{ protected String writePluginMetaInfo(Properties properties) throws Exception { File pluginMetaFile = createPluginMetaFile(); try (OutputStreamWriter writer = new OutputStreamWriter( - new FileOutputStream(pluginMetaFile), StandardCharsets.UTF_8)){ + Files.newOutputStream(pluginMetaFile.toPath()), StandardCharsets.UTF_8)){ properties.store(writer, Constant.PLUGIN_METE_COMMENTS); return pluginMetaFile.getPath(); } diff --git a/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/dev/DevConfig.java b/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/dev/DevConfig.java index 20ed1b65d3642a0bf0c666f72f6bf7454e1f5da1..9070a6eb3116748360fe06f741cac5a85127977e 100644 --- a/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/dev/DevConfig.java +++ b/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/dev/DevConfig.java @@ -34,4 +34,9 @@ public class DevConfig { */ private List moduleDependencies; + /** + * 本地jar依赖文件定义 + */ + private List localJars; + } diff --git a/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/dev/DevRepackager.java b/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/dev/DevRepackager.java index 9e436c24dad17ca38a6a4e0fefd3669ee971a0fb..6540b3f7daffb010f8dff037c70c6460943beed3 100644 --- a/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/dev/DevRepackager.java +++ b/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/dev/DevRepackager.java @@ -44,11 +44,19 @@ public class DevRepackager extends BasicRepackager { @Override protected Set getDependenciesIndexSet() throws Exception { - moduleDependencies = getModuleDependencies(repackageMojo.getDevConfig()); + DevConfig devConfig = repackageMojo.getDevConfig(); + if(devConfig == null){ + return super.getDependenciesIndexSet(); + } + moduleDependencies = getModuleDependencies(devConfig); Set dependenciesIndexSet = super.getDependenciesIndexSet(); for (Dependency dependency : moduleDependencies.values()) { dependenciesIndexSet.add(dependency.getClassesPath()); } + List localJars = devConfig.getLocalJars(); + if(!ObjectUtils.isEmpty(localJars)){ + dependenciesIndexSet.addAll(localJars); + } return dependenciesIndexSet; } diff --git a/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/main/JarOuterPackager.java b/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/main/JarOuterPackager.java index 3e24c97d77bbffed6a2202e95c3f6bed2ae07c1a..4d1e3ee4d73c0a67e48df291268e523d68a17cf8 100644 --- a/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/main/JarOuterPackager.java +++ b/spring-brick-maven-packager/src/main/java/com/gitee/starblues/plugin/pack/main/JarOuterPackager.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.Set; import java.util.jar.Attributes; import java.util.jar.Manifest; +import java.util.stream.Stream; import static com.gitee.starblues.common.ManifestKey.*; @@ -86,11 +87,7 @@ public class JarOuterPackager extends JarNestPackager { attributes.putValue(START_CLASS, mainConfig.getMainClass()); attributes.putValue(MAIN_CLASS, MAIN_CLASS_VALUE); attributes.putValue(MAIN_PACKAGE_TYPE, PackageType.MAIN_PACKAGE_TYPE_JAR_OUTER); - String libDir = PackageStructure.LIB_NAME; - if(!ObjectUtils.isEmpty(mainConfig.getLibDir())){ - libDir = mainConfig.getLibDir(); - } - attributes.putValue(MAIN_LIB_DIR, libDir); + attributes.putValue(MAIN_LIB_DIR, getLibPath()); attributes.putValue(MAIN_LIB_INDEXES, getLibIndexes()); return manifest; } @@ -119,12 +116,25 @@ public class JarOuterPackager extends JarNestPackager { packageJar.copyZipToPackage(artifact.getFile()); } else { File artifactFile = artifact.getFile(); - String targetFilePath = FilesUtils.joiningFilePath( - mainConfig.getOutputDirectory(), PackageStructure.LIB_NAME, artifactFile.getName()); + String libPath = getLibPath(); + if(FilesUtils.isRelativePath(libPath)){ + libPath = FilesUtils.resolveRelativePath(mainConfig.getOutputDirectory(), getLibPath()); + } else { + libPath = FilesUtils.joiningFilePath(mainConfig.getOutputDirectory(), libPath); + } + String targetFilePath = FilesUtils.joiningFilePath(libPath, artifactFile.getName()); FileUtils.copyFile(artifactFile, new File(targetFilePath)); dependencyIndexNames.add(artifactFile.getName()); } } } + private String getLibPath(){ + String libDir = PackageStructure.LIB_NAME; + if(!ObjectUtils.isEmpty(mainConfig.getLibDir())){ + libDir = mainConfig.getLibDir(); + } + return libDir; + } + } diff --git a/spring-brick-maven-packager/src/main/resources/META-INF/maven/com.gitee.starblues.springboot-plugin-maven-packager/plugin-help.xml b/spring-brick-maven-packager/src/main/resources/META-INF/maven/com.gitee.starblues.springboot-plugin-maven-packager/plugin-help.xml index ebe06e796278073f4d6a73fc560a66a0b5b8e87d..ddfb1ce44fb119f21f5ada61509aea1ebc8ee3ae 100644 --- a/spring-brick-maven-packager/src/main/resources/META-INF/maven/com.gitee.starblues.springboot-plugin-maven-packager/plugin-help.xml +++ b/spring-brick-maven-packager/src/main/resources/META-INF/maven/com.gitee.starblues.springboot-plugin-maven-packager/plugin-help.xml @@ -1,21 +1,17 @@ - - Spring Boot Plugin Maven Packager com.gitee.starblues spring-brick-maven-packager - 3.0.2 + 3.0.3 spring-brick-packager false true repackage - Repackage existing JAR and WAR archives so that they can be executed from the command - line using {@literal java -jar}. With <code>layout=NONE</code> can also be used simply - to package a JAR with nested dependencies (and no main class, so not executable). + 重新打包 compile+runtime false true @@ -28,54 +24,49 @@ java per-lookup once-per-session - 1.0.0 + 3.0.0 compile+runtime true project org.apache.maven.project.MavenProject - 1.0.0 + 3.0.0 true false - The Maven project. + 当前项目 outputDirectory java.io.File - 1.0.0 + 3.0.0 true true - Directory containing the generated archive. + 打包输出目录地址 includes java.util.List - 1.2.0 + 3.0.0 false true - Collection of artifact definitions to include. The {@link Include} element defines - mandatory {@code groupId} and {@code artifactId} properties and an optional - mandatory {@code groupId} and {@code artifactId} properties and an optional - {@code classifier} property. + 包含依赖定义 excludes java.util.List - 1.1.0 + 3.0.0 false true - Collection of artifact definitions to exclude. The {@link Exclude} element defines - mandatory {@code groupId} and {@code artifactId} properties and an optional - {@code classifier} property. + 排除依赖定义 skip boolean - 1.2.0 + 3.0.0 false true - Skip the execution. + 跳过执行 mode diff --git a/spring-brick-maven-packager/src/main/resources/META-INF/maven/plugin.xml b/spring-brick-maven-packager/src/main/resources/META-INF/maven/plugin.xml index ebe06e796278073f4d6a73fc560a66a0b5b8e87d..ddfb1ce44fb119f21f5ada61509aea1ebc8ee3ae 100644 --- a/spring-brick-maven-packager/src/main/resources/META-INF/maven/plugin.xml +++ b/spring-brick-maven-packager/src/main/resources/META-INF/maven/plugin.xml @@ -1,21 +1,17 @@ - - Spring Boot Plugin Maven Packager com.gitee.starblues spring-brick-maven-packager - 3.0.2 + 3.0.3 spring-brick-packager false true repackage - Repackage existing JAR and WAR archives so that they can be executed from the command - line using {@literal java -jar}. With <code>layout=NONE</code> can also be used simply - to package a JAR with nested dependencies (and no main class, so not executable). + 重新打包 compile+runtime false true @@ -28,54 +24,49 @@ java per-lookup once-per-session - 1.0.0 + 3.0.0 compile+runtime true project org.apache.maven.project.MavenProject - 1.0.0 + 3.0.0 true false - The Maven project. + 当前项目 outputDirectory java.io.File - 1.0.0 + 3.0.0 true true - Directory containing the generated archive. + 打包输出目录地址 includes java.util.List - 1.2.0 + 3.0.0 false true - Collection of artifact definitions to include. The {@link Include} element defines - mandatory {@code groupId} and {@code artifactId} properties and an optional - mandatory {@code groupId} and {@code artifactId} properties and an optional - {@code classifier} property. + 包含依赖定义 excludes java.util.List - 1.1.0 + 3.0.0 false true - Collection of artifact definitions to exclude. The {@link Exclude} element defines - mandatory {@code groupId} and {@code artifactId} properties and an optional - {@code classifier} property. + 排除依赖定义 skip boolean - 1.2.0 + 3.0.0 false true - Skip the execution. + 跳过执行 mode diff --git a/spring-brick/pom.xml b/spring-brick/pom.xml index e0c702dbc4442e60d3613bd95a2087a2253f29a9..c92fc860fbfdbaf16ba242fc7d719a342c6b1dfb 100644 --- a/spring-brick/pom.xml +++ b/spring-brick/pom.xml @@ -7,7 +7,7 @@ spring-brick-parent com.gitee.starblues - 3.0.2 + 3.0.3 spring-brick diff --git a/spring-brick/src/main/java/com/gitee/starblues/core/DefaultPluginManager.java b/spring-brick/src/main/java/com/gitee/starblues/core/DefaultPluginManager.java index f5824ac4c37b8126917951ecccb0ddf6f9543f0c..ac678a21772abae3f55ade7d69391468b536b782 100644 --- a/spring-brick/src/main/java/com/gitee/starblues/core/DefaultPluginManager.java +++ b/spring-brick/src/main/java/com/gitee/starblues/core/DefaultPluginManager.java @@ -49,11 +49,11 @@ import java.util.stream.Collectors; /** * 抽象的插件管理者 * @author starBlues - * @version 3.0.2 + * @version 3.0.3 */ public class DefaultPluginManager implements PluginManager{ - private final Logger log = LoggerFactory.getLogger(this.getClass()); + private final Logger log = LoggerFactory.getLogger(DefaultPluginManager.class); private final RealizeProvider provider; private final IntegrationConfiguration configuration; diff --git a/spring-brick/src/main/java/com/gitee/starblues/core/PluginLauncherManager.java b/spring-brick/src/main/java/com/gitee/starblues/core/PluginLauncherManager.java index d9b9b907fd185d58c7784b2a7bc0e3db50ead2e8..de3cd3904d93223059bf0073cfe581bc6425be14 100644 --- a/spring-brick/src/main/java/com/gitee/starblues/core/PluginLauncherManager.java +++ b/spring-brick/src/main/java/com/gitee/starblues/core/PluginLauncherManager.java @@ -60,7 +60,8 @@ public class PluginLauncherManager extends DefaultPluginManager{ GenericApplicationContext applicationContext, IntegrationConfiguration configuration) { super(realizeProvider, configuration); - this.mainApplicationContext = new MainApplicationContextProxy(applicationContext, applicationContext); + this.mainApplicationContext = + new MainApplicationContextProxy(applicationContext, configuration, applicationContext); this.mainGenericApplicationContext = applicationContext; this.configuration = configuration; this.invokeSupperCache = new DefaultInvokeSupperCache(); diff --git a/spring-brick/src/main/java/com/gitee/starblues/core/launcher/plugin/PluginMainResourcePatternDefiner.java b/spring-brick/src/main/java/com/gitee/starblues/core/launcher/plugin/PluginMainResourcePatternDefiner.java index 8772b542c3e8cd3d90184f6b84d07c1d4508e9f3..e74dfce25d5eae4acb4f40cbf6ed6921cec27631 100644 --- a/spring-brick/src/main/java/com/gitee/starblues/core/launcher/plugin/PluginMainResourcePatternDefiner.java +++ b/spring-brick/src/main/java/com/gitee/starblues/core/launcher/plugin/PluginMainResourcePatternDefiner.java @@ -61,6 +61,8 @@ public class PluginMainResourcePatternDefiner extends JavaMainResourcePatternDef addApiDoc(includeResourcePatterns); addDbDriver(includeResourcePatterns); + addIdea(includeResourcePatterns); + // 配置插件自定义从主程序加载的资源匹配 Set includeMainResourcePatterns = descriptor.getIncludeMainResourcePatterns(); if(ObjectUtils.isEmpty(includeMainResourcePatterns)){ @@ -76,8 +78,6 @@ public class PluginMainResourcePatternDefiner extends JavaMainResourcePatternDef return includeResourcePatterns; } - - @Override public Set getExcludePatterns() { Set excludeResourcePatterns = new HashSet<>(); @@ -99,8 +99,13 @@ public class PluginMainResourcePatternDefiner extends JavaMainResourcePatternDef patterns.add("org/springframework/remoting/**"); patterns.add("org/springframework/ui/**"); - patterns.add("com/fasterxml/jackson/**"); + patterns.add("org/springframework/boot/autoconfigure/http/**"); + patterns.add("org/springframework/boot/autoconfigure/web/**"); + patterns.add("org/springframework/boot/autoconfigure/websocket/**"); + patterns.add("org/springframework/boot/autoconfigure/webservices/**"); + patterns.add("org/springframework/boot/autoconfigure/jackson/**"); + patterns.add("com/fasterxml/jackson/**"); } protected void addApiDoc(Set patterns){ @@ -136,6 +141,11 @@ public class PluginMainResourcePatternDefiner extends JavaMainResourcePatternDef patterns.add("jdbc/h2/**"); } + private void addIdea(Set includeResourcePatterns) { + // idea debug agent + includeResourcePatterns.add("com/intellij/rt/debugger/agent/**"); + } + /** * 获取基本的 MainResourcePatternDefiner * @param pluginInteractive PluginInteractive diff --git a/spring-brick/src/main/java/com/gitee/starblues/integration/AutoIntegrationConfiguration.java b/spring-brick/src/main/java/com/gitee/starblues/integration/AutoIntegrationConfiguration.java index 5134ad9517a376a4639b877a1a99a3c9d0819ddc..39e3af8d19f5c50d0ac994b1d7969c0aba1e8a84 100644 --- a/spring-brick/src/main/java/com/gitee/starblues/integration/AutoIntegrationConfiguration.java +++ b/spring-brick/src/main/java/com/gitee/starblues/integration/AutoIntegrationConfiguration.java @@ -32,7 +32,7 @@ import java.util.Set; /** * 自动集成的配置 * @author starBlues - * @version 3.0.1 + * @version 3.0.3 */ @EqualsAndHashCode(callSuper = true) @Component @@ -92,7 +92,7 @@ public class AutoIntegrationConfiguration extends DefaultIntegrationConfiguratio * pluginRestPathPrefix: 为pluginRestPathPrefix的配置值 * pluginId: 为插件id */ - @Value("${pluginRestPathPrefix:true}") + @Value("${enablePluginIdRestPathPrefix:true}") private Boolean enablePluginIdRestPathPrefix; /** diff --git a/spring-brick/src/main/java/com/gitee/starblues/integration/ExtendPointWebConfiguration.java b/spring-brick/src/main/java/com/gitee/starblues/integration/ExtendPointWebConfiguration.java index e1e197d57fcb14aba5bb0cbabf9f0607d70ab25c..9c198e3793606b04624cba07dff84ccddc9ef354 100644 --- a/spring-brick/src/main/java/com/gitee/starblues/integration/ExtendPointWebConfiguration.java +++ b/spring-brick/src/main/java/com/gitee/starblues/integration/ExtendPointWebConfiguration.java @@ -17,6 +17,7 @@ package com.gitee.starblues.integration; import com.gitee.starblues.integration.listener.SwaggerListener; +import com.gitee.starblues.spring.ResolvePluginThreadClassLoader; import com.gitee.starblues.spring.web.PluginStaticResourceConfig; import com.gitee.starblues.spring.web.PluginStaticResourceWebMvcConfigurer; import com.gitee.starblues.spring.web.thymeleaf.PluginThymeleafInvolved; @@ -27,6 +28,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.context.support.GenericApplicationContext; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.resource.ResourceResolver; import org.thymeleaf.spring5.SpringTemplateEngine; import org.thymeleaf.templatemode.TemplateMode; @@ -90,4 +92,9 @@ public class ExtendPointWebConfiguration { } + @Bean + public WebMvcConfigurer webMvcConfigurer(){ + return new ResolvePluginThreadClassLoader(); + } + } diff --git a/spring-brick/src/main/java/com/gitee/starblues/spring/MainApplicationContext.java b/spring-brick/src/main/java/com/gitee/starblues/spring/MainApplicationContext.java index d7017a0c1d8cca17583fd3dd862e6c18fae45dd3..24b2df36e9fe8635f31b1133890dd073f6ba36f8 100644 --- a/spring-brick/src/main/java/com/gitee/starblues/spring/MainApplicationContext.java +++ b/spring-brick/src/main/java/com/gitee/starblues/spring/MainApplicationContext.java @@ -32,4 +32,19 @@ public interface MainApplicationContext extends ApplicationContext { */ Map> getConfigurableEnvironment(); + /** + * If Resolve the specified main dependency against the beans defined in this factory. + * + * @param packageName 当前依赖包名称 + * @return boolean + */ + boolean isResolveDependency(String packageName); + + /** + * 是否为web环境 + * @return boolean + */ + boolean isWebEnvironment(); + + } diff --git a/spring-brick/src/main/java/com/gitee/starblues/spring/MainApplicationContextProxy.java b/spring-brick/src/main/java/com/gitee/starblues/spring/MainApplicationContextProxy.java index b77d4a3b610a8cc4a2f2c9aa528699b0aa2f2db3..27e5f25f7944000a2e2b11a83dda3aa126bf4255 100644 --- a/spring-brick/src/main/java/com/gitee/starblues/spring/MainApplicationContextProxy.java +++ b/spring-brick/src/main/java/com/gitee/starblues/spring/MainApplicationContextProxy.java @@ -16,6 +16,9 @@ package com.gitee.starblues.spring; +import com.gitee.starblues.integration.IntegrationConfiguration; +import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext; +import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.EnumerablePropertySource; @@ -34,15 +37,24 @@ import java.util.Map; public class MainApplicationContextProxy extends ApplicationContextProxy implements MainApplicationContext{ private final GenericApplicationContext applicationContext; + private final IntegrationConfiguration configuration; + private final boolean isWebEnvironment; - public MainApplicationContextProxy(GenericApplicationContext applicationContext) { + public MainApplicationContextProxy(GenericApplicationContext applicationContext, + IntegrationConfiguration configuration) { super(applicationContext.getBeanFactory()); this.applicationContext = applicationContext; + this.configuration = configuration; + this.isWebEnvironment = getIsWebEnvironment(applicationContext); } - public MainApplicationContextProxy(GenericApplicationContext applicationContext, AutoCloseable autoCloseable) { + public MainApplicationContextProxy(GenericApplicationContext applicationContext, + IntegrationConfiguration configuration, + AutoCloseable autoCloseable) { super(applicationContext.getBeanFactory(), autoCloseable); this.applicationContext = applicationContext; + this.configuration = configuration; + this.isWebEnvironment = getIsWebEnvironment(applicationContext); } @Override @@ -67,4 +79,19 @@ public class MainApplicationContextProxy extends ApplicationContextProxy impleme return environmentMap; } + @Override + public boolean isResolveDependency(String packageName) { + return packageName.startsWith(configuration.mainPackage()); + } + + @Override + public boolean isWebEnvironment() { + return isWebEnvironment; + } + + private boolean getIsWebEnvironment(GenericApplicationContext applicationContext){ + return applicationContext instanceof AnnotationConfigServletWebServerApplicationContext + || applicationContext instanceof AnnotationConfigReactiveWebServerApplicationContext; + } + } diff --git a/spring-brick/src/main/java/com/gitee/starblues/spring/ResolvePluginThreadClassLoader.java b/spring-brick/src/main/java/com/gitee/starblues/spring/ResolvePluginThreadClassLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..f2191e979eb299e02512579b140d724fb94bbe41 --- /dev/null +++ b/spring-brick/src/main/java/com/gitee/starblues/spring/ResolvePluginThreadClassLoader.java @@ -0,0 +1,71 @@ +/** + * Copyright [2019-2022] [starBlues] + * + * 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.gitee.starblues.spring; + +import com.gitee.starblues.loader.classloader.GenericClassLoader; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 解决插件线程中的ClassLoader + * + * @author starBlues + * @version 3.0.3 + */ +public class ResolvePluginThreadClassLoader implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new ResolveHandlerInterceptor()).addPathPatterns("/**"); + } + + private static class ResolveHandlerInterceptor implements HandlerInterceptor { + + private final ThreadLocal oldClassLoader = new ThreadLocal<>(); + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if(handler instanceof HandlerMethod){ + HandlerMethod handlerMethod = (HandlerMethod) handler; + ClassLoader classLoader = handlerMethod.getBeanType().getClassLoader(); + if(classLoader instanceof GenericClassLoader){ + oldClassLoader.set(Thread.currentThread().getContextClassLoader()); + Thread.currentThread().setContextClassLoader(classLoader); + } + } + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + try { + ClassLoader classLoader = oldClassLoader.get(); + if(classLoader != null){ + Thread.currentThread().setContextClassLoader(classLoader); + } + } finally { + oldClassLoader.remove(); + } + } + } + +} diff --git a/spring-brick/src/main/java/com/gitee/starblues/spring/web/PluginStaticResourceResolver.java b/spring-brick/src/main/java/com/gitee/starblues/spring/web/PluginStaticResourceResolver.java index b923cde29c9bc2ba05aeda8d1210235ebb671045..4e6c89aae416b53e2f31b50075caa6fdebe14841 100644 --- a/spring-brick/src/main/java/com/gitee/starblues/spring/web/PluginStaticResourceResolver.java +++ b/spring-brick/src/main/java/com/gitee/starblues/spring/web/PluginStaticResourceResolver.java @@ -106,8 +106,18 @@ public class PluginStaticResourceResolver extends AbstractResourceResolver { // 存在后缀 return null; } - partialPath = UrlUtils.joiningUrlPath(partialPath, indexPageName); - return findResource(pluginResource, partialPath); + + // 查找第一级节点,找不到则读取根index.html + if(partialPath.contains(UrlUtils.SPLIT)){ + partialPath = partialPath.substring(0, partialPath.indexOf(UrlUtils.SPLIT)); + } + // 第一级节点 + resource = findResource(pluginResource, UrlUtils.joiningUrlPath(partialPath, indexPageName)); + if(resource != null){ + return resource; + } + // 根节点 + return findResource(pluginResource, UrlUtils.joiningUrlPath(UrlUtils.SPLIT, indexPageName)); } } @@ -144,7 +154,11 @@ public class PluginStaticResourceResolver extends AbstractResourceResolver { PluginResource resource = new PluginResource(classPath + partialPath, pluginResource.getPluginDescriptor()); resource.setClassLoader(pluginClassLoader); if(resource.exists()){ - return resource; + // 确保资源为文件 + File file = resource.getFile(); + if(file != null && file.isFile()){ + return resource; + } } } catch (Exception e){ logger.debug("Get static resources of classpath '{}' error.", classPath, e); diff --git a/update.md b/update.md index f2ee7f572cab55d8b8c99fdee742d857ab76c4b7..06ba90122c031f2f37fa6b9c4995f6d37ca7879b 100644 --- a/update.md +++ b/update.md @@ -1,7 +1,12 @@ -1. 新增 `xx-outer、dir` 打包类型的插件可自定义依赖目录 -2. 新增`includeSystemScope`、`type=main` 打包属性 -3. 修复插件拦截器无法拦截不存在的url -4. 修复主程序在 `jar-outer` 打包模式后无法启动问题 -5. 修复插件首次安装时异常 -6. fix https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I53K4G -7. fix https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I53T9W \ No newline at end of file +1. 【新增[#I58CDB]([#I58CDB](https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I58CDB))】 +插件可触发`WebServerInitializedEvent`类型的事件 +2. 【新增】插件`dev`模式打包, 新增`localJars`配置(配置本地`jar`依赖文件) +3. 【支持】支持插件`Controller`可不配置地址前缀(配置后会影响插件拦截器和静态资源访问) +4. 【修复】`enablePluginIdRestPathPrefix`不生效问题 +5. 【修复】插件无法注入`ObjectProvider`、`ObjectFactory`类型为主程序的`Bean` +6. 【修复[#I58CDB](https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I58CDB)】 +插件`Controller`使用`Aop`后, 获取不到参数 +7. 【修复[#I58GCI](https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I58GCI)】 +主程序打包参数`libDir`不生效问题 +8. 【优化】优化静态资源文件加载问题 +9. 【优化】优化插件在某些版本的`idea`中缺失`debug`包, 导致无法`debug` \ No newline at end of file