All Downloads are FREE. Search and download functionalities are using the official Maven repository.

shz.spring.BeanContainer Maven / Gradle / Ivy

There is a newer version: 2023.2.5
Show newest version
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 cls) { T bean = null; try { bean = context.getBean(cls); } catch (Throwable ignored) { } return bean; } public static void set(int order, Class cls, Consumer setter) { set(order, () -> setter.accept(get(cls))); } public static void set(Class cls, Consumer setter) { set(0, cls, setter); } public static T get(Class 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 cls, Supplier supplier, Consumer setter) { set(order, () -> setter.accept(get(cls, supplier))); } public static void set(Class 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 beanPredicate, BiConsumer beanConsumer) { set(order, () -> { for (String name : context.getBeanDefinitionNames()) { if (beanNamePredicate == null || beanNamePredicate.test(name)) { Object bean = get(name); if (bean == null) continue; bean = getTargetBean(bean); if (bean == null) continue; if (beanPredicate == null || beanPredicate.test(bean)) beanConsumer.accept(name, bean); } } }); } public static void consumerBean(Predicate beanNamePredicate, Predicate beanPredicate, BiConsumer beanConsumer) { consumerBean(0, beanNamePredicate, beanPredicate, beanConsumer); } public static void inject(int order, Predicate beanNamePredicate, Predicate beanPredicate, BiFunction valueFunc, boolean force) { consumerBean(order, beanNamePredicate, beanPredicate, (name, bean) -> AccessibleHelp.setField(bean, field -> { Object val; if (!force) { val = AccessibleHelp.getField(field, bean); if (val != null) return NullConstant.OBJECT; } val = valueFunc == null ? get(field.getType()) : valueFunc.apply(bean, field); if (val != null) return val; return NullConstant.OBJECT; })); } public static void inject(Predicate beanNamePredicate, Predicate beanPredicate, BiFunction valueFunc, boolean force) { inject(0, beanNamePredicate, beanPredicate, valueFunc, force); } public static void inject(int order, BiFunction valueFunc) { inject(order, name -> !name.startsWith("org.springframework"), null, valueFunc, false); } public static void inject(BiFunction valueFunc) { inject(0, valueFunc); } public static T invoke(String className, String method, String[] typeNames, String[] strArgs) { Class cls = ClassLoaderHelp.load(className); ClientFailureMsg.requireNonNull(cls, "类%s不存在", className); Object bean = get(cls); ClientFailureMsg.requireNonNull(bean, "实例不存在,类:%s", className); Class[] ptypes; if (NullHelp.isEmpty(typeNames)) ptypes = ArrayConstant.EMPTY_CLASS_ARRAY; else { ptypes = new Class[typeNames.length]; Arrays.setAll(ptypes, i -> ClassLoaderHelp.load(typeNames[i])); } Object[] args; if (NullHelp.isEmpty(ptypes)) args = ArrayConstant.EMPTY_OBJECT_ARRAY; else { ClientFailureMsg.requireNonEmpty(strArgs, "缺少参数"); ClientFailureMsg.requireNon(strArgs.length != ptypes.length, "参数类型与值个数不一致"); args = new Object[ptypes.length]; Arrays.setAll(args, i -> { Object obj = FieldSetter.parse(strArgs[i], ptypes[i]); if (obj != null && obj != NullConstant.OBJECT) return obj; return JSON.parseObject(strArgs[i], ptypes[i]); }); } return AccessibleHelp.invoke(bean, method, ptypes, args); } }