From 5d8fa4acd8a4d9e995b8fd2a4048710de85e5e12 Mon Sep 17 00:00:00 2001 From: StarBlues Date: Sat, 21 May 2022 17:30:02 +0800 Subject: [PATCH 1/2] update to 3.0.0 --- pom.xml | 2 +- spring-brick-bootstrap/pom.xml | 2 +- .../EmptyMainApplicationContext.java | 12 +- .../bootstrap/PluginApplicationContext.java | 5 +- .../PluginDisableAutoConfiguration.java | 72 +++++++ .../bootstrap/PluginListableBeanFactory.java | 188 +++++++++++++++-- .../bootstrap/PluginSpringApplication.java | 7 +- .../PluginWebApplicationContext.java | 96 +++++++++ ...lveHttpMessageConvertersConfiguration.java | 41 ++++ .../PluginApplicationWebEventListener.java | 82 ++++++++ .../ComposeSpringPluginProcessor.java | 6 +- .../web/PluginControllerProcessor.java | 198 ++++++++---------- .../main/resources/META-INF/spring.factories | 7 + spring-brick-common/pom.xml | 2 +- spring-brick-loader/pom.xml | 2 +- spring-brick-maven-packager/pom.xml | 2 +- .../pack/AbstractDependencyFilterMojo.java | 6 + .../plugin/pack/BasicRepackager.java | 3 +- .../starblues/plugin/pack/dev/DevConfig.java | 5 + .../plugin/pack/dev/DevRepackager.java | 10 +- .../plugin/pack/main/JarOuterPackager.java | 24 ++- .../plugin-help.xml | 35 ++-- .../main/resources/META-INF/maven/plugin.xml | 35 ++-- spring-brick/pom.xml | 2 +- .../starblues/core/DefaultPluginManager.java | 4 +- .../starblues/core/PluginLauncherManager.java | 3 +- .../PluginMainResourcePatternDefiner.java | 7 +- .../AutoIntegrationConfiguration.java | 4 +- .../ExtendPointWebConfiguration.java | 7 + .../spring/MainApplicationContext.java | 15 ++ .../spring/MainApplicationContextProxy.java | 31 ++- .../ResolvePluginThreadClassLoader.java | 71 +++++++ update.md | 16 +- 33 files changed, 791 insertions(+), 211 deletions(-) create mode 100644 spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginDisableAutoConfiguration.java create mode 100644 spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/PluginWebApplicationContext.java create mode 100644 spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/ResolveHttpMessageConvertersConfiguration.java create mode 100644 spring-brick-bootstrap/src/main/java/com/gitee/starblues/bootstrap/listener/PluginApplicationWebEventListener.java create mode 100644 spring-brick-bootstrap/src/main/resources/META-INF/spring.factories create mode 100644 spring-brick/src/main/java/com/gitee/starblues/spring/ResolvePluginThreadClassLoader.java diff --git a/pom.xml b/pom.xml index c715765..0970aa1 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 730adc0..cf32d07 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 0321276..e4ddb24 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 2ed37d0..b6c9cb1 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 0000000..7c69c39 --- /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 fda8129..5d1a873 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 59a7002..8ac00e9 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 0000000..64bb67f --- /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 0000000..5490027 --- /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 0000000..6865401 --- /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 05d4847..63e7911 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 a097e64..a23b314 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 0000000..9d17993 --- /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 f5213b9..98f6c36 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 2df4213..2b61cd0 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 10d4c6b..cb70eb6 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 42e0e14..19505ea 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 bb1f790..44bc3a5 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 20ed1b6..9070a6e 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 9e436c2..6540b3f 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 3e24c97..4d1e3ee 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 ebe06e7..ddfb1ce 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 ebe06e7..ddfb1ce 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 e0c702d..c92fc86 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 f5824ac..ac678a2 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 d9b9b90..de3cd39 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 8772b54..8da8b8c 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 @@ -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){ 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 5134ad9..39e3af8 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 e1e197d..9c198e3 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 d7017a0..24b2df3 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 b77d4a3..27e5f25 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 0000000..f2191e9 --- /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/update.md b/update.md index f2ee7f5..7e7d884 100644 --- a/update.md +++ b/update.md @@ -1,7 +1,9 @@ -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. 【支持】支持插件`Controller`可不配置地址前缀 +3. 【修复】`enablePluginIdRestPathPrefix`不生效问题 +4. 【修复】插件无法注入`ObjectProvider`、`ObjectFactory`类型为主程序的`Bean` +5. 【修复[#I58CDB](https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I58CDB)】 +插件`Controller`使用`Aop`后, 获取不到参数 +6. 【修复[#I58GCI](https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I58GCI)】 +主程序打包参数`libDir`不生效问题 \ No newline at end of file -- Gitee From 8bea878752988d156e7acacf466b4c76db63b4a1 Mon Sep 17 00:00:00 2001 From: StarBlues Date: Sun, 22 May 2022 18:01:15 +0800 Subject: [PATCH 2/2] fix debug --- .../PluginMainResourcePatternDefiner.java | 9 +++++++-- .../web/PluginStaticResourceResolver.java | 20 ++++++++++++++++--- update.md | 15 ++++++++------ 3 files changed, 33 insertions(+), 11 deletions(-) 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 8da8b8c..e74dfce 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<>(); @@ -141,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/spring/web/PluginStaticResourceResolver.java b/spring-brick/src/main/java/com/gitee/starblues/spring/web/PluginStaticResourceResolver.java index b923cde..4e6c89a 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 7e7d884..06ba901 100644 --- a/update.md +++ b/update.md @@ -1,9 +1,12 @@ 1. 【新增[#I58CDB]([#I58CDB](https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I58CDB))】 插件可触发`WebServerInitializedEvent`类型的事件 -2. 【支持】支持插件`Controller`可不配置地址前缀 -3. 【修复】`enablePluginIdRestPathPrefix`不生效问题 -4. 【修复】插件无法注入`ObjectProvider`、`ObjectFactory`类型为主程序的`Bean` -5. 【修复[#I58CDB](https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I58CDB)】 +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`后, 获取不到参数 -6. 【修复[#I58GCI](https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I58GCI)】 -主程序打包参数`libDir`不生效问题 \ No newline at end of file +7. 【修复[#I58GCI](https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I58GCI)】 +主程序打包参数`libDir`不生效问题 +8. 【优化】优化静态资源文件加载问题 +9. 【优化】优化插件在某些版本的`idea`中缺失`debug`包, 导致无法`debug` \ No newline at end of file -- Gitee