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

cn.crane4j.extension.spring.Crane4jApplicationContext Maven / Gradle / Ivy

There is a newer version: 2.8.2
Show newest version
package cn.crane4j.extension.spring;

import cn.crane4j.core.cache.CacheManager;
import cn.crane4j.core.container.Container;
import cn.crane4j.core.container.ContainerDefinition;
import cn.crane4j.core.container.ContainerProvider;
import cn.crane4j.core.container.DefaultContainerManager;
import cn.crane4j.core.container.lifecycle.ContainerLifecycleProcessor;
import cn.crane4j.core.executor.BeanOperationExecutor;
import cn.crane4j.core.executor.handler.AssembleOperationHandler;
import cn.crane4j.core.executor.handler.DisassembleOperationHandler;
import cn.crane4j.core.executor.handler.key.KeyResolver;
import cn.crane4j.core.parser.BeanOperationParser;
import cn.crane4j.core.parser.handler.strategy.PropertyMappingStrategy;
import cn.crane4j.core.parser.handler.strategy.PropertyMappingStrategyManager;
import cn.crane4j.core.parser.handler.strategy.SimplePropertyMappingStrategyManager;
import cn.crane4j.core.support.Crane4jGlobalConfiguration;
import cn.crane4j.core.support.Crane4jGlobalSorter;
import cn.crane4j.core.support.TypeResolver;
import cn.crane4j.core.support.converter.ConverterManager;
import cn.crane4j.core.support.reflect.PropertyOperator;
import cn.crane4j.core.util.ConfigurationUtil;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Delegate;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.ApplicationContext;
import org.springframework.core.DecoratingProxy;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.Order;

import java.lang.reflect.AnnotatedElement;
import java.util.Objects;

/**
 * 

The global configuration class implemented based on the Spring context, * when obtaining the required components from the instance, * will directly obtain the corresponding bean through the {@link ApplicationContext} held. * * @author huangchengxing * @see ApplicationContext */ @Slf4j @RequiredArgsConstructor public class Crane4jApplicationContext extends DefaultContainerManager implements Crane4jGlobalConfiguration, SmartInitializingSingleton, DisposableBean, InitializingBean { static { // support compare by @Order annotation and Ordered interface Crane4jGlobalSorter.INSTANCE.addCompareValueExtractor(t -> { if (Objects.isNull(t)) { return null; } if (t instanceof Ordered) { return ((Ordered)t).getOrder(); } Integer order = findOrderFromAnnotation(t); if (Objects.isNull(order) && t instanceof DecoratingProxy) { order = findOrderFromAnnotation(((DecoratingProxy)t).getDecoratedClass()); } return order; }); } @Nullable private static Integer findOrderFromAnnotation(Object t) { if (!(t instanceof AnnotatedElement)) { return null; } Order annotation = AnnotatedElementUtils.findMergedAnnotation(((AnnotatedElement) t), Order.class); return Objects.nonNull(annotation) ? annotation.value() : null; } /** * application context */ @Getter private final ApplicationContext applicationContext; /** * bean name <-> container namespace */ private final BiMap beanNameNamespaceMapping = HashBiMap.create(); /** * property mapping strategy manager */ @Delegate private final PropertyMappingStrategyManager propertyMappingStrategyManager = new SimplePropertyMappingStrategyManager(); /** * Get {@link ConverterManager} * * @return {@link ConverterManager} */ @Override public ConverterManager getConverterManager() { return applicationContext.getBean(ConverterManager.class); } /** * Get property operator. * * @return property operator */ @Override public PropertyOperator getPropertyOperator() { return applicationContext.getBean(PropertyOperator.class); } /** * Get type handler. * * @return type handler */ @Override public TypeResolver getTypeResolver() { return applicationContext.getBean(TypeResolver.class); } /** * Get {@link ContainerProvider} by given name. * * @param name name * @return {@link ContainerProvider} instance */ @SuppressWarnings("unchecked") @Nullable @Override public T getContainerProvider(String name) { T provider = super.getContainerProvider(name); return Objects.isNull(provider) && applicationContext.containsBean(name) ? (T)applicationContext.getBean(name, ContainerProvider.class) : provider; } /** * Obtaining and caching container instances from provider or definition. * * @param namespace namespace of container, which can also be the cache name for the container instance. * @return container instance * @see ContainerLifecycleProcessor#whenCreated */ @Nullable @Override public Container getContainer(String namespace) { // if namespace is a bean name, convert it to namespace, otherwise use it directly namespace = beanNameNamespaceMapping.getOrDefault(namespace, namespace); return super.getContainer(namespace); } /** * Whether this provider has container of given {@code namespace}. * * @param namespace namespace * @return boolean */ @Override public boolean containsContainer(String namespace) { return super.containsContainer(namespace) || applicationContext.containsBean(namespace); } /** * Get bean operation executor. * * @param executorName executor name * @param executorType executor type * @return executor */ @NonNull @Override public BeanOperationExecutor getBeanOperationExecutor( @Nullable String executorName, Class executorType) { return ConfigurationUtil.getComponentFromConfiguration( BeanOperationExecutor.class, executorType, executorName, (t, n) -> applicationContext.getBean(n, t), applicationContext::getBean ); } /** * Get bean operation parser. * * @param parserName parser name * @param parserType parser type * @return parser */ @NonNull @Override public BeanOperationParser getBeanOperationsParser(@Nullable String parserName, Class parserType) { return ConfigurationUtil.getComponentFromConfiguration( BeanOperationParser.class, parserType, parserName, (t, n) -> applicationContext.getBean(n, t), applicationContext::getBean ); } /** * Get assemble operation handler. * * @param handlerName handler name * @param handlerType handler type * @return handler */ @NonNull @Override public AssembleOperationHandler getAssembleOperationHandler(@Nullable String handlerName, Class handlerType) { return ConfigurationUtil.getComponentFromConfiguration( AssembleOperationHandler.class, handlerType, handlerName, (t, n) -> applicationContext.getBean(n, t), applicationContext::getBean ); } /** * Get disassemble operation handler. * * @param handlerName handler name * @param handlerType handler type * @return handler */ @NonNull @Override public DisassembleOperationHandler getDisassembleOperationHandler(@Nullable String handlerName, Class handlerType) { return ConfigurationUtil.getComponentFromConfiguration( DisassembleOperationHandler.class, handlerType, handlerName, (t, n) -> applicationContext.getBean(n, t), applicationContext::getBean ); } /** * Get cache factory. * * @param name cache factory name * @return cache factory * @since 2.4.0 */ @NonNull @Override public CacheManager getCacheManager(String name) { return applicationContext.getBean(name, CacheManager.class); } /** * Get bean name by namespace. * * @param namespace namespace * @return bean name */ @Nullable public String getBeanNameByNamespace(String namespace) { return beanNameNamespaceMapping.inverse().get(namespace); } /** * Get namespace by bean name. * * @param beanName namespace * @return namespace */ @Nullable public String getNamespaceByBeanName(String beanName) { return beanNameNamespaceMapping.get(beanName); } /** * Get key resolver. * * @param resolverType resolver type * @return key resolver * @since 2.7.0 */ @Override public KeyResolver getKeyResolver(Class resolverType) { if (applicationContext.getBeanNamesForType(resolverType).length > 0) { return applicationContext.getBean(resolverType); } return applicationContext.getAutowireCapableBeanFactory() .createBean(resolverType); } // ============================ life cycle ============================ /** * Load all {@link ContainerLifecycleProcessor} from spring context. */ @Override public void afterPropertiesSet() { applicationContext.getBeansOfType(ContainerLifecycleProcessor.class).forEach((name, processor) -> { log.info("install container lifecycle processor [{}]", name); registerContainerLifecycleProcessor(processor); }); } /** * After Spring initializes all singleton beans, * register all beans that implement the {@link Container} interface with the current context. */ @Override public void afterSingletonsInstantiated() { applicationContext.getBeansOfType(ContainerLifecycleProcessor.class).forEach((name, processor) -> { if (registerContainerLifecycleProcessor(processor)) { log.info("install container lifecycle processor [{}]", name); } }); applicationContext.getBeansOfType(ContainerDefinition.class).forEach((beanName, definition) -> { beanNameNamespaceMapping.put(beanName, definition.getNamespace()); log.info("register container definition bean [{}] from spring context, actual namespace is [{}]", beanName, definition.getNamespace()); registerContainer(definition); }); applicationContext.getBeansOfType(Container.class).forEach((beanName, container) -> { beanNameNamespaceMapping.put(beanName, container.getNamespace()); log.info("register container bean [{}] bean from spring context, actual namespace is [{}]", beanName, container.getNamespace()); registerContainer(container); }); applicationContext.getBeansOfType(ContainerProvider.class) .forEach((beanName, provider) -> { log.info("register container provider [{}] from spring context", beanName); registerContainerProvider(beanName, provider); }); applicationContext.getBeansOfType(PropertyMappingStrategy.class) .forEach((beanName, strategy) -> { log.info("register property mapping strategy manager [{}]({}) from spring context", beanName, strategy); propertyMappingStrategyManager.addPropertyMappingStrategy(strategy); }); } /** * Clear container cache on destruction. */ @Override public void destroy() { log.info("global configuration has been destroyed."); clear(); // TODO clear propertyMappingStrategyManager and keyResolverRegistry } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy