1. 程式人生 > >Spring boot 動態載入和部署匯入的spring程式

Spring boot 動態載入和部署匯入的spring程式

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.PropertiesLoaderUtils;
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.Component;
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.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;

@Service
public class LoadService  {

    @Autowired
    private AnnotationConfigEmbeddedWebApplicationContext annotationConfigEmbeddedWebApplicationContext;
   
    public void register(File file) {
        try {
            file = new File("D:\\test1.1.0.jar");
			//查詢依賴的jar包,同級目錄下的lib/
            List<URL> dependencyJar = findDependencyJar(file);


            URL[] urls = dependencyJar.toArray(new URL[dependencyJar.size()]);
			//新建classloader 核心
            URLClassLoader urlClassLoader = new URLClassLoader(urls, annotationConfigEmbeddedWebApplicationContext.getClassLoader());

			//獲取匯入的jar的controller  service  dao 等類,並且建立BeanDefinition
            Set<BeanDefinition> beanDefinitions = getBeanDefinitions(urlClassLoader);
            
            beanDefinitions.forEach(item -> {
				//根據beanDefinition通過BeanFactory註冊bean
                 annotationConfigEmbeddedWebApplicationContext.getDefaultListableBeanFactory().registerBeanDefinition(item.getBeanClassName(), item);
            });
			
			//修改BeanFactory的ClassLoader
            annotationConfigEmbeddedWebApplicationContext.getDefaultListableBeanFactory().setBeanClassLoader(urlClassLoader);
			//獲取requestMappingHandlerMapping,用來註冊HandlerMapping
			RequestMappingHandlerMapping requestMappingHandlerMapping=annotationConfigEmbeddedWebApplicationContext.getBean(RequestMappingHandlerMapping.class);
            beanDefinitions.forEach(item -> {
				
                String classname = item.getBeanClassName();
                try {
                    Class<?> c = Class.forName(classname, false, urlClassLoader);
                    Controller annotation = c.getAnnotation(Controller.class);
					//獲取該bean 真正的建立
					Object proxy = annotationConfigEmbeddedWebApplicationContext.getBean(item.getBeanClassName());
					//如果此bean是Controller,則註冊到RequestMappingHandlerMapping裡面
                    if (annotation != null) {
						
                        Method getMappingForMethod = ReflectionUtils.findMethod(RequestMappingHandlerMapping.class, "getMappingForMethod", Method.class, Class.class);
                        getMappingForMethod.setAccessible(true);
                        try {
                            Method[] method_arr = c.getMethods();
                            for (Method m_d : method_arr) {
                                if (m_d.getAnnotation(RequestMapping.class) != null) {
                                    //建立RequestMappingInfo 
                                    RequestMappingInfo mapping_info = (RequestMappingInfo) getMappingForMethod.invoke(requestMappingHandlerMapping, m_d, c);
									//註冊
                                    requestMappingHandlerMapping.registerMapping(mapping_info, proxy, m_d);
                                }

                            }

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

                    }
                }catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            });

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

    }

    private static List<URL> findDependencyJar(File file) throws MalformedURLException {
        List<URL> list = new ArrayList<>();
        File parentFile = file.getParentFile();
        File libFile = new File(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;

    }


    public  Set<BeanDefinition> getBeanDefinitions(ClassLoader classLoader) throws Exception {
        Set<BeanDefinition> candidates = new LinkedHashSet<>();

        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(classLoader);
        Resource[] resources = resourcePatternResolver.getResources("classpath*:com/xxx/**/*.**");

        MetadataReaderFactory metadata=new SimpleMetadataReaderFactory();
        for(Resource resource:resources) {
            MetadataReader metadataReader=metadata.getMetadataReader(resource);
            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
            sbd.setResource(resource);
            sbd.setSource(resource);
            candidates.add(sbd);
        }
        for(BeanDefinition beanDefinition : candidates) {
            String classname=beanDefinition.getBeanClassName();
            Controller c=Class.forName(classname,false,classLoader).getAnnotation(Controller.class);
            Service s=Class.forName(classname,false,classLoader).getAnnotation(Service.class);
            Component component=Class.forName(classname,false,classLoader).getAnnotation(Component.class);
            if(c!=null ||s!=null ||component!=null)
                System.out.println(classname);
        }

        return candidates;
    }

}