为什么使用JndiObjectFactoryBean来配置JNDI数据源不起作用?

时间:2016-04-12 13:53:13

标签: java spring jndi

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

但是如果我使用JndiObjectFactoryBean来配置。当我想获得datasource时,该对象将为null。

@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 context.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>

2 个答案:

答案 0 :(得分:5)

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
}

答案 1 :(得分:1)

我在这里落地而没有意识到这是我过去遇到的一个问题 - 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
    }