动态扩展Rest接口地址,动态卸载Rest接口

7 篇文章 0 订阅
4 篇文章 0 订阅

动态扩展Rest接口地址,动态卸载Rest接口

在这里插入图片描述

import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import sun.misc.ClassLoaderUtil;

import java.io.File;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * 加载后台插件,热发布
 *
 * @author caigaoqing
 */
@Service
public class LoadPluginServiceImpl  {

    @Autowired
    private GenericApplicationContext annotationConfigWebApplicationContext;

    @Autowired
    ApplicationContext context;

    /**
     * 注册插件,注册bean,注册springmvc的 bean
     *
     * @param url      上传oss的地址
     * @param scanPath 扫描路径
     * @return 注册成功的beans
     */
    public List<String> register(String url, String scanPath) {
        //注册的 Bean
        List<String> beans = new ArrayList<>();
        try {
            URL[] urls = scanUrl(url);
            //新建classloader 核心
            URLClassLoader urlClassLoader = new URLClassLoader(urls, annotationConfigWebApplicationContext.getClassLoader());

            //  获取导入的jar的controller  service  dao 等类,并且创建BeanDefinition
            Set<BeanDefinition> beanDefinitions = getBeanDefinitions(urlClassLoader, scanPath);
            beanDefinitions.forEach(item -> {
                registerBean(beans, urlClassLoader, item);
                //根据beanDefinition通过BeanFactory注册bean
                annotationConfigWebApplicationContext.getDefaultListableBeanFactory().registerBeanDefinition(item.getBeanClassName(), item);
            });

            //修改BeanFactory的ClassLoader
            annotationConfigWebApplicationContext.getDefaultListableBeanFactory().setBeanClassLoader(urlClassLoader);
            //获取requestMappingHandlerMapping,用来注册HandlerMapping
            RequestMappingHandlerMapping requestMappingHandlerMapping = annotationConfigWebApplicationContext.getBean(RequestMappingHandlerMapping.class);
            beanDefinitions.forEach(item -> {
                registerController(beans, urlClassLoader, requestMappingHandlerMapping, item);
            });
            urlClassLoader.close();
            ClassLoaderUtil.releaseLoader(urlClassLoader);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return beans;
    }


    /**
     * 卸载插件,卸载bean,卸载springmvc的 bean
     *
     * @param url      上传oss的地址
     * @param scanPath 扫描路径
     * @return 卸载成功的beans
     */
    public List<String> unregisterBean(String url, String scanPath) {
        List<String> beanList = new ArrayList<>();
        try {
            URL[] urls = scanUrl(url);
            //新建classloader 核心
            URLClassLoader urlClassLoader = new URLClassLoader(urls, annotationConfigWebApplicationContext.getClassLoader());

            //  获取导入的jar的controller  service  dao 等类,并且创建BeanDefinition
            Set<BeanDefinition> beanDefinitions = getBeanDefinitions(urlClassLoader, scanPath);
            beanDefinitions.forEach(item -> {
                //根据beanDefinition通过BeanFactory注册bean
                annotationConfigWebApplicationContext.getDefaultListableBeanFactory().removeBeanDefinition(item.getBeanClassName());
            });
            //修改BeanFactory的ClassLoader
            annotationConfigWebApplicationContext.getDefaultListableBeanFactory().setBeanClassLoader(urlClassLoader);
            //获取requestMappingHandlerMapping,用来注册HandlerMapping
            RequestMappingHandlerMapping requestMappingHandlerMapping = annotationConfigWebApplicationContext.getBean(RequestMappingHandlerMapping.class);
            beanDefinitions.forEach(item -> {
                unRegisterController(beanList, urlClassLoader, requestMappingHandlerMapping, item);
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        return beanList;
    }

    /**
     * 注册 接口
     *
     * @param beans                        统计加载的Bean列表
     * @param urlClassLoader               url类加载器
     * @param requestMappingHandlerMapping requestMapping映射
     * @param item                         Bean定义
     */
    private void registerController(List<String> beans, URLClassLoader urlClassLoader, RequestMappingHandlerMapping requestMappingHandlerMapping, BeanDefinition item) {
        String classname = item.getBeanClassName();
        beans.add(classname);
        try {
            Class<?> c = Class.forName(classname, false, urlClassLoader);
            Controller controllerAnnotation = c.getAnnotation(Controller.class);
            RestController restControllerAnnotation = c.getAnnotation(RestController.class);
            //获取该bean 真正的创建
            Object proxy = annotationConfigWebApplicationContext.getBean(item.getBeanClassName());
            //如果此bean是Controller,则注册到RequestMappingHandlerMapping里面
            if (controllerAnnotation != null || restControllerAnnotation != null) {

                Method getMappingForMethod = ReflectionUtils.findMethod(RequestMappingHandlerMapping.class, "getMappingForMethod", Method.class, Class.class);
                getMappingForMethod.setAccessible(true);
                try {
                    Method[] methodArr = c.getMethods();
                    for (Method md : methodArr) {
                        AnnotatedType annotatedReturnType = md.getAnnotatedReturnType();
                        annotatedReturnType.getType();
                        RequestMapping aliasAnnotation = AnnotationUtils.findAnnotation(md, RequestMapping.class);
                        if (aliasAnnotation != null) {
                            //创建RequestMappingInfo
                            RequestMappingInfo mappingInfo = (RequestMappingInfo) getMappingForMethod.invoke(requestMappingHandlerMapping, md, c);
                            //注册
                            requestMappingHandlerMapping.registerMapping(mappingInfo, proxy, md);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 注册Bean
     *
     * @param list           列表
     * @param urlClassLoader url类加载器
     * @param item           bean定义
     */
    private void registerBean(List<String> list, URLClassLoader urlClassLoader, BeanDefinition item) {
        try {
            Class<?> c = Class.forName(item.getBeanClassName(), false, urlClassLoader);
            //处理@service指定beanName的注册别名
            if (c.getAnnotation(Service.class) != null) {
                String beanName = c.getAnnotation(Service.class).value();
                list.add("AliasBean>>" + beanName);
                annotationConfigWebApplicationContext.getDefaultListableBeanFactory().registerAlias(item.getBeanClassName(), beanName);
            }
            //处理接口注册别名
            if (c.getInterfaces().length > 0) {
                AnnotatedType[] annotatedInterfaces = c.getAnnotatedInterfaces();
                for (int i = 0; i < annotatedInterfaces.length; i++) {
                    Type type = annotatedInterfaces[i].getType();
                    String typeName = type.getTypeName();
                    list.add("AliasBean>>" + typeName);
                    annotationConfigWebApplicationContext.getDefaultListableBeanFactory().registerAlias(item.getBeanClassName(), typeName);
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    /**
     * 统计
     *
     * @param beanList                     bean列表
     * @param urlClassLoader               url类装入器
     * @param requestMappingHandlerMapping 请求映射处理程序映射
     * @param item                         项
     */
    private void unRegisterController(List<String> beanList, URLClassLoader urlClassLoader, RequestMappingHandlerMapping requestMappingHandlerMapping, BeanDefinition item) {
        String classname = item.getBeanClassName();
        beanList.add(classname);
        try {
            Class<?> c = Class.forName(classname, false, urlClassLoader);
            Controller controllerAnnotation = c.getAnnotation(Controller.class);
            RestController restControllerAnnotation = c.getAnnotation(RestController.class);
            //获取该bean 真正的创建
            //如果此bean是Controller,则注册到RequestMappingHandlerMapping里面
            if (controllerAnnotation != null || restControllerAnnotation != null) {

                Method getMappingForMethod = ReflectionUtils.findMethod(RequestMappingHandlerMapping.class, "getMappingForMethod", Method.class, Class.class);
                getMappingForMethod.setAccessible(true);
                try {
                    Method[] methodArr = c.getMethods();
                    for (Method md : methodArr) {
                        AnnotatedType annotatedReturnType = md.getAnnotatedReturnType();
                        annotatedReturnType.getType();
                        RequestMapping aliasAnnotation = AnnotationUtils.findAnnotation(md, RequestMapping.class);
                        if (aliasAnnotation != null) {
                            //创建RequestMappingInfo
                            RequestMappingInfo mappingInfo = (RequestMappingInfo) getMappingForMethod.invoke(requestMappingHandlerMapping, md, c);
                            //卸载
                            requestMappingHandlerMapping.unregisterMapping(mappingInfo);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                urlClassLoader.close();
                ClassLoaderUtil.releaseLoader(urlClassLoader);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @param url
     * @return
     * @throws MalformedURLException
     */
    public URL[] scanUrl(String url) throws MalformedURLException {
        File file = new File(FilenameUtils.getName(url));
        //查找依赖的jar包,同级目录下的lib/
        List<URL> dependencyJar = findDependencyJar(file);

        URL[] urls = dependencyJar.toArray(new URL[dependencyJar.size()]);
        return urls;
    }


    /**
     * 查看jar中类
     *
     * @param file 文件
     * @return 返回地址
     * @throws MalformedURLException
     */
    private static List<URL> findDependencyJar(File file) throws MalformedURLException {
        List<URL> list = new ArrayList<>();
        File parentFile = file.getParentFile();
        File libFile = new File(FilenameUtils.getName(file.getParent() + File.separator + "lib"));
        if (libFile.exists() && parentFile.isDirectory()) {
            for (File jar : libFile.listFiles()) {
                if (jar.isFile()
                        && jar.getName().toLowerCase().endsWith(".jar")
                ) {
                    list.add(jar.toURI().toURL());
                }
            }
        }
        list.add(file.toURI().toURL());
        return list;

    }


    /**
     * 加载BeanDefinition
     *
     * @param classLoader 类加载器
     * @param scanPath    扫描路径
     * @return 生成BeanDefinition
     * @throws Exception
     */
    public Set<BeanDefinition> getBeanDefinitions(ClassLoader classLoader, String scanPath) throws Exception {
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(classLoader);
        Resource[] resources = resourcePatternResolver.getResources("classpath*:" + scanPath + "/*.**");

        MetadataReaderFactory metadata = new SimpleMetadataReaderFactory();
        for (Resource resource : resources) {
            MetadataReader metadataReader = metadata.getMetadataReader(resource);
            ScannedGenericBeanDefinition beanDefinition = new ScannedGenericBeanDefinition(metadataReader);
            String classname = beanDefinition.getBeanClassName();
            Class<?> aClass = Class.forName(classname, false, classLoader);
            if (aClass.isInterface()) {
                continue;
            }
            beanDefinition.setResource(resource);
            beanDefinition.setSource(resource);
            candidates.add(beanDefinition);
        }
        return candidates;
    }


}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值