|
@@ -1,11 +1,7 @@
|
|
|
package com.chelvc.framework.base.context;
|
|
|
|
|
|
-import java.io.IOException;
|
|
|
-import java.io.InputStream;
|
|
|
import java.lang.ref.WeakReference;
|
|
|
-import java.nio.charset.StandardCharsets;
|
|
|
import java.time.Duration;
|
|
|
-import java.util.Arrays;
|
|
|
import java.util.Collection;
|
|
|
import java.util.Collections;
|
|
|
import java.util.Comparator;
|
|
@@ -18,10 +14,6 @@ import java.util.Properties;
|
|
|
import java.util.Set;
|
|
|
import java.util.function.Consumer;
|
|
|
import java.util.function.Function;
|
|
|
-import java.util.function.Predicate;
|
|
|
-import java.util.function.Supplier;
|
|
|
-import java.util.stream.Collectors;
|
|
|
-import java.util.stream.Stream;
|
|
|
|
|
|
import com.chelvc.framework.base.config.MultipleServerConfigurer;
|
|
|
import com.chelvc.framework.base.util.SpringUtils;
|
|
@@ -35,41 +27,22 @@ import com.chelvc.framework.common.util.JacksonUtils;
|
|
|
import com.chelvc.framework.common.util.ObjectUtils;
|
|
|
import com.chelvc.framework.common.util.StringUtils;
|
|
|
import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
-import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
import com.google.common.collect.Lists;
|
|
|
import com.google.common.collect.Maps;
|
|
|
-import com.google.common.collect.Sets;
|
|
|
import lombok.NonNull;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.aop.framework.AopProxyUtils;
|
|
|
import org.springframework.beans.BeansException;
|
|
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
|
|
-import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
|
|
-import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
|
import org.springframework.context.ApplicationContext;
|
|
|
import org.springframework.context.ApplicationContextAware;
|
|
|
import org.springframework.context.EnvironmentAware;
|
|
|
-import org.springframework.context.annotation.ComponentScan;
|
|
|
import org.springframework.context.i18n.LocaleContextHolder;
|
|
|
-import org.springframework.context.support.GenericApplicationContext;
|
|
|
import org.springframework.core.Ordered;
|
|
|
-import org.springframework.core.annotation.AnnotationUtils;
|
|
|
import org.springframework.core.annotation.Order;
|
|
|
import org.springframework.core.env.Environment;
|
|
|
import org.springframework.core.io.Resource;
|
|
|
-import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
|
|
-import org.springframework.core.io.support.ResourcePatternResolver;
|
|
|
-import org.springframework.http.MediaType;
|
|
|
-import org.springframework.http.converter.HttpMessageConverter;
|
|
|
-import org.springframework.http.converter.StringHttpMessageConverter;
|
|
|
-import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
|
|
|
-import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
|
|
|
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
|
|
-import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
|
|
|
-import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
-import org.springframework.stereotype.Controller;
|
|
|
-import org.springframework.web.bind.annotation.RestController;
|
|
|
|
|
|
/**
|
|
|
* 应用上下文工具类
|
|
@@ -81,11 +54,6 @@ import org.springframework.web.bind.annotation.RestController;
|
|
|
@Component
|
|
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
|
|
public class ApplicationContextHolder implements EnvironmentAware, ApplicationContextAware, PropertyRefreshListener {
|
|
|
- /**
|
|
|
- * 服务端口属性
|
|
|
- */
|
|
|
- public static final String SERVER_PORT_PROPERTY = "server.port";
|
|
|
-
|
|
|
/**
|
|
|
* 应用名称属性
|
|
|
*/
|
|
@@ -96,30 +64,6 @@ public class ApplicationContextHolder implements EnvironmentAware, ApplicationCo
|
|
|
*/
|
|
|
public static final String APPLICATION_PROFILE_PROPERTY = "spring.profiles.active";
|
|
|
|
|
|
- /**
|
|
|
- * bootstrap.yml文件搜索路径
|
|
|
- */
|
|
|
- public static final String BOOTSTRAP_YML_PATH =
|
|
|
- ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "/bootstrap.yml";
|
|
|
-
|
|
|
- /**
|
|
|
- * bootstrap.properties文件搜索路径
|
|
|
- */
|
|
|
- public static final String BOOTSTRAP_PROPERTIES_PATH =
|
|
|
- ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "/bootstrap.properties";
|
|
|
-
|
|
|
- /**
|
|
|
- * application.yml文件搜索路径
|
|
|
- */
|
|
|
- public static final String APPLICATION_YML_PATH =
|
|
|
- ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "/application.yml";
|
|
|
-
|
|
|
- /**
|
|
|
- * application.properties文件搜索路径
|
|
|
- */
|
|
|
- public static final String APPLICATION_PROPERTIES_PATH =
|
|
|
- ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "/application.properties";
|
|
|
-
|
|
|
/**
|
|
|
* 属性名/对象实例映射表
|
|
|
*/
|
|
@@ -152,42 +96,6 @@ public class ApplicationContextHolder implements EnvironmentAware, ApplicationCo
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 获取服务端口
|
|
|
- *
|
|
|
- * @return 服务端口
|
|
|
- */
|
|
|
- public static Integer getPort() {
|
|
|
- Environment environment = getEnvironment(false);
|
|
|
- return environment == null ? null : getPort(environment);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 根据 *.yml、*.properties文件资源获取服务端口
|
|
|
- *
|
|
|
- * @param resource *.yml、*.properties文件资源对象实例
|
|
|
- * @return 服务端口
|
|
|
- */
|
|
|
- public static Integer getPort(@NonNull Resource resource) {
|
|
|
- Properties properties = getResourceProperties(resource);
|
|
|
- if (properties == null) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- String property = properties.getProperty(SERVER_PORT_PROPERTY);
|
|
|
- return StringUtils.ifEmpty(property, Integer::parseInt);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取服务端口
|
|
|
- *
|
|
|
- * @param environment 应用环境
|
|
|
- * @return 服务端口
|
|
|
- */
|
|
|
- public static Integer getPort(@NonNull Environment environment) {
|
|
|
- String property = environment.getProperty(SERVER_PORT_PROPERTY);
|
|
|
- return StringUtils.ifEmpty(property, Integer::parseInt);
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* 获取环境标识
|
|
|
*
|
|
@@ -205,7 +113,7 @@ public class ApplicationContextHolder implements EnvironmentAware, ApplicationCo
|
|
|
* @return 环境标识
|
|
|
*/
|
|
|
public static String getProfile(@NonNull Resource resource) {
|
|
|
- Properties properties = getResourceProperties(resource);
|
|
|
+ Properties properties = SpringUtils.getResourceProperties(resource);
|
|
|
return properties == null ? null : properties.getProperty(APPLICATION_PROFILE_PROPERTY);
|
|
|
}
|
|
|
|
|
@@ -250,56 +158,56 @@ public class ApplicationContextHolder implements EnvironmentAware, ApplicationCo
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 获取应用环境对象
|
|
|
+ * 获取应用名称
|
|
|
*
|
|
|
- * @return 应用环境对象
|
|
|
+ * @return 应用名称
|
|
|
*/
|
|
|
- public static Environment getEnvironment() {
|
|
|
- return getEnvironment(true);
|
|
|
+ public static String getApplicationName() {
|
|
|
+ Environment environment = getEnvironment(false);
|
|
|
+ return environment == null ? null : getApplicationName(environment);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 获取应用环境对象
|
|
|
+ * 根据 *.yml、*.properties文件资源获取应用名称
|
|
|
*
|
|
|
- * @param required 是否必须
|
|
|
- * @return 应用环境对象
|
|
|
+ * @param resource *.yml、*.properties文件资源对象实例
|
|
|
+ * @return 应用名称
|
|
|
*/
|
|
|
- public static Environment getEnvironment(boolean required) {
|
|
|
- if (required) {
|
|
|
- return AssertUtils.nonnull(ENVIRONMENT, () -> "Application environment has not been initialized");
|
|
|
- }
|
|
|
- return ENVIRONMENT;
|
|
|
+ public static String getApplicationName(@NonNull Resource resource) {
|
|
|
+ Properties properties = SpringUtils.getResourceProperties(resource);
|
|
|
+ return properties == null ? null : properties.getProperty(APPLICATION_NAME_PROPERTY);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取应用名称
|
|
|
*
|
|
|
+ * @param environment 应用环境
|
|
|
* @return 应用名称
|
|
|
*/
|
|
|
- public static String getApplicationName() {
|
|
|
- Environment environment = getEnvironment(false);
|
|
|
- return environment == null ? null : getApplicationName(environment);
|
|
|
+ public static String getApplicationName(@NonNull Environment environment) {
|
|
|
+ return environment.getProperty(APPLICATION_NAME_PROPERTY);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 获取应用名称
|
|
|
+ * 获取应用环境对象
|
|
|
*
|
|
|
- * @param environment 应用环境
|
|
|
- * @return 应用名称
|
|
|
+ * @return 应用环境对象
|
|
|
*/
|
|
|
- public static String getApplicationName(@NonNull Environment environment) {
|
|
|
- return environment.getProperty(APPLICATION_NAME_PROPERTY);
|
|
|
+ public static Environment getEnvironment() {
|
|
|
+ return getEnvironment(true);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 根据 *.yml、*.properties文件资源获取应用名称
|
|
|
+ * 获取应用环境对象
|
|
|
*
|
|
|
- * @param resource *.yml、*.properties文件资源对象实例
|
|
|
- * @return 应用名称
|
|
|
+ * @param required 是否必须
|
|
|
+ * @return 应用环境对象
|
|
|
*/
|
|
|
- public static String getApplicationName(@NonNull Resource resource) {
|
|
|
- Properties properties = getResourceProperties(resource);
|
|
|
- return properties == null ? null : properties.getProperty(APPLICATION_NAME_PROPERTY);
|
|
|
+ public static Environment getEnvironment(boolean required) {
|
|
|
+ if (required) {
|
|
|
+ return AssertUtils.nonnull(ENVIRONMENT, () -> "Application environment has not been initialized");
|
|
|
+ }
|
|
|
+ return ENVIRONMENT;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -324,212 +232,6 @@ public class ApplicationContextHolder implements EnvironmentAware, ApplicationCo
|
|
|
return APPLICATION_CONTEXT;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 获取所有application.yml文件资源
|
|
|
- *
|
|
|
- * @return 资源对象数组
|
|
|
- */
|
|
|
- public static List<Resource> getApplicationResources() {
|
|
|
- List<Resource> resources = Lists.newLinkedList();
|
|
|
- ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
|
|
-
|
|
|
- // bootstrap.yml配置文件
|
|
|
- try {
|
|
|
- resources.addAll(Arrays.asList(resourcePatternResolver.getResources(BOOTSTRAP_YML_PATH)));
|
|
|
- } catch (IOException e) {
|
|
|
- throw new RuntimeException(e);
|
|
|
- }
|
|
|
-
|
|
|
- // 查找application.yml配置文件
|
|
|
- try {
|
|
|
- resources.addAll(Arrays.asList(resourcePatternResolver.getResources(APPLICATION_YML_PATH)));
|
|
|
- } catch (IOException e) {
|
|
|
- throw new RuntimeException(e);
|
|
|
- }
|
|
|
-
|
|
|
- // bootstrap.properties配置文件
|
|
|
- try {
|
|
|
- resources.addAll(Arrays.asList(resourcePatternResolver.getResources(BOOTSTRAP_PROPERTIES_PATH)));
|
|
|
- } catch (IOException e) {
|
|
|
- throw new RuntimeException(e);
|
|
|
- }
|
|
|
-
|
|
|
- // 查找application.properties配置文件
|
|
|
- try {
|
|
|
- resources.addAll(Arrays.asList(resourcePatternResolver.getResources(APPLICATION_PROPERTIES_PATH)));
|
|
|
- } catch (IOException e) {
|
|
|
- throw new RuntimeException(e);
|
|
|
- }
|
|
|
- return resources;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 判断类对象是否属于指定资源
|
|
|
- *
|
|
|
- * @param resource 资源对象
|
|
|
- * @param clazz 类对象
|
|
|
- * @return true/false
|
|
|
- */
|
|
|
- public static boolean isResourceClass(@NonNull Resource resource, @NonNull Class<?> clazz) {
|
|
|
- String file = clazz.getProtectionDomain().getCodeSource().getLocation().getPath();
|
|
|
- try {
|
|
|
- return resource.getURL().getPath().contains(file);
|
|
|
- } catch (IOException e) {
|
|
|
- throw new RuntimeException(e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取资源文件 .yml、.properties属性
|
|
|
- *
|
|
|
- * @param resource *.yml、*.properties文件资源对象实例
|
|
|
- * @return 应用名称
|
|
|
- */
|
|
|
- public static Properties getResourceProperties(@NonNull Resource resource) {
|
|
|
- String filename = resource.getFilename();
|
|
|
- if (StringUtils.isEmpty(filename) || filename.endsWith(".yml")) {
|
|
|
- // yml
|
|
|
- YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
|
|
|
- yaml.setResources(resource);
|
|
|
- return yaml.getObject();
|
|
|
- }
|
|
|
- // properties
|
|
|
- Properties properties = new Properties();
|
|
|
- try (InputStream input = resource.getInputStream()) {
|
|
|
- properties.load(input);
|
|
|
- } catch (IOException e) {
|
|
|
- throw new RuntimeException(e);
|
|
|
- }
|
|
|
- return properties;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 查找接口对象实例
|
|
|
- *
|
|
|
- * @return 接口对象实例列表
|
|
|
- */
|
|
|
- public static List<Object> lookupControllers() {
|
|
|
- return lookupControllers(getApplicationContext());
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 查找接口对象实例
|
|
|
- *
|
|
|
- * @param applicationContext 应用上下文
|
|
|
- * @return 接口对象实例列表
|
|
|
- */
|
|
|
- public static List<Object> lookupControllers(@NonNull ApplicationContext applicationContext) {
|
|
|
- return Stream.of(applicationContext.getBeansWithAnnotation(Controller.class).values(),
|
|
|
- applicationContext.getBeansWithAnnotation(RestController.class).values())
|
|
|
- .flatMap(Collection::stream).distinct().collect(Collectors.toList());
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 查找类对象所属资源
|
|
|
- *
|
|
|
- * @param clazz 类对象
|
|
|
- * @param resources 资源对象集合
|
|
|
- * @return 资源对象
|
|
|
- */
|
|
|
- public static Resource lookupClassResource(@NonNull Class<?> clazz, @NonNull Collection<Resource> resources) {
|
|
|
- if (ObjectUtils.isEmpty(resources)) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- return resources.stream().filter(resource -> isResourceClass(resource, clazz)).findAny().orElse(null);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 查找应用中的类对象
|
|
|
- *
|
|
|
- * @param condition 类对象条件判断
|
|
|
- * @return 类对象列表
|
|
|
- */
|
|
|
- public static List<Class<?>> lookupApplicationClasses(@NonNull Predicate<Class<?>> condition) {
|
|
|
- return lookupApplicationClasses(getApplicationContext(), condition);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 查找应用中的类对象
|
|
|
- *
|
|
|
- * @param applicationContext 应用上下文对象
|
|
|
- * @param condition 类对象条件判断
|
|
|
- * @return 类对象列表
|
|
|
- */
|
|
|
- public static List<Class<?>> lookupApplicationClasses(@NonNull ApplicationContext applicationContext,
|
|
|
- @NonNull Predicate<Class<?>> condition) {
|
|
|
- Set<String> packages = Sets.newHashSet();
|
|
|
- applicationContext.getBeansWithAnnotation(SpringBootApplication.class).forEach((key, value) -> {
|
|
|
- Class<?> clazz = value.getClass();
|
|
|
-
|
|
|
- // 加载@ComponentScan包扫描路径配置
|
|
|
- ComponentScan componentScan = AnnotationUtils.findAnnotation(clazz, ComponentScan.class);
|
|
|
- if (componentScan != null) {
|
|
|
- packages.addAll(Arrays.asList(componentScan.basePackages()));
|
|
|
- }
|
|
|
-
|
|
|
- // 加载@SpringBootApplication包扫描路径配置
|
|
|
- SpringBootApplication springBootApplication =
|
|
|
- AnnotationUtils.findAnnotation(clazz, SpringBootApplication.class);
|
|
|
- if (springBootApplication != null) {
|
|
|
- packages.addAll(Arrays.asList(springBootApplication.scanBasePackages()));
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- // 根据包扫描路径查找类对象
|
|
|
- return packages.stream().flatMap(pack -> SpringUtils.lookupClasses(pack, condition).stream())
|
|
|
- .distinct().collect(Collectors.toList());
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 注册对象实例
|
|
|
- *
|
|
|
- * @param name 对象名称
|
|
|
- * @param type 对象类型
|
|
|
- * @param supplier 对象实例提供函数
|
|
|
- * @param <T> 对象类型泛型
|
|
|
- * @return 对象实例
|
|
|
- */
|
|
|
- public static <T> T register(@NonNull String name, @NonNull Class<T> type, @NonNull Supplier<T> supplier) {
|
|
|
- ApplicationContext applicationContext = getApplicationContext();
|
|
|
- ((GenericApplicationContext) getApplicationContext()).registerBean(name, type, supplier);
|
|
|
- return applicationContext.getBean(name, type);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 自定义消息转换处理器
|
|
|
- *
|
|
|
- * @param converters 消息转换处理器列表
|
|
|
- * @return 消息转换处理器列表
|
|
|
- */
|
|
|
- public static List<HttpMessageConverter<?>> converters(List<HttpMessageConverter<?>> converters) {
|
|
|
- if (ObjectUtils.isEmpty(converters)) {
|
|
|
- return Collections.emptyList();
|
|
|
- }
|
|
|
- return converters.stream().map(converter -> {
|
|
|
- Class<?> clazz = converter.getClass();
|
|
|
- if (clazz == StringHttpMessageConverter.class) {
|
|
|
- converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
|
|
|
- } else if (converter instanceof AbstractJackson2HttpMessageConverter) {
|
|
|
- ObjectMapper mapper = JacksonUtils.getDefaultSerializer();
|
|
|
- List<MediaType> types = Lists.newArrayList(converter.getSupportedMediaTypes());
|
|
|
- if (!types.contains(MediaType.TEXT_PLAIN)) {
|
|
|
- types.add(MediaType.TEXT_PLAIN);
|
|
|
- }
|
|
|
- if (clazz == MappingJackson2HttpMessageConverter.class) {
|
|
|
- converter = new MappingJackson2HttpMessageConverter(mapper);
|
|
|
- } else if (clazz == MappingJackson2XmlHttpMessageConverter.class) {
|
|
|
- converter = new MappingJackson2XmlHttpMessageConverter(mapper);
|
|
|
- } else if (clazz == MappingJackson2CborHttpMessageConverter.class) {
|
|
|
- converter = new MappingJackson2CborHttpMessageConverter(mapper);
|
|
|
- } else if (clazz == MappingJackson2SmileHttpMessageConverter.class) {
|
|
|
- converter = new MappingJackson2SmileHttpMessageConverter(mapper);
|
|
|
- }
|
|
|
- ((AbstractJackson2HttpMessageConverter) converter).setSupportedMediaTypes(types);
|
|
|
- }
|
|
|
- return converter;
|
|
|
- }).collect(Collectors.toList());
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* 基于@Order注解对类对象排序
|
|
|
*
|