org.hibernate.util.ConfigHelper.java

本文详细介绍了使用Java类加载器加载配置文件的过程,包括当前线程类加载器、当前类加载器和系统类加载器的使用,以及如何通过类路径定位配置文件并获取其输入流和读取内容。

该类为hibernate资源加载工具类,在资源加载过程中,用到JDK的三种类加载类

1. 当前线程类加载器

    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

2. 当前类加载器

    ClassLoader contextClassLoader = ConfigHelper.class.getClassLoader();

3. 系统类加载器

    ClassLoader contextClassLoader = ClassLoader.getSystemClassLoader()

 

在这里按照1、2、3依次加载,如果当前线程类加载器加载成功,则直接返回.........

 

在该类中用到一个类org.hibernate.cfg.Environment.java,从名称可以看到该类为hibernate环境相关的处理

 


package org.hibernate.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;

/**
 * A simple class to centralize logic needed to locate config files on the system.
 *
 * @author Steve
 */
public final class ConfigHelper {
 private static final Log log = LogFactory.getLog(ConfigHelper.class);

 /** Try to locate a local URL representing the incoming path.  The first attempt
  * assumes that the incoming path is an actual URL string (file://, etc).  If this
  * does not work, then the next attempts try to locate this UURL as a java system
  * resource.
  *
  * @param path The path representing the config location.
  * @return An appropriate URL or null.
  */
 public static final URL locateConfig(final String path) {
  try {
   return new URL(path);
  }
  catch(MalformedURLException e) {
   return findAsResource(path);
  }
 }

 /**
  * Try to locate a local URL representing the incoming path. 
  * This method <b>only</b> attempts to locate this URL as a
  * java system resource.
  *
  * @param path The path representing the config location.
  * @return An appropriate URL or null.
  */
 public static final URL findAsResource(final String path) {
  URL url = null;

  // First, try to locate this resource through the current
  // context classloader.
  ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
  if (contextClassLoader!=null) {
   url = contextClassLoader.getResource(path);
  }
  if (url != null)
   return url;

  // Next, try to locate this resource through this class's classloader
  url = ConfigHelper.class.getClassLoader().getResource(path);
  if (url != null)
   return url;

  // Next, try to locate this resource through the system classloader
  url = ClassLoader.getSystemClassLoader().getResource(path);

  // Anywhere else we should look?
  return url;
 }

 /** Open an InputStream to the URL represented by the incoming path.  First makes a call
  * to {@link #locateConfig(java.lang.String)} in order to find an appropriate URL.
  * {@link java.net.URL#openStream()} is then called to obtain the stream.
  *
  * @param path The path representing the config location.
  * @return An input stream to the requested config resource.
  * @throws HibernateException Unable to open stream to that resource.
  */
 public static final InputStream getConfigStream(final String path) throws HibernateException {
  final URL url = ConfigHelper.locateConfig(path);

  if (url == null) {
   String msg = "Unable to locate config file: " + path;
   log.fatal(msg);
   throw new HibernateException(msg);
  }

  try {
   return url.openStream();
        }
  catch(IOException e) {
         throw new HibernateException("Unable to open config file: " + path, e);
        }
 }

 /** Open an Reader to the URL represented by the incoming path.  First makes a call
  * to {@link #locateConfig(java.lang.String)} in order to find an appropriate URL.
  * {@link java.net.URL#openStream()} is then called to obtain a stream, which is then
  * wrapped in a Reader.
  *
  * @param path The path representing the config location.
  * @return An input stream to the requested config resource.
  * @throws HibernateException Unable to open reader to that resource.
  */
 public static final Reader getConfigStreamReader(final String path) throws HibernateException {
  return new InputStreamReader( getConfigStream(path) );
 }

 /** Loads a properties instance based on the data at the incoming config location.
  *
  * @param path The path representing the config location.
  * @return The loaded properties instance.
  * @throws HibernateException Unable to load properties from that resource.
  */
 public static final Properties getConfigProperties(String path) throws HibernateException {
  try {
   Properties properties = new Properties();
   properties.load( getConfigStream(path) );
   return properties;
  }
  catch(IOException e) {
   throw new HibernateException("Unable to load properties from specified config file: " + path, e);
  }
 }
 
 private ConfigHelper() {}

 public static InputStream getResourceAsStream(String resource) {
  String stripped = resource.startsWith("/") ?
    resource.substring(1) : resource;
 
  InputStream stream = null;
  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  if (classLoader!=null) {
   stream = classLoader.getResourceAsStream( stripped );
  }
  if ( stream == null ) {
   Environment.class.getResourceAsStream( resource );
  }
  if ( stream == null ) {
   stream = Environment.class.getClassLoader().getResourceAsStream( stripped );
  }
  if ( stream == null ) {
   throw new HibernateException( resource + " not found" );
  }
  return stream;
 }
}

`java.lang.NullPointerException` 是 Java 中常见的异常,当应用程序试图在需要对象的地方使用 `null` 时抛出。异常位置在 `org.hibernate.hql.ast.util.SessionFactoryHelper.findSQLFunction(SessionFactoryHelper.java:364)` 通常意味着在该方法中某个对象为 `null`,而代码尝试对其进行操作。以下是一些可能的解决方法: ### 检查 Hibernate 配置 确保 Hibernate 的配置文件(如 `hibernate.cfg.xml` 或 Spring Boot 中的 `application.properties`/`application.yml`)正确配置。错误的配置可能导致 `SessionFactory` 或相关对象未正确初始化,从而引发 `NullPointerException`。 ```properties # application.properties 示例 spring.datasource.url=jdbc:mysql://localhost:3306/yourdb spring.datasource.username=yourusername spring.datasource.password=yourpassword spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true ``` ### 检查 SQL 函数注册 `findSQLFunction` 方法通常用于查找 SQL 函数。确保所有自定义的 SQL 函数都已正确注册到 Hibernate 中。可以通过实现 `org.hibernate.dialect.Dialect` 并重写 `registerFunctions` 方法来注册自定义函数。 ```java import org.hibernate.dialect.MySQL8Dialect; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.type.StandardBasicTypes; public class CustomMySQLDialect extends MySQL8Dialect { public CustomMySQLDialect() { super(); registerFunction("custom_function", new SQLFunctionTemplate(StandardBasicTypes.STRING, "custom_function(?1)")); } } ``` 然后在配置文件中指定自定义方言: ```properties spring.jpa.database-platform=com.example.CustomMySQLDialect ``` ### 确保 SessionFactory 正确初始化 在使用 Hibernate 时,`SessionFactory` 必须正确初始化。在 Spring Boot 中,通常会自动配置 `SessionFactory`,但也需要确保依赖注入正确。 ```java import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class MyService { private final SessionFactory sessionFactory; @Autowired public MyService(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } // 使用 SessionFactory 的方法 } ``` ### 调试和日志记录 在 `SessionFactoryHelper.findSQLFunction` 方法附近添加调试日志,输出可能为 `null` 的对象,以便确定具体是哪个对象为 `null`。 ```java import org.slf4j.Logger; import org.slf4j.LoggerFactory; // 在 SessionFactoryHelper 类中添加日志记录 private static final Logger logger = LoggerFactory.getLogger(SessionFactoryHelper.class); public SQLFunction findSQLFunction(String name) { // 检查可能为 null 的对象 if (someObject == null) { logger.error("someObject is null"); } // 其他代码 } ``` ### 检查依赖版本 确保 Hibernate 及其相关依赖的版本兼容。不兼容的版本可能导致类初始化失败或对象未正确创建。可以通过 Maven 或 Gradle 管理依赖版本。 ```xml <!-- pom.xml 示例 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.6.10.Final</version> </dependency> ``` ### 检查数据库连接 确保数据库服务正在运行,并且应用程序可以正常连接到数据库。可以使用数据库管理工具(如 MySQL Workbench)测试数据库连接。 ### 检查代码逻辑 检查调用 `findSQLFunction` 方法的代码逻辑,确保传递的参数不为 `null`。 ```java // 示例代码 String functionName = getFunctionName(); if (functionName != null) { SQLFunction function = sessionFactoryHelper.findSQLFunction(functionName); // 处理函数 } ``` ### 检查 HQL 查询 如果异常是在执行 HQL 查询时抛出的,检查 HQL 查询语句是否正确,是否包含未定义的 SQL 函数。 ```java // 示例 HQL 查询 String hql = "SELECT custom_function(column) FROM Entity"; Query query = session.createQuery(hql); List result = query.list(); ``` ### 检查事务管理 确保事务管理正确配置。不正确的事务管理可能导致 `Session` 或 `SessionFactory` 未正确初始化或关闭。 ```java import org.springframework.transaction.annotation.Transactional; @Service public class MyService { @Transactional public void doSomething() { // 业务逻辑 } } ``` ### 检查第三方库 如果使用了第三方库,确保这些库与 Hibernate 兼容。不兼容的第三方库可能会干扰 Hibernate 的正常运行。 ### 检查服务器环境 确保服务器环境(如 Java 版本、服务器配置等)符合应用程序的要求。 ### 检查数据库权限 确保应用程序使用的数据库用户具有执行相关 SQL 函数的权限。 ### 检查缓存 如果使用了 Hibernate 的二级缓存,确保缓存配置正确。错误的缓存配置可能导致对象未正确加载,从而引发 `NullPointerException`。 ### 检查代码中的空指针 在调用 `findSQLFunction` 方法之前,确保传递的参数不为 `null`。可以使用 `Objects.requireNonNull` 方法进行检查。 ```java import java.util.Objects; public SQLFunction findSQLFunction(String name) { Objects.requireNonNull(name, "Function name cannot be null"); // 其他代码 } ``` ### 检查数据库表结构 确保数据库表结构与实体类定义一致。不一致的表结构可能导致 Hibernate 在查询时出现问题。 ### 检查数据源配置 确保数据源配置正确,包括数据库连接 URL、用户名、密码等。 ```properties # application.properties 示例 spring.datasource.url=jdbc:mysql://localhost:3306/yourdb spring.datasource.username=yourusername spring.datasource.password=yourpassword ``` ### 检查 Hibernate 版本兼容性 确保 Hibernate 版本与其他依赖库(如 Spring Boot、JDBC 驱动等)兼容。 ### 检查数据库驱动 确保使用的数据库驱动版本与数据库版本兼容。 ```xml <!-- pom.xml 示例 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency> ``` ### 检查 SQL 函数定义 确保 SQL 函数在数据库中正确定义。可以使用数据库管理工具(如 MySQL Workbench)检查函数定义。 ### 检查 Hibernate 日志 启用 Hibernate 的详细日志记录,查看更详细的错误信息。 ```properties # application.properties 示例 logging.level.org.hibernate=DEBUG ``` 通过以上步骤,可以逐步排查并解决 `java.lang.NullPointerException` 异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值