InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("dbconfig.properties")的作用

本文深入探讨了Java类加载机制,解释了Java程序如何通过类加载器(ClassLoader)在Java虚拟机(JVM)中运行。详细介绍了系统默认的三个类加载器:BootStrap、ExtClassLoader和AppClassLoader的作用及组织结构,以及类加载过程中的动态性如何提高读写效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.与普通程序不同的是,Java程序(class文件)并不是本地的可执行程序。当运行Java程序时,首先运行JVM(Java虚拟机),然后再把Java class加载到JVM里头运行,负责加载Java class的这部分就叫做Class Loader。中文叫做类加载器。

Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader

类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap。

Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。
 
2.类加载指的是将类的class文件读入内存,并为之创建一个java.lang.Class对象,而系统中所有的类,它们实际上也是对象,称为类对象,它们都是java.lang.Class的实例,虚拟机为每种类型管理一个独一无二的Class对象,也就是说,每个类(型)都有一个Class对象.
 
3. java中class.forName和classLoader都可用来对类进行加载。properties一般放配置信息的,存放的是键值对格式.如userName=root 这样便于管理!
jdbcUtil.class 得到的是class JdbcUtil ,class对象是java.lang.Class<T>这个类生成的对象,每个类都有一个class对象
getResourceAsStream(),返回的是InputStream 对象,
Properties类是用来操作properties文件的
props.load(in) ,加载进来,进行一行一行的读取
类加载器属于动态的载入,可以提高读写效率.
还可以用java.util.ResourceBundle的类来读取properties文件.ResourceBundle.getBundle("文件名").getString("键");
<think>这段代码是JDBCUtils类的一部分,主要功能是初始化一个Druid连接池。代码使用静态代码块来确保连接池的初始化只执行一次。下面我将详细解释代码的执行流程。 ###代码执行流程详解```javapublicclass JDBCUtils{//静态变量,用于存储连接池对象static DataSource dataSource;//静态代码块:在类加载时执行,且只执行一次static{//1.使用字节输入流读取配置文件InputStream is= JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");Propertiesproperties =new Properties();try{//2.将流中的数据加载到Properties对象中properties.load(is);//3.根据properties中的数据,使用DruidDataSourceFactory创建连接池对象dataSource =DruidDataSourceFactory.createDataSource(properties);} catch(Exceptione){//4.如果出现异常,抛出运行时异常throw newRuntimeException(e);}} }``` ####步骤分解: 1. **类加载触发静态代码块**:-当`JDBCUtils`类第一次被使用时(例如:调用该类的静态方法或访问静态变量),JVM会加载该类。-类加载过程中,静态代码块(`static {... }`)会被执行,且仅执行一次。 2. **读取配置文件**:-`JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties")`:-使用类加载器从类路径(classpath)的根目录下获取名为`druid.properties`的配置文件的输入流(`InputStream`)。-注意:配置文件必须放在`src/main/resources`(Maven项目)或类路径能够访问的位置。 3. **加载配置文件到Properties对象**:-创建`Properties`对象,用于存储键值对配置。- `properties.load(is)`:从输入流中读取配置,将配置文件中的键值对加载到`properties`对象中。4.**创建Druid连接池**:-`DruidDataSourceFactory.createDataSource(properties)`:-使用Druid提供的工厂类,根据`properties`中的配置创建连接池对象(`DataSource`)。-配置包括:数据库URL、用户名、密码、初始连接数、最大连接数等(在`druid.properties`中定义)。5.**异常处理**:-如果在读取配置文件或创建连接池过程中发生异常(如文件不存在、配置错误等),捕获异常并抛出`RuntimeException`,导致类初始化失败。###配置文件示例(druid.properties)```properties#数据库连接配置driverClassName=com.mysql.cj.jdbc.Driverurl=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTCusername=rootpassword=123456#连接池配置initialSize=5minIdle=5maxActive=20maxWait=60000``` ###关键点说明:- **静态代码块的作用**:确保连接池初始化在类加载时完成,且只执行一次,避免重复创建连接池。- **配置文件位置**:必须位于类路径下,否则`getResourceAsStream`会返回`null`,导致`properties.load(is)`抛出`NullPointerException`。- **异常处理**:将检查异常(`Exception`)转换为非检查异常(`RuntimeException`),强制使用者处理配置错误。###使用示例在其他类中,可以通过`JDBCUtils.getConnection()`获取数据库连接(需要补充该方法):```javapublicstatic ConnectiongetConnection() throwsSQLException{return dataSource.getConnection();} ```###注意事项1.**资源关闭**:静态代码块中打开的`InputStream`没有显式关闭,但`properties.load(is)`方法内部会处理流的关闭?实际上,在`try`块结束后,使用`try-with-resources`可以自动关闭流,但这里没有使用。建议修改为:```javastatic{//使用try-with-resources确保流关闭try (InputStream is= JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties")){Properties properties= newProperties();properties.load(is);dataSource= DruidDataSourceFactory.createDataSource(properties);}catch (Exception e) {thrownew RuntimeException(e);}} ```2.**连接池单例**:该设计确保了`dataSource`是单例的,整个应用共享同一个连接池。 ###完整工具类建议通常,`JDBCUtils`还会提供关闭连接的方法,例如:```javapublicstatic voidclose(Connection conn,Statement stmt,ResultSetrs){try {if (rs !=null)rs.close(); }catch (SQLExceptione){ e.printStackTrace();}try {if (stmt !=null)stmt.close();} catch(SQLException e) {e.printStackTrace(); }try{ if(conn!= null) conn.close();} catch(SQLException e) {e.printStackTrace(); }} ```§§相关问题§§: 1.静态代码块和实例初始化块有什么区别? 2. Druid连接池的常用配置参数有哪些? 3.如何确保数据库连接在使用后正确关闭?4.除了Druid,还有哪些常见的Java数据库连接池?</think>### JDBCUtils 静态代码块执行流程详解 ```java public class JDBCUtils { static DataSource dataSource; // 静态代码块 - 类加载时自动执行 static { // 1. 使用字节输入流读取配置文件 InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"); Properties properties = new Properties(); try { // 2. 将流中的数据加载到 Properties 对象中 properties.load(is); // 3. 根据 properties 中的数据构建连接池对象 dataSource = DruidDataSourceFactory.createDataSource(properties); } catch (Exception e) { // 4. 异常处理 throw new RuntimeException(e); } } } ``` ### 执行流程详解 #### 1. **类加载阶段(触发静态代码块执行)** - 当 `JDBCUtils` 类第一次被使用时(例如调用 `JDBCUtils.getConnection()` 或访问任何静态成员) - JVM 的类加载器加载 `JDBCUtils.class` 文件 - **静态代码块自动执行**(在类初始化阶段执行,且只执行一次) #### 2. **读取配置文件** ```java InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"); ``` - **类加载器获取资源**:使用当前类的类加载器从 classpath 中获取 `druid.properties` 文件 - **资源定位**: - 在 Maven 项目中,文件通常位于 `src/main/resources/` 目录 - 在普通 Java 项目中,文件位于类路径根目录 - **返回输入流**:以 `InputStream` 形式返回配置文件内容 #### 3. **加载配置到 Properties 对象** ```java Properties properties = new Properties(); properties.load(is); ``` - **创建 Properties 对象**:用于存储键值对配置 - **加载配置**: - 从输入流读取配置内容 - 解析为键值对格式(如 `key=value`) - 存储在 `properties` 对象中 #### 4. **创建 Druid 连接池** ```java dataSource = DruidDataSourceFactory.createDataSource(properties); ``` - **工厂方法调用**:使用 Druid 提供的工厂类创建连接池 - **连接池初始化**: - 解析配置参数(数据库URL、用户名、密码等) - 根据配置创建指定数量的初始连接 - 初始化连接池管理结构 - **赋值静态变量**:将初始化好的连接池对象赋给 `dataSource` 静态变量 #### 5. **异常处理** ```java } catch (Exception e) { throw new RuntimeException(e); } ``` - **异常捕获**:捕获可能发生的所有异常(IO异常、配置解析异常等) - **异常转换**:将检查异常转换为非检查异常(RuntimeException) - **失败反馈**:如果初始化失败,后续任何使用 `JDBCUtils` 的操作都会抛出异常 ### 执行流程图解 ```mermaid graph TD A[类首次使用] --> B[加载JDBCUtils类] B --> C[执行静态代码块] C --> D[获取druid.properties输入流] D --> E[加载配置到Properties对象] E --> F[创建Druid连接池] F --> G[初始化连接池] G --> H[赋值给dataSource静态变量] H --> I[类初始化完成] D -- 文件不存在 --> J[抛出异常] E -- 配置格式错误 --> J F -- 数据库连接失败 --> J J --> K[抛出RuntimeException] K --> L[类初始化失败] ``` ### 关键特性说明 1. **一次性初始化**: - 静态代码块只在类加载时执行一次 - 确保连接池只被创建一次,避免重复初始化 2. **资源自动管理**: - 输入流由类加载器管理,不需要显式关闭 - 连接池由 Druid 自动管理连接生命周期 3. **配置驱动**: - 所有连接池参数通过外部配置文件管理 - 修改配置无需重新编译代码 4. **线程安全**: - 静态初始化在类加载阶段完成,保证线程安全 - Druid 连接池本身是线程安全的 ### 典型使用场景 ```java public class UserDAO { public List<User> getAllUsers() { try (Connection conn = JDBCUtils.getConnection(); PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users"); ResultSet rs = pstmt.executeQuery()) { List<User> users = new ArrayList<>(); while (rs.next()) { users.add(new User(rs.getInt("id"), rs.getString("name"))); } return users; } catch (SQLException e) { throw new RuntimeException("查询用户失败", e); } } } ``` ### 配置示例 (druid.properties) ```properties # 基本配置 driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC username=root password=123456 # 连接池配置 initialSize=5 minIdle=5 maxActive=20 maxWait=60000 validationQuery=SELECT 1 testWhileIdle=true ``` ### 常见问题排查 1. **配置文件找不到**: - 确保 `druid.properties` 位于资源目录 - 检查文件名拼写是否正确 - 在 Maven 项目中确认文件在 `src/main/resources` 目录 2. **数据库连接失败**: - 检查 `url` 格式是否正确 - 验证数据库服务是否运行 - 确认用户名/密码是否正确 3. **连接池初始化失败**: - 检查必需的配置项是否缺失 - 查看 Druid 版本与JDK版本是否兼容 - 确认数据库驱动是否在类路径中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值