shz.spring.BeanContainer Maven / Gradle / Ivy
package shz.spring;
import com.alibaba.fastjson2.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
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 shz.core.*;
import shz.core.cl.ClassLoaderHelp;
import shz.core.constant.ArrayConstant;
import shz.core.constant.NullConstant;
import shz.core.function.Todo;
import shz.core.msg.ClientFailureMsg;
import shz.core.thread.UncaughtExceptionHandler;
import shz.core.type.TypeHelp;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.*;
import java.util.stream.Collectors;
/**
* 执行顺序
* //@AutoConfigureAfter:在指定的配置类初始化后再加载
* //@AutoConfigureBefore:在指定的配置类初始化前加载
* //@AutoConfigureOrder:数越小越先初始化
*
* 条件配置
* //@ConditionalOnClass : classpath中存在该类时起效
* //@ConditionalOnMissingClass : classpath中不存在该类时起效
* //@ConditionalOnBean : DI容器中存在该类型Bean时起效
* //@ConditionalOnMissingBean : DI容器中不存在该类型Bean时起效
* //@ConditionalOnSingleCandidate : DI容器中该类型Bean只有一个或@Primary的只有一个时起效
* //@ConditionalOnExpression : SpEL表达式结果为true时
* //@ConditionalOnProperty : 参数设置或者值一致时起效
* //@ConditionalOnResource : 指定的文件存在时起效
* //@ConditionalOnJndi : 指定的JNDI存在时起效
* //@ConditionalOnJava : 指定的Java版本存在时起效
* //@ConditionalOnWebApplication : Web应用环境下起效
* //@ConditionalOnNotWebApplication : 非Web应用环境下起效
*/
@SuppressWarnings("unchecked")
public final class BeanContainer implements ApplicationContextInitializer, EnvironmentPostProcessor, BeanDefinitionRegistryPostProcessor, ApplicationListener, Ordered {
private static final Logger log = LoggerFactory.getLogger(BeanContainer.class);
private static volatile ApplicationContext context;
private static Environment environment;
private static volatile DefaultListableBeanFactory beanFactory;
private static final Object setMonitor = new Object();
/**
* 执行列表
*/
private static List TODO_LIST = new CopyOnWriteArrayList<>();
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
synchronized (setMonitor) {
BeanContainer.context = applicationContext;
if (beanFactory != null) todo();
}
}
private void todo() {
if (TODO_LIST != null) {
TODO_LIST.stream().sorted(Comparator.comparing(Todo::order)).forEach(Todo::run);
TODO_LIST = null;
}
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
BeanContainer.environment = environment;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
if (!(configurableListableBeanFactory instanceof DefaultListableBeanFactory)) return;
synchronized (setMonitor) {
BeanContainer.beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
if (context != null) todo();
}
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
synchronized (setMonitor) {
BeanContainer.context = event.getApplicationContext();
if (beanFactory != null) todo();
}
Thread.UncaughtExceptionHandler uch = Thread.getDefaultUncaughtExceptionHandler();
if (uch != null) return;
uch = get(UncaughtExceptionHandler.class);
if (uch == null) {
for (UncaughtExceptionHandler e : ServiceLoader.load(UncaughtExceptionHandler.class)) {
uch = e;
break;
}
}
Thread.setDefaultUncaughtExceptionHandler(uch == null ? (t, e) -> log.error(
"[未捕获线程异常]id:{},name:{},msg:{},trace:{}",
t.getId(), t.getName(), e.getMessage(), Arrays.stream(e.getStackTrace()).map(Object::toString).collect(Collectors.joining("\n"))
) : uch);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
public static ApplicationContext getContext() {
return context;
}
public static Environment getEnvironment() {
return environment;
}
public static DefaultListableBeanFactory getBeanFactory() {
return beanFactory;
}
public static T get(String name) {
T bean = null;
try {
bean = (T) context.getBean(name);
} catch (Throwable ignored) {
}
return bean;
}
public static void set(int order, Runnable setter) {
if (context == null || beanFactory == null) {
synchronized (setMonitor) {
if (context == null || beanFactory == null) {
TODO_LIST.add(new Todo() {
@Override
public int order() {
return order;
}
@Override
public void run() {
setter.run();
}
});
return;
}
}
}
setter.run();
}
public static void set(Runnable setter) {
set(0, setter);
}
public static void set(int order, String name, Consumer setter) {
set(order, () -> setter.accept(get(name)));
}
public static void set(String name, Consumer setter) {
set(0, name, setter);
}
public static T get(String name, Supplier supplier) {
T bean = get(name);
if (bean != null) return bean;
if (supplier == null) return null;
bean = supplier.get();
if (bean != null) try {
beanFactory.registerSingleton(name, bean);
} catch (Throwable ignored) {
}
return bean;
}
public static void set(int order, String name, Supplier supplier, Consumer setter) {
set(order, () -> setter.accept(get(name, supplier)));
}
public static void set(String name, Supplier supplier, Consumer setter) {
set(0, name, supplier, setter);
}
public static T get(Class extends T> cls) {
T bean = null;
try {
bean = context.getBean(cls);
} catch (Throwable ignored) {
}
return bean;
}
public static void set(int order, Class extends T> cls, Consumer setter) {
set(order, () -> setter.accept(get(cls)));
}
public static void set(Class extends T> cls, Consumer setter) {
set(0, cls, setter);
}
public static T get(Class extends T> cls, Supplier supplier) {
T bean = get(cls);
if (bean != null) return bean;
if (supplier == null) return null;
bean = supplier.get();
if (bean != null) try {
beanFactory.registerSingleton(cls.toGenericString(), bean);
} catch (Throwable ignored) {
}
return bean;
}
public static void set(int order, Class extends T> cls, Supplier supplier, Consumer setter) {
set(order, () -> setter.accept(get(cls, supplier)));
}
public static void set(Class extends T> cls, Supplier supplier, Consumer setter) {
set(0, cls, supplier, setter);
}
public static T get(String name, String className) {
T bean = get(name);
if (bean != null) return bean;
Class cls = (Class) ClassLoaderHelp.load(className, true, ClassLoaderHelp.get());
if (cls == null) return null;
return get(cls, () -> AccessibleHelp.newInstance(cls));
}
public static void set(int order, String name, String className, Consumer setter) {
set(order, () -> setter.accept(get(name, className)));
}
public static void set(String name, String className, Consumer setter) {
set(0, name, className, setter);
}
public static Class getBeanClass(Object bean) {
return (Class) (AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) : bean.getClass());
}
public static T getTargetBean(Object bean) {
while (true) if (!AopUtils.isAopProxy(bean = getTargetBean0(bean))) break;
return (T) bean;
}
private static Object getTargetBean0(Object bean) {
try {
if (AopUtils.isJdkDynamicProxy(bean)) return getJdkTargetBean(bean);
else if (AopUtils.isCglibProxy(bean)) return getCglibTargetBean(bean);
} catch (Exception e) {
return null;
}
return bean;
}
private static Object getJdkTargetBean(Object proxy) throws Exception {
Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
h.setAccessible(true);
AopProxy aopProxy = (AopProxy) h.get(proxy);
Field advised = aopProxy.getClass().getDeclaredField("advised");
advised.setAccessible(true);
return ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
}
private static Object getCglibTargetBean(Object proxy) throws Exception {
Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
h.setAccessible(true);
Object dynamicAdvisedInterceptor = h.get(proxy);
Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
advised.setAccessible(true);
return ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
}
private static final DefaultParameterNameDiscoverer PND = new DefaultParameterNameDiscoverer();
public static String[] getParameterNames(Method method) {
return PND.getParameterNames(method);
}
public static String[] getParameterNames(Constructor> constructor) {
return PND.getParameterNames(constructor);
}
private static final ResourcePatternResolver RPR = new PathMatchingResourcePatternResolver();
public static Resource getResource(String location) {
return RPR.getResource(getExprProperty(location));
}
public static Resource[] getResources(String locationPattern) {
try {
return RPR.getResources(getExprProperty(locationPattern));
} catch (IOException e) {
return new Resource[0];
}
}
public static void registerBeanDefinition(int order, Class> cls, Class> fbCls, Object... args) {
set(order, () -> registerBeanDefinition0(cls, fbCls, args));
}
private static void registerBeanDefinition0(Class> cls, Class> fbCls, Object... args) {
if (context.containsBeanDefinition(cls.getSimpleName())) return;
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(cls);
GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
ConstructorArgumentValues argumentValues = definition.getConstructorArgumentValues();
for (int i = 0; i < args.length; ++i) argumentValues.addIndexedArgumentValue(i, args[i]);
definition.setBeanClass(fbCls);
definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
beanFactory.registerBeanDefinition(cls.getSimpleName(), definition);
}
public static void registerBeanDefinition(Class> cls, Class> fbCls, Object... args) {
registerBeanDefinition(0, cls, fbCls, args);
}
public static void registerBeanDefinitionAnnotatedWith(int order, Class aCls, Class> fbCls, Function, Object[]> func) {
set(order, () -> TypeHelp.consumerClasses(c -> {
if (c.isAnnotationPresent(aCls)) registerBeanDefinition0(c, fbCls, func.apply(c));
return 0;
}, 0));
}
public static void registerBeanDefinitionAnnotatedWith(Class aCls, Class> fbCls, Function, Object[]> func) {
registerBeanDefinitionAnnotatedWith(0, aCls, fbCls, func);
}
public static void registerBeanDefinitionChildes(int order, Class> cls, Class> fbCls, Function, Object[]> func) {
set(order, () -> TypeHelp.consumerClasses(c -> {
if (cls.isAssignableFrom(c)) registerBeanDefinition0(c, fbCls, func.apply(c));
return 0;
}, 0));
}
public static void registerBeanDefinitionChildes(Class> cls, Class> fbCls, Function, Object[]> func) {
registerBeanDefinitionChildes(0, cls, fbCls, func);
}
public static String getExprProperty(String s) {
return RegexHelp.transform(s, environment::getProperty);
}
public static void setExprProperty(int order, String s, Consumer setter) {
set(order, () -> setter.accept(getExprProperty(s)));
}
public static void setExprProperty(String s, Consumer setter) {
setExprProperty(0, s, setter);
}
public static String getProperty(String key) {
return environment.getProperty(key);
}
public static void setProperty(int order, String key, Consumer setter) {
set(order, () -> setter.accept(getProperty(key)));
}
public static void setProperty(String key, Consumer setter) {
setProperty(0, key, setter);
}
public static void consumerBeanAnnotatedWith(int order, Class cls, BiConsumer beanConsumer) {
set(order, () -> context.getBeansWithAnnotation(cls).forEach(beanConsumer));
}
public static void consumerBeanAnnotatedWith(Class cls, BiConsumer beanConsumer) {
consumerBeanAnnotatedWith(0, cls, beanConsumer);
}
public static void consumerBean(int order, Predicate beanNamePredicate, Predicate