相关文章推荐
害羞的鸵鸟  ·  雪中悍刀行,男频行不行?-虎嗅网·  8 月前    · 
冷冷的移动电源  ·  浙江众合科技股份有限公司关于沈阳地铁6号线一 ...·  1 年前    · 
逼格高的作业本  ·  《当个妖孽这么难》-漫画全集在线阅读-爱奇艺叭嗒·  1 年前    · 
睡不着的卡布奇诺  ·  可以越野的纯电动SUV——东风EV纳米BOX ...·  1 年前    · 
害羞的帽子  ·  全新东风本田英仕派ePHEV实车,配插电式混 ...·  2 年前    · 
Code  ›  类加载器之URLClassLoader开发者社区
url lib urlclassloader
https://cloud.tencent.com/developer/article/1674553
叛逆的领结
1 年前
作者头像
每天学Java
0 篇文章

类加载器之URLClassLoader

前往专栏
腾讯云
开发者社区
文档 意见反馈 控制台
首页
学习
活动
专区
工具
TVP
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP
返回腾讯云官网
社区首页 > 专栏 > 每天学Java > 正文

类加载器之URLClassLoader

发布 于 2020-08-05 16:39:36
4.4K 0
举报

在前面关于 类加载子系统 的文章中,我们提到启动类加载器是其他类加载器的parent,其本身parent为null、扩展类加载器的parent是启动类加载器、应用类加载器的parent是扩展类加载器,但是在那篇文章中并没有强调 parent代表的含义是一个“委派”体系,而并不是继承关系 。

在类加载器的体系中,真实的继承关系如下:

通过源码我们可以发现AppClassLoader和ExtClassLoader都是Launcher的静态内部类,继承自URLClassLoader。

那么URLClassLoader和SecureClassLoader具体是做什么的呢?

  • SecureClassLoader:扩展了ClassLoader,并为定义具有相关代码源和权限的类提供了额外支持,这些代码源和权限默认情况下由系统策略检索。
  • URLClassLoader:继承自SecureClassLoader,支持从jar文件和文件夹中获取class,继承于classload,加载时首先去classload里判断是否由启动类加载器加载过。

今天这篇文章我们重点要说的就是URLClassLoader,在上面类加载器的真实继承关系图中,我们知道URLClassLoader扩展了ClassLoader,所以它在ClassLoader的基础上扩展了一些功能,这些扩展的功能中,最主要的一点就是URLClassLoader却可以加载任意路径下的类(ClassLoader只能加载classpath下面的类)。

如果你未接触URLClassLoader,那么要实现动态加载类都是使用用Class.forName()这个方法,但是 这个方法只能创建程序中已经引用的类,如果我们需要动态加载程序外的类,Class.forName()是不够的 ,这个时候就是需要使用URLClassLoader的时候。

在我的个人项目中,对于URLClassLoader是有实际使用过的,这里以我的项目作为案例,来看一下URLClassLoader的使用。

背景: 在我的个人网站和 小程序 接口开发的最开始阶段,是使用Spring Boot来开发的,这种方式搭建接口十分便捷,但是在后面不断学习的过程中,我萌发了自己实现一个类似Tomcat的小应用,然后模拟Spring实现自己的一套开发规范。这套个人项目首先是一个Maven项目,以Netty为基础实现Http协议,然后参考Spring实现DI和AOP,以及一系列的注解实现接口的开发,下面大概展示一些目录结构:

那么这个应用和URLClassLoader有什么关系呢?

首先一个普通Maven项目在打包成jar的时候,jar包内部本身是不包含依赖的,我们可以通过Maven-assembly-plugin插件将程序和它本身所依赖的jar包一起打到一个包里,但是这种方式每次打包后,jar都会比较大,所以最终采用依赖和项目代码进行分离的方案,将依赖jar放入lib文件下。

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <!--target/lib是依赖jar包的输出目录,根据自己喜好配置-->
                            <outputDirectory>target/lib</outputDirectory>
                            <excludeTransitive>false</excludeTransitive>
                            <stripVersion>false</stripVersion>
                            <includeScope>runtime</includeScope>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

当程序代码和依赖代码分离之后,如何部署到 服务器 成为了一个问题,最开始我想的是将其打包为一个可执行的jar,以类似SpringBoot的方式去部署,但是思考之后我更倾向于能有一个统一的部署方案,对于后续新的应用也可以部署,于是就想到了URLClassLoader: 将项目jar和lib下的依赖jar放入URLClassLoader类的urls (存储加载的classes和resources)中,然后 通过JarFile对项目jar进行遍历,找到程序的入口Main,然后使用URLClassLoader对类进行加载,最终启动它 。这里的jar和lib路径是使用参数进行传递(这里为了直观所以写死),然后将程序编译为可执行的命令(参考 模拟javac命令 文章),后续就可以进行统一部署发布了

   public static void main(String[] args) throws Exception {
        String jar = "/jerry/target/jerry-1.0-SNAPSHOT.jar";
        String lib = "/jerry/target/lib";
        JarFile jarFile = new JarFile(new File(jar));
        Enumeration<JarEntry> entry = jarFile.entries();
        //Lib文件+项目Jar
        URL url = new URL("file:" + jar);
        File file_directory = new File(lib);
        URL[] urls = new URL[file_directory.listFiles().length + 1];
        int i = 0;
        urls[i++] = url;
        for (File file : file_directory.listFiles()) {
            urls[i++] = new URL("file:" + file.getAbsolutePath());
        ClassLoader loader = new URLClassLoader(urls);
        Class<?> c = null;
        Object o = null;
        while (entry.hasMoreElements()) {
            JarEntry jarEntry = entry.nextElement();
            String name = jarEntry.getName();
            System.out.println(name);
            if (name != null && name.endsWith(".class")) {
                if (name.equals("Main.class")) {
                    c = loader.loadClass(name.substring(0, name.length() - 6));
                    o = c.newInstance();
        if (o != null) {
 
推荐文章
害羞的鸵鸟  ·  雪中悍刀行,男频行不行?-虎嗅网
8 月前
冷冷的移动电源  ·  浙江众合科技股份有限公司关于沈阳地铁6号线一期工程信号系统集成采购中标的公告|浙江省_新浪财经_新浪网
1 年前
逼格高的作业本  ·  《当个妖孽这么难》-漫画全集在线阅读-爱奇艺叭嗒
1 年前
睡不着的卡布奇诺  ·  可以越野的纯电动SUV——东风EV纳米BOX为何成为“6万级唯一”?_汽车产业互联
1 年前
害羞的帽子  ·  全新东风本田英仕派ePHEV实车,配插电式混动系统,轴距超2.8米
2 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号