1、ClassLoader.getResourceAsStream() 与Class.getResourceAsStream()的区别

本文详细解析了Java中ClassLoader的工作原理,包括getResourceAsStream方法的区别、三种标准类加载器的作用及加载顺序,以及如何通过自定义ClassLoader来加载特定的类资源。此外还介绍了Class和Thread类中getClassLoader和getContextClassLoader方法的不同应用场景。
例如你写了一个MyTest类在包com.test.mycode 下,那么MyTest.class.getResourceAsStream("name") 会在com.test.mycode包下查找相应的资源。
     如果这个name是以 '/' 开头的,那么就会从classpath的根路径下开始查找。  
    ClassLoader.getResourceAsStream()  无论要查找的资源前面是否带'/' 都会从classpath的根路径下查找。
    所以: MyTest.getClassLoader().getResourceAsStream("name") 和 
            MyTest.getClassLoader().getResourceAsStream("name") 的效果是一样的。
 
2、一共有三种加载器
bootstrap classloader :负责加载JAVA核心类( jre 下lib和class目录中的内容)
extension classloader :负责加载JAVA扩展类(jre 下lib/ext 目录中的内容)
system classloader :负责加载应用指定的类 (环境变量classpath中配置的内容)
一个类的加载顺序也是按上面的排列来的,这样就能保证系统的类能先加载。 
与此同时用户也可以自己定义ClassLoader,用来加载特殊的资源。
这里就涉及到 Class.getClassLoader()  和  Thread.currentThread.getContextClassLoader()的区别。
举一个简单的例子:
   假如某天JAVA给我们提供了一个叫 StartCamera 的类用来启动电脑的标准摄像头,并将这个类打包在一个jar中。
   正常情况下,我们要启动摄像头时只需将这个jar配置到classpath中。系统启动时system classloader会将这个类加载到应用中。
   但因为摄像头的生产厂家不一样,针对新的设备会有多个不同的StartCamera实现,在应用中我们不知道实际的用户会用到哪种。于是我们就自定义了一个ClassLoader,用来针对具体的设备类型加载相应的StartCamera类。
   这样一来就出现:优先加载我们定义的类,加载不到的情况下再加载系统的。 这样的需求,是系统默认的父委托加载机制无法满足的。
 
   Thread.currentThread.getContextClassLoader() 就是这样产生的。 我们使用Thread.currentThread.setContextClassLoader() 可以为当前线程指定相应的ClassLoader,然后用get的方式来获取。
   那么上面的加载代码就可能是这样子的:  
public void useCamera(){
  StartCamera s = this.findClassLoader().loadClass("StartCamera");
 
  s.start();
}
private ClassLoader findClassLoader(){
  ClassLoader loader = Thread.currentThread().getContextClassLoader();
  if(loader==null){
     loader = ClassLoader.getSystemClassLoader();
  }
 
  return loader;
}
4、returngetFields()与getDeclaredFields()区别:getFields()只能访问类中声明为公有的字段,私有的字段它无法访问,能访问从其它类继承来的公有方法.getDeclaredFields()能访问类中所有的字段,与public,private,protect无关,不能访问从其它类继承来的方法  
* getMethods()与getDeclaredMethods()区别:getMethods()只能访问类中声明为公有的方法,私有的方法它无法访问,能访问从其它类继承来的公有方法.getDeclaredFields()能访问类中所有的字段,与public,private,protect无关,不能访问从其它类继承来的方法  
* getConstructors()与getDeclaredConstructors()区别:getConstructors()只能访问类中声明为public的构造函数.getDeclaredConstructors()能访问类中所有的构造函数,与public,private,protect无关  
 
4、ystem.exit(0)、ystem.exit(1)、
这个方法是用来结束当前正在运行中的java虚拟机
System.exit(0)是将你的整个虚拟机里的内容都停掉了 ,而dispose()只是关闭这个窗口,但是并没有停止整个application exit() 。无论如何,内存都释放了!也就是说连JVM都关闭了,内存里根本不可能还有什么东西
System.exit(0)是正常退出程序,而System.exit(1)或者说非0表示非正常退出程序
System.exit(status)不管status为何值都会退出程序。和return 相比有以下不同点:return是回到上一层,而System.exit(status)是回到最上层
 
 

转载于:https://www.cnblogs.com/weixiuli/p/6406127.html

### Java ClassLoader 使用 `getResourceAsStream` 获取资源输入流的解决方案 当使用 `ClassLoader.getResourceAsStream()` 方法尝试从 JAR 文件中加载资源时,可能会遇到无法找到指定资源的情况。这是因为打包后的文件结构发生了变化,相对路径不再适用。 以下是解决问题的具体方法以及代码示例: #### 1. **通过类加载器获取资源** 可以利用 `Class` 或 `ClassLoader` 的 `getResourceAsStream` 方法来访问嵌套在 JAR 中的资源文件。这种方式适用于 Spring Boot 打包的应用程序或其他类似的场景[^1]。 ```java // 示例:通过当前类的类加载器获取 logback.xml 资源 InputStream is = YourClassName.class.getClassLoader().getResourceAsStream("logback.xml"); if (is != null) { try { // 处理 InputStream 数据 byte[] buffer = new byte[is.available()]; is.read(buffer); String content = new String(buffer, StandardCharsets.UTF_8); System.out.println(content); } catch (IOException e) { e.printStackTrace(); } } else { System.err.println("Resource not found!"); } ``` #### 2. **动态设置 ContextClassLoader** 如果默认的上下文类加载器无法满足需求,则可以通过 `Thread.currentThread().setContextClassLoader()` 动态修改当前线程的上下文类加载器行为,从而实现对外部 JAR 的支持[^3]。 ```java // 修改当前线程的上下文类加载器 Thread.currentThread().setContextClassLoader(new URLClassLoader(new URL[]{new File("/path/to/external.jar").toURI().toURL()})); // 加载外部 JAR 中的资源 InputStream externalIs = Thread.currentThread().getContextClassLoader().getResourceAsStream("external-resource.txt"); if (externalIs != null) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(externalIs)); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } else { System.err.println("External resource not found!"); } ``` #### 3. **Spring Boot 场景下的注意事项** 在 Spring Boot 应用中,由于其内部封装了类加载机制,在某些情况下可能需要特别注意如何正确配置资源路径。例如,直接使用相对路径可能导致 `FileNotFoundException`,因为打包后的文件结构已发生变化[^4]。 推荐始终采用基于 `classpath:` 前缀的方式定义资源位置,如下所示: ```properties logging.config=classpath:logback.xml ``` 或者在代码中显式调用: ```java InputStream configStream = YourApplication.class.getClassLoader().getResourceAsStream("logback.xml"); LogManager.resetConfiguration(); // 如果使用 Logback 配置重置逻辑 JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext((LoggerContext) LoggerFactory.getILoggerFactory()); try { configurator.doConfigure(configStream); } catch (JoranException ignored) {} ``` --- ### 总结 以上提供了多种方式解决通过类加载器获取资源输入流的问题,包括标准做法、动态调整上下文类加载器的行为,以及针对 Spring Boot 特殊环境的最佳实践。这些方案能够有效应对不同场景下可能出现的资源加载失败情况。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值