• (转)自定义ClassLoader ----可以加载第三方jar包


     package com.classloader.util;
    
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLClassLoader;
    import java.net.URLStreamHandlerFactory;
    import java.security.CodeSource;
    import java.security.PermissionCollection;
    import java.util.Enumeration;
    import java.util.jar.Manifest;
    
    public class NetworkClassLoader extends URLClassLoader {
    
        String baseUrl;
    
        public String getBaseUrl() {
            return baseUrl;
        }
    
        public void setBaseUrl(String baseUrl) {
            this.baseUrl = baseUrl;
        }
    
        public NetworkClassLoader(){
            this(new URL[]{});
        }
    
        /**
         * URL 以'/'结尾的为目录
         *     否则为jar包
         *     未指定其父类加载器为系统类加载器
         * @param urls
         */
        public NetworkClassLoader(URL[] urls) {
            super(urls);
        }
    
        /**
         * 同上,指定classLoader
         * @param urls
         * @param parent
         */
        public NetworkClassLoader(URL[] urls, ClassLoader parent) {
            super(urls,parent);
        }
    
        /**
         * 同上,URL工厂处理器
         * @param urls
         * @param parent
         * @param factory
         */
        public NetworkClassLoader(URL[] urls, ClassLoader parent,
                  URLStreamHandlerFactory factory) {
             super(urls,parent,factory);
        }
    
        /**
         * [添加baseUrl]
         * @param url
         */
        public void addURL(String url){
            URL uurl=null;
            try {
                uurl = new URL(baseUrl+url);
            } catch (MalformedURLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            addURL(uurl);
        }
    
        /**
         * 添加url[添加baseUrl]
         */
        protected void addURL(URL url) {
            super.addURL(url);
        }
    
        /**
         * 返回urls
         */
        public URL[] getURLs() {
            return super.getURLs();
        }
    
        /**
         * 查找类对象
         *   从以上的URLS中查找加载当前类对象[会打开所有的jars去查找指定的类]
         *   (可以通过调用findClass来得到以上URL加载包中的类)
         */
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            return super.findClass(name);
        }
    
        /**
         * defineClass SecureClassLoader定义为最终方法,不允许更改.
         * 在使用这个类对象前,必须先resolved(解析)
         */
    
    
        /**
         * 查找资源[自定义相对URL查找路径]
         *   从以上的URLS中查找当前名称的资源
         * 这个必须重写,因为是public 哈哈
         */
        public URL findResource(String name) {
            URL url = null;
            try {
                url = new URL(baseUrl+name);
            } catch (MalformedURLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return url;
        }
    
        /**
         * 查找资源列表[URL查找路径]
         */
        public Enumeration<URL> findResources(String name) throws IOException {
            return super.findResources(name);
        }
    
        /**
         * 在当前的ClassLoader中,定义一个新的Package,Package的属性由Manifest指定.这个包的源文件
         */
        protected Package definePackage(String name, Manifest man, URL url)
                throws IllegalArgumentException {
            return super.definePackage(name, man, url);
        }
    
        /**
         * 加载路径权限
         */
        protected PermissionCollection getPermissions(CodeSource codesource) {
            return super.getPermissions(codesource);
        }
    }

    以下是用法: 

        NetworkClassLoader loader = new NetworkClassLoader();
        loader.setBaseUrl("file:///F:\框架\maven\app\jms\src\main\webapp\modules\");
    
        loader.addURL("App/lib/test.jar");
        loader.addURL("App/lib/test1.jar");
        loader.addURL("App/template/view.vm");
        loader.addURL("App/config.xml");

    这里初始化了此类加载器所使用的类资源,配置文件等。
    以下是如何加载类资源: 

    Class clazz= loader.findClass("com.jvm.look.A");//加载类

    以下是加载配置文件资源 

    URL uuu = loader.findResource("App/config.xml");

    有一点需要注意的,这个类加载器还是双亲委托机制,比如有一个类"com.annotation.table.Test"在父类加载器中如果已经加载过了,那么如果这个类在test.jar中存在,那么不会重新定义加载,而使用父类加载器加载的类,有人问了,那我如何覆盖父类加载器中定义的类。
    可以进行如下操作: 

    Class clazz2= loader.findClass("com.annotation.table.Test");

    重新加载类,类的加载序列我在上一篇已经讲过了,不熟悉的可以看以上文章.
    可能有人会问了,如果每一个类都这样,那我不崩溃了,我需要把我加载的jar覆盖父类加载器中定义的所有类. 

        /**
         * 覆盖父加载器中定义的类,使用当前类加载器加载资源,那么所有的类都在此加载器中执行.
         * 这样,所有URL中的类都通过此类加载器加载,也就是说URL中的类的定义类加载器就是当前类加载器.
         * 建议:尽量不要使用这种方式覆盖父加载器定义的类.[按一种约定双亲委托机制加载]
         * (如果重载了,那么尽量使用此loader加载类,这样所有逻辑都在此ClassLoader中运行,当然还有SDK还是从双亲加载)
         * 可以在SDK中定义接口,在此JAR里面提供实现.
         */
        public void initAllJar(){
            URL[] urls = this.getURLs();
    
            for(URL urll:urls){
                String url = urll.getFile();
                //重新定义这个架包中的所有类.
                if(url.endsWith("jar")){
                    File jarFile  = getJarFile(url);
                    JarFile jarFileTemp = null;
                    try {
                        jarFileTemp = new JarFile(jarFile);
                        Enumeration<JarEntry> en = jarFileTemp.entries();
                        while (en.hasMoreElements()) {
                            JarEntry je = en.nextElement();
                            String name = je.getName();
                            if (name.endsWith(CLASS_FILE)) {
                                String className = name.substring(0, name.length()
                                        - CLASS_FILE.length());
                                findClass(pathToDot(className));
                            }
                        }
    
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (ClassNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
    
    /**
         * 转jar包路径和jar文件名为具体文件.
         *
         * @param root
         * @param jar
         * @return
         */
        private File getJarFile(String file) {
            if (file.startsWith(PREFIX_FILE))
                file = file.substring(PREFIX_FILE.length());
            int end = file.indexOf(JAR_URL_SEPERATOR);
            if (end != (-1))
                file = file.substring(0, end);
            return new File(file);
        }
    
       /**
         * 转路径为包名[/ ==> .]/[\ ==> .]
         * @param s
         * @return
         */
        private String pathToDot(String s) {
            return s.replace('/', '.').replace('\', '.');
        }

    其实JDK中已经提供了好几个ClassLoader,大家可以扩展,比如项目中有两个架包版本,结构全部都一样,但是两个架包都必须运行。这时自定义类加载器就有用了。

    转:http://a123159521.iteye.com/blog/1095264

  • 相关阅读:
    构建之法阅读笔记03
    12.16第三周总结
    构建之法阅读笔记02
    12.9第二周周总结
    四则运算2
    构建之法阅读笔记01
    12.2第一周总结
    课堂练习-增加信息
    软件工程00
    web自动化测试---web页面元素的定位
  • 原文地址:https://www.cnblogs.com/wangle1001986/p/3838330.html
Copyright © 2020-2023  润新知