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

com.plugin.development.context.AnnotationConfigPluginContextFactory Maven / Gradle / Ivy

There is a newer version: 3.0.0
Show newest version
package com.plugin.development.context;

import com.plugin.development.context.process.PluginPostBeanProcess;
import com.plugin.development.exception.PluginBeanFactoryException;
import com.plugin.development.context.factory.PluginBeanRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 针对 AnnotationConfigApplicationContext 处理的插件工厂管理者
 * @author zhangzhuo
 * @version 1.0
 */
public class AnnotationConfigPluginContextFactory
        extends AbstractPluginContextFactory {

    private final Logger log = LoggerFactory.getLogger(AnnotationConfigPluginContextFactory.class);
    /**
     * spring 管理的插件bean集合Map.key为插件的id
     */
    private final static Map SPRING_BEAN_MAP = new ConcurrentHashMap<>();
    private final static Lock LOCK = new ReentrantLock(true);

    /**
     * 主程序中的 ApplicationContext。不要和插件中的 ApplicationContext 混淆
     */
    private final ApplicationContext mainApplicationContext;
    private final PluginBeanRegistry componentBeanRegistry;
    private final PluginBeanRegistry> pluginControllerBeanRegistry;

    private final List pluginPostBeanProcess;

    public AnnotationConfigPluginContextFactory(PluginContext pluginContext) {
        Objects.requireNonNull(pluginContext);
        Objects.requireNonNull(pluginContext.getMainApplicationContext());
        this.mainApplicationContext = pluginContext.getMainApplicationContext();
        this.componentBeanRegistry = pluginContext.getComponentBeanRegistry();
        this.pluginControllerBeanRegistry = pluginContext.getControllerBeanRegistry();
        List pluginPostBeanProcess = pluginContext.getPluginPostBeanProcess();
        if(pluginPostBeanProcess == null){
            this.pluginPostBeanProcess = new ArrayList<>();
        } else {
            this.pluginPostBeanProcess = pluginPostBeanProcess;
        }

    }


    @Override
    public void registry(String pluginId, AnnotationConfigApplicationContext applicationContext)
            throws PluginBeanFactoryException {
        log.debug("Start registry");
        refreshBefore(pluginId, applicationContext);
        // 刷新插件ApplicationContext
        applicationContext.refresh();
        processPluginApplication(pluginId, applicationContext);
        notifyRegistry(pluginId);
        log.debug("registry finish");
    }



    /**
     * 处理插件中的Application
     * @param pluginId 插件id
     * @param applicationContext 主程序上下文
     * @throws PluginBeanFactoryException 插件bean工厂异常
     */
    protected void processPluginApplication(String pluginId, AnnotationConfigApplicationContext applicationContext)
            throws PluginBeanFactoryException {
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        LOCK.lock();
        try {
            registryBefore(pluginId, applicationContext);
            if(SPRING_BEAN_MAP.containsKey(pluginId)){
                throw new PluginBeanFactoryException("The plugin " + pluginId + " has been registered");
            }
            PluginSpringBean pluginSpringBean = new PluginSpringBean();
            Set controllerComponentNames = resolveComponent(applicationContext, beanDefinitionNames, pluginSpringBean);
            resolveController(pluginSpringBean, controllerComponentNames);
            SPRING_BEAN_MAP.put(pluginId, pluginSpringBean);
        } finally {
            LOCK.unlock();
        }
    }

    /**
     * 解决 @Component 组件
     * @param pluginApplicationContext 插件上下文
     * @param beanDefinitionNames bean 定义的名称
     * @param pluginSpringBean 插件中要注册到spring中的bean
     * @return 返回注册的组件名称
     * @throws PluginBeanFactoryException 插件bean工厂异常
     */
    private Set resolveComponent(AnnotationConfigApplicationContext pluginApplicationContext,
                                         String[] beanDefinitionNames,
                                         PluginSpringBean pluginSpringBean) throws PluginBeanFactoryException {
        Set controllerComponentNames = new HashSet<>();
        // 对插件的applicationContext刷新
        // 先向spring注入插件中Component
        for (String beanDefinitionName : beanDefinitionNames) {
            if(ignoreBeanNames(beanDefinitionName)){
                continue;
            }
            Object bean = pluginApplicationContext.getBean(beanDefinitionName);

            Class aClass = bean.getClass();
            registryBeforePostBeanProcess(bean, pluginApplicationContext);
            String beanName = componentBeanRegistry.registry(bean);
            if(StringUtils.isEmpty(beanName)){
                continue;
            }
            pluginSpringBean.addComponentBeanName(beanName);
            if (aClass.getAnnotation(RestController.class) != null ||
                    aClass.getAnnotation(Controller.class) != null) {
                // 如果存在RestController 或者 Controller 注解, 说明该组件是Controller组件。
                controllerComponentNames.add(beanName);
            }
        }
        return controllerComponentNames;
    }


    /**
     * 刷新之前。此处用于扩展
     * @param pluginId 插件id
     * @param applicationContext 上下文
     * @throws PluginBeanFactoryException 插件bean工厂异常
     */
    protected void refreshBefore(String pluginId, AnnotationConfigApplicationContext applicationContext)
            throws PluginBeanFactoryException {
        // 在此处扩展新增对插件中bean的处理
        pluginPostBeanProcess.sort(Comparator.comparing(PluginPostBeanProcess::order,
                Comparator.nullsLast(Comparator.naturalOrder())));
    }

    /**
     * 向主容器注册之前的操作
     * @param pluginId 插件id
     * @param applicationContext 主程序上下文
     * @throws PluginBeanFactoryException 插件bean工厂异常
     */
    protected void registryBefore(String pluginId, AnnotationConfigApplicationContext applicationContext)
            throws PluginBeanFactoryException{
        // 什么事也不做。
    }

    /**
     * 扩展点: 向主容器注册之前处理 插件中的bean。
     * @param bean bean实例对象
     * @param pluginApplicationContext 插件的 applicationContext
     * @throws PluginBeanFactoryException 插件bean工厂异常
     */
    protected void registryBeforePostBeanProcess(Object bean,
                                                 AnnotationConfigApplicationContext pluginApplicationContext)
            throws PluginBeanFactoryException{
        for (PluginPostBeanProcess postBeanProcess : pluginPostBeanProcess) {
            if(postBeanProcess == null){
                continue;
            }
            postBeanProcess.process(bean, pluginApplicationContext);
        }
    }


    /**
     * 注册 @Controller
     * @param pluginSpringBean  插件中要注册到spring中的bean
     * @param controllerComponentNames controller 组件名称
     * @throws PluginBeanFactoryException 插件bean工厂异常
     */
    private void resolveController(PluginSpringBean pluginSpringBean,
                                   Set controllerComponentNames) throws PluginBeanFactoryException {
        for (String controllerComponentName : controllerComponentNames) {
            // 从spring容器中获取到controller实例
            Object controllerComponent = mainApplicationContext.getBean(controllerComponentName);
            if(controllerComponent == null){
                continue;
            }
            Set requestMappingInfos = pluginControllerBeanRegistry.registry(
                    controllerComponent);
            if(requestMappingInfos == null){
                continue;
            }
            for (RequestMappingInfo requestMappingInfo : requestMappingInfos) {
                pluginSpringBean.addRequestMappingInfo(requestMappingInfo);
            }
        }
    }



    @Override
    public void unRegistry(String pluginId) throws PluginBeanFactoryException {
        PluginSpringBean pluginSpringBean = SPRING_BEAN_MAP.get(pluginId);
        if(pluginSpringBean == null){
            log.warn("unRegistry->Not found plugin id : {}", pluginId);
            return;
        }
        LOCK.lock();
        try {
            Set componentBeanNames = pluginSpringBean.getComponentBeanNames();
            for (String componentBeanName : componentBeanNames) {
                componentBeanRegistry.unRegistry(componentBeanName);
            }
            Set requestMappingInfos = pluginSpringBean.getRequestMappingInfos();
            pluginControllerBeanRegistry.unRegistry(requestMappingInfos);
            SPRING_BEAN_MAP.remove(pluginId);
            notifyUnRegistry(pluginId);
        } finally {
            LOCK.unlock();
        }
    }

    @Override
    public Class supportApplicationContextClass() {
        return AnnotationConfigApplicationContext.class;
    }

    /**
     * 要忽略的bean名称
     * @param beanName bean名称
     * @return 是否忽略
     */
    private Boolean ignoreBeanNames(String beanName){
        if(StringUtils.isEmpty(beanName)){
            return true;
        }
        switch (beanName){
            case "org.springframework.context.annotation.internalConfigurationAnnotationProcessor":
                return true;
            case "org.springframework.context.annotation.internalAutowiredAnnotationProcessor":
                return true;
            case "org.springframework.context.annotation.internalRequiredAnnotationProcessor":
                return true;
            case "org.springframework.context.annotation.internalCommonAnnotationProcessor":
                return true;
            case "org.springframework.context.event.internalEventListenerProcessor":
                return true;
            case "org.springframework.context.event.internalEventListenerFactory":
                return true;
            default:
                return false;
        }
    }

    /**
     * 插件bean定义
     */
    private class PluginSpringBean {
        private Set componentBeanNames = new HashSet<>();
        private Set requestMappingInfos = new HashSet<>();

        public void addComponentBeanName(String componentBeanName){
            if(componentBeanName == null || "".equals(componentBeanName)){
                log.error("addComponentBeanName->componentBeanName can not empty!");
                return;
            }
            componentBeanNames.add(componentBeanName);
        }

        public void addRequestMappingInfo(RequestMappingInfo requestMappingInfo){
            if(requestMappingInfo == null){
                log.error("addRequestMappingInfo->requestMappingInfo can not null!");
                return;
            }
            requestMappingInfos.add(requestMappingInfo);
        }

        public Set getComponentBeanNames() {
            return componentBeanNames;
        }

        public Set getRequestMappingInfos() {
            return requestMappingInfos;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy