【问题标题】:why use JndiObjectFactoryBean to config JNDI datasource did not work?为什么使用 JndiObjectFactoryBean 配置 JNDI 数据源不起作用?
【发布时间】:2016-04-12 13:53:13
【问题描述】:

当我使用 Java-base 来配置我的 JNDI 时。春季 4.2.5。

但是如果我使用 JndiObjectFactoryBean 进行配置。当我想获取datasource 时,该对象将为空。

@Bean
    public DataSource dataSource(){
        JndiObjectFactoryBean jndiObjectFactoryBean =new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiName("jdbc/SpittrDS");
        jndiObjectFactoryBean.setResourceRef(true);
        jndiObjectFactoryBean.setProxyInterface(DataSource.class);
        return (DataSource) jndiObjectFactoryBean.getObject();  //NULL!!!
    }

但是如果把方法改成这个,效果很好。

@Bean
    public DataSource dataSource(){
        final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
        dsLookup.setResourceRef(true);
        DataSource dataSource = dsLookup.getDataSource("java:comp/env/jdbc/SpittrDS");
        return dataSource;
    }

我不知道问题出在哪里。

Tomcat 9.0 上下文.xml

<Context>

    <!-- Default set of monitored resources. If one of these changes, the    -->
    <!-- web application will be reloaded.                                   -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>

    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!--
    <Manager pathname="" />
    -->

    <Resource name="jdbc/SpittrDS"
      auth="Container"
      type="javax.sql.DataSource"
      driverClassName="com.mysql.jdbc.Driver"
      url="jdbc:mysql://localhost:3306/spittrds"
      username="root"
      password="1"
      maxActive="100"
      maxIdle="20"
      minIdle="5"
      maxWait="10000"/>
</Context>

【问题讨论】:

    标签: java spring jndi


    【解决方案1】:

    在 JndiObjectFactoryBean 中的实际查找是在生命周期回调方法中完成的。像这样在 @Bean 方法中显式调用该方法(解决方法)

        @Bean
        public DataSource dataSource(){
            JndiObjectFactoryBean jndiObjectFactoryBean =new JndiObjectFactoryBean();
            jndiObjectFactoryBean.setJndiName("jdbc/SpittrDS");
            jndiObjectFactoryBean.setResourceRef(true);
            jndiObjectFactoryBean.setProxyInterface(DataSource.class);
            jndiObjectFactoryBean.afterPropertiesSet();
            return (DataSource) jndiObjectFactoryBean.getObject();  //NULL!!!
        }
    

    或者更好的方法。让您的 @Bean 方法返回 JndiObjectFactoryBean 并管理它的生命周期。然后在需要 DataSource 的依赖 bean 中注入工厂创建的数据源

        @Bean
        public JndiObjectFactoryBean dataSource(){
            JndiObjectFactoryBean jndiObjectFactoryBean =new JndiObjectFactoryBean();
            jndiObjectFactoryBean.setJndiName("jdbc/SpittrDS");
            jndiObjectFactoryBean.setResourceRef(true);
            jndiObjectFactoryBean.setProxyInterface(DataSource.class);
            return jndiObjectFactoryBean;
        }
    
    //in your dependnecy
    
    @Bean
    public SomeBean someBean(DataSource dataSource){
       //use the injected datasource shich comes from the factory
    }
    

    【讨论】:

    • 我想知道为什么这个方法jndiObjectFactoryBean.getObject()返回null
    • 正如我所说,实际查找是在创建 bean 后 Spring 调用的 afterPropertiesSet 方法中完成的。在该调用之前,不会从 JNDI 检索对象。
    • 如果我有多个数据源,那么如何在 someBean() 中选择特定的一个?
    • 还在这里查看那些在 Spring 中苦苦挣扎的人试图过早地初始化数据源,当时他们还不能通过 JNDI 进行查找(似乎)——我无法让它工作,但它那里似乎更温暖:stackoverflow.com/questions/32776410/…
    【解决方案2】:

    我来到这里时没有意识到这是我过去遇到过的问题 - Error Casting Spring's JndiObjectFactoryBean to ConnectionFactory for Solace-MQ JMS

    所以一种解决方法(不是首选方法)是在尝试 getObject() 之前在 jndiObjectFactoryBean 上调用 afterPropertiesSet()

    @Bean
        public DataSource dataSource(){
            JndiObjectFactoryBean jndiObjectFactoryBean =new JndiObjectFactoryBean();
            jndiObjectFactoryBean.setJndiName("jdbc/SpittrDS");
            jndiObjectFactoryBean.setResourceRef(true);
            jndiObjectFactoryBean.setProxyInterface(DataSource.class);
            jndiObjectFactoryBean.afterPropertiesSet();
            return (DataSource) jndiObjectFactoryBean.getObject();  //NOT NULL
        }
    

    【讨论】:

      【解决方案3】:

      对于那些只想通过 JNDI 定义数据源的方法的人,我会选择:

      @Bean
      public JndiObjectFactoryBean dataSource(){
          return new JndiDataSourceLookup().getDataSource("jdbc/SpittrDS");
      }
      

      【讨论】:

        猜你喜欢
        • 2011-12-07
        • 2017-03-06
        • 2020-12-14
        • 2021-12-30
        • 1970-01-01
        • 2013-01-08
        • 1970-01-01
        • 1970-01-01
        • 2016-01-02
        相关资源
        最近更新 更多