spring bean 动态添加

1.场景:服务运行期间,上传jar,并根据jar中的bean-context.xml动态添加spring bean


bean-context.xml:



	

2.步骤:

  a.自定义继承URLClassLoader的类加载jar,

HotUrlClassLoader:

public class HotUrlClassLoader extends URLClassLoader {
    private JarURLConnection cachedJarFile;
    public HotUrlClassLoader() {
        super(new URL[]{},findParentClassLoader());
    }

    /**
     * 将指定的文件url添加到类加载器的classpath中去,并缓存jar connection,方便以后卸载jar
     * 一个可想类加载器的classpath中添加的文件url
     * @return
     */
 public void addURLFile(URL file){
     try { // 打开并缓存文件url连接
          URLConnection uc = file.openConnection();
          if (uc instanceof JarURLConnection)
          { uc.setUseCaches(true);
          ((JarURLConnection) uc).getManifest();
          cachedJarFile = (JarURLConnection)uc; }
     } catch (Exception e)
     {
         System.err.println("Failed to cache plugin JAR file: " + file.toExternalForm());
     }
     addURL(file);

 }
    public void unloadJarFile(String url){
        JarURLConnection jarURLConnection = cachedJarFile;
        if(jarURLConnection==null){
            return;
        } try {
            System.err.println("Unloading plugin JAR file " + jarURLConnection.getJarFile().getName());
            jarURLConnection.getJarFile().close();
            jarURLConnection=null;
        } catch (Exception e) {
            System.err.println("Failed to unload JAR file\n"+e);
        }
    }
    public static ClassLoader findParentClassLoader(){

//        ClassLoader parent=HotUrlClassLoader.class.getClassLoader();
        ClassLoader parent=ClassLoader.getSystemClassLoader();
        if(parent==null){
            parent=HotUrlClassLoader.class.getClassLoader();
        }
        if(parent==null){
            parent=ClassLoader.getSystemClassLoader();
        }
        return parent;
    }
}

b.使用HotLoader加载指定目录jar

 

public class HotLoader  {
//    @Resource
//    private SystemConfig systemConfig;
    private Logger logger=LoggerFactory.getLogger(HotLoader.class);
    private final static String JAR_HEADER="jar:file:";
    private final static String JAR_END="!/";
    private  final  static ConcurrentHashMap LOADER_CACHE = new ConcurrentHashMap<>();;
    public HotUrlClassLoader loadJar(String jarName,ApplicationContext applicationContext){
        HotUrlClassLoader classLoader=LOADER_CACHE.get(jarName);

        if (classLoader!=null){
            return classLoader;
        }
//        jarName="test.jar";
        classLoader=new HotUrlClassLoader();
        StringBuilder path =new StringBuilder();
        path.append(JAR_HEADER);
        path.append(File.separator);
        path.append("E:error");
        path.append(File.separator);
        path.append(jarName);
        path.append(JAR_END);
        try {
            URL jarURl=new URL(path.toString());
            classLoader.addURLFile(jarURl);
            LOADER_CACHE.put(jarName,classLoader);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return classLoader;
    }
    public Class loadClass(String jarName,String name) throws ClassNotFoundException {
        ClassLoader urlClassLoader =HotUrlClassLoader.findParentClassLoader();
        Class c= null;
        try {
            c = urlClassLoader.loadClass(name);
            if(Objects.nonNull(c)){
                return c;
            }
        } catch (ClassNotFoundException e) {
            logger.info("parent classLoader not found "+name);
            urlClassLoader= LOADER_CACHE.get(jarName);
        }

      return urlClassLoader.loadClass(name);
    }

    public void unloadJarFile(String jarName) throws MalformedURLException {
        HotUrlClassLoader urlClassLoader = LOADER_CACHE.get(jarName);
//        urlClassLoader.
        if(urlClassLoader==null){ return; } //        String path = systemConfig.getExternalClassPath();
         String path = "E:/testspace/externalClassPath";
        String jarStr = "jar:file:/"+path+"/"+jarName+"!/";
        urlClassLoader.unloadJarFile(jarStr);
        urlClassLoader = null;
        LOADER_CACHE.remove(jarName);
    }

c.加载初始化jar中bean,并将bean,放到spring主上下文中

public String loadJar(String jarName) throws Exception
    {
        HotLoader classLoader = new HotLoader();
        try {
            HotUrlClassLoader jarLoader=classLoader.loadJar("creatoo-demo-1.0-SNAPSHOT.jar");
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
            context.setClassLoader(jarLoader);
            context.setConfigLocation("/bean-context.xml");
            context.refresh();
            ConfigurableListableBeanFactory contextBeanFactory=context.getBeanFactory();
            DefaultListableBeanFactory capableBeanFactory=(DefaultListableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
            Iterator iter = contextBeanFactory.getBeanNamesIterator();
            while (iter.hasNext()){
                String beanName=iter.next().toString();
                if(contextBeanFactory.containsBeanDefinition(beanName)&&!capableBeanFactory.containsSingleton(beanName)){
                    capableBeanFactory.registerSingleton(beanName,contextBeanFactory.getBean(beanName));
                    logger.info(beanName);
                }
            }
        }catch (Exception e){
            logger.error("jar加载失败",e);
            throw new RuleServerException("jar加载失败");
        }
        return ResponseUtil.returnSuc("jar加载成功").toString();
    }

 

你可能感兴趣的:(spring,spring,bean,动态加载)