【问题标题】:Hibernate 5 + Spring + JDBC thin client UCP interfaces not visible to classloaderHibernate 5 + Spring + JDBC 瘦客户端 UCP 接口对类加载器不可见
【发布时间】:2019-06-21 20:03:46
【问题描述】:

我已经升级了以下库:

  • 春季 3.2.0 -> 4.3.22
  • 休眠 4.1.1 -> 5.1.11

值得注意的是,我还使用 JDBC 瘦客户端库

  • OJDBC 7
  • ucp 12.1.0
  • 在 12.1.0 上

我正在开发一个部署在 WSO2 应用服务器中的 Axis2 服务。初始化的一部分是加载休眠会话工厂。定义如下。

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="configLocation">
        <value>classpath:hibernate.cfg.xml</value>
    </property>
    <property name = "dataSource" ref = "dataSource"></property>
</bean>

当我去初始化 bean 时,我通过 ClassPathXmlApplicationContext 使用我的休眠会话工厂定义指向文件来完成它。

final ClassLoader classLoader = service.getClassLoader();
ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext(new String[] {"repository/conf/pda/applicationContext_dataInventory.xml"}, false)
appCtx.setClassLoader(classLoader);
appCtx.refresh(); // <--- Causes error

当我打电话给appCtx.refresh() 时,我收到一个异常声明

Caused by: java.lang.IllegalArgumentException: interface oracle.ucp.jdbc.LabelableConnection is not visible from class loader
        at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:616)
        at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:592)
        at java.lang.reflect.WeakCache$Factory.get(WeakCache.java:244)
        at java.lang.reflect.WeakCache.get(WeakCache.java:141)
        at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:455)
        at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:738)
        at oracle.ucp.jdbc.proxy.ConnectionProxyFactory.createConnectionProxy(ConnectionProxyFactory.java:79)
        at oracle.ucp.jdbc.PoolDataSourceImpl.getConnection(PoolDataSourceImpl.java:1046)
        at com.xxx.espds.cim.dataMgmt.hibernate.FailoverPoolDataSource.getConnection(FailoverPoolDataSource.java:519)
        at com.xxx.espds.cim.dataMgmt.hibernate.FailoverPoolDataSource.getConnection(FailoverPoolDataSource.java:497)
        at com.xxx.espds.cim.dataMgmt.hibernate.FailoverPoolDataSource.getConnection(FailoverPoolDataSource.java:492)
        at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
        at org.hibernate.internal.SessionFactoryImpl$3.obtainConnection(SessionFactoryImpl.java:677)
        at org.hibernate.hql.spi.id.IdTableHelper.executeIdTableCreationStatements(IdTableHelper.java:67)
        at org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy.finishPreparation(GlobalTemporaryTableBulkIdStrategy.java:125)
        at org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy.finishPreparation(GlobalTemporaryTableBulkIdStrategy.java:42)
        at org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl.prepare(AbstractMultiTableBulkIdStrategyImpl.java:88)
        at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:471)
        at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:422)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:711)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:727)
        at org.springframework.orm.hibernate5.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:511)
        at org.springframework.orm.hibernate5.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:495)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1689)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1627)

如果我在刷新调用之前通过调用appCtx.getClassLoader().loadClass("oracle.ucp.jdbc.LabelableConnection"); 手动加载类,那么这个特定的错误将会消失,但我最终会在类加载器不可见的另一个接口上遇到错误。我的想法是这与 Spring/Hibernate 没有使用与我提供给ClassPathXmlApplicationContext 相同的类加载器有关。

为什么 UCP 类在会话工厂初始化时不可见?

【问题讨论】:

    标签: java spring hibernate osgi classloader


    【解决方案1】:

    通过将线程类加载器设置为用于 ClassPathXmlApplicationContext 的 ClassLoader 解决了问题。 oracle JDBC 最终会尝试使用Thread.currentThread().getContextClassLoader(); 从 UCP 依赖项加载它自己的一些类。下面详细说明了该修复的代码

    // Get current thread ClassLoader and reset it after we do the initial load. While we previously set the
    // Spring ClassLoader, when we initialize the UCP ConnectionPool via the hibernate sessionFactory the jdbc
    // thin client attempts to load classes using the currentThread().getContextClassLoader(). To get around this,
    // we need to set the threads ClassLoader to the one that has information on the JDBC libraries, and since we
    // always package up the libraries in each service, that would be the service.getClassLoader()
    final ClassLoader classLoader = service.getClassLoader();
    ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"}, false);
    appCtx.setClassLoader(classLoader);
    ClassLoader threadLoader = Thread.currentThread().getContextClassLoader();
    Thread.currentThread().setContextClassLoader(classLoader);
    appCtx.refresh();
    Thread.currentThread().setContextClassLoader(threadLoader);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-25
      • 2021-05-29
      • 1970-01-01
      • 2010-12-09
      • 1970-01-01
      相关资源
      最近更新 更多