【问题标题】:How to retrieve JNDI using Spring @Configuration instead of XML configuration如何使用 Spring @Configuration 而不是 XML 配置检索 JNDI
【发布时间】:2013-10-26 05:25:45
【问题描述】:

我已经开始开发一个新的 Spring 3.2.4 应用程序,并尝试使用基于 Java 的配置,而不是我过去使用的 XML 文件。但是,我在过渡时遇到了麻烦。

使用 XML,我将其编码如下:

<!-- application datasource -->
<bean id="dataSource.jndi" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton" lazy-init="true">
    <property name="jndiName" value="java:comp/env/jdbc/liment" />
</bean>

<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="dataSource" ref="dataSource.jndi"/>
</bean>

但是,我非常想弄清楚如何在 Java 中做到这一点。我正在尝试复制配置,但遇到了麻烦:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages={"com.ia"})
public class AppConfigJPA {
    @Bean
    public DataSource dataSource() {
        // configure and return the necessary JDBC DataSource
        JndiObjectFactoryBean dataSource = new JndiObjectFactoryBean();
        dataSource.setJndiName("java:comp/env/jdbc/liment");
        try {
            dataSource.afterPropertiesSet();
        } catch (IllegalArgumentException | NamingException e) {
            // rethrow
            throw new RuntimeException(e);
        }
        return (DataSource)dataSource.getObject();
    }

    @Bean
    public EntityManagerFactory entityManagerFactory(){
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setPersistenceUnitName("persistenceUnit");
        emf.setDataSource(dataSource());
            emf.afterPropertiesSet
        return emf.getObject();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory());
    }

}

但是,我收到以下错误消息:

Caused by: java.lang.IllegalStateException: No persistence exception translators found in bean factory. Cannot perform exception translation.
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:142)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.setBeanFactory(PersistenceExceptionTranslationInterceptor.java:117)
    at org.springframework.data.repository.core.support.PersistenceExceptionTranslationRepositoryProxyPostProcessor.<init>(PersistenceExceptionTranslationRepositoryProxyPostProcessor.java:44)
    at org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport.setBeanFactory(TransactionalRepositoryFactoryBeanSupport.java:85)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1502)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1470)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
    ... 33 more

我错过了什么或做错了什么?

编辑

在@SotiriosDelimanolis 回复之后,我修改了我的代码以阅读以下内容:

@Autowired DataSource dataSource;
@Autowired EntityManagerFactory entityManagerFactory;


@Bean
public JndiObjectFactoryBean dataSource() {
    // configure and return the necessary JDBC DataSource
    JndiObjectFactoryBean dataSource = new JndiObjectFactoryBean();
    dataSource.setJndiName("java:comp/env/jdbc/josak");
    return dataSource;
}

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setPersistenceUnitName("persistenceUnit");
    emf.setDataSource(dataSource);
    return emf;
}

@Bean
public PlatformTransactionManager transactionManager() {
    return new JpaTransactionManager(entityManagerFactory);
}

但是现在我得到了 Autowired 异常:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: javax.sql.DataSource com.ia.system.configuration.AppConfigJPA.dataSource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:514)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
    ... 31 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:988)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:858)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:770)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
    ... 33 more

【问题讨论】:

  • 你能验证dataSource.getObject();返回的引用是null吗?如果您致电afterPropertiesSet(),则不会发生这种情况。请发布更长的堆栈跟踪。
  • @SotiriosDelimanolis 实际上,在看到您的评论之前,我只是在代码中发现了一个错误。我忘记了 entityManagerFactory() 中的“afterPropertiesSet()”调用。但是现在,我得到了一个与持久性异常翻译器相关的不同异常。

标签: java spring spring-annotations


【解决方案1】:

这是一个奇怪的设计(针对PersistenceExceptionTranslator),我不立即理解,但这是解决方案。

您的LocalContainerEntityManagerFactoryBeanFactoryBean,但也是PersistenceExceptionTranslator(实现两者)。但是您并没有将 LocalContainerEntityManagerFactoryBean 放入您的上下文中,您只是获取它创建的对象。

代替

@Bean
public EntityManagerFactory entityManagerFactory(){
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setPersistenceUnitName("persistenceUnit");
    emf.setDataSource(dataSource());
        emf.afterPropertiesSet
    return emf.getObject();
}

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setPersistenceUnitName("persistenceUnit");
    emf.setDataSource(dataSource());
    return emf;
}

@Autowired
private EntityManagerFactory entityManagerFactory;

@Bean
public PlatformTransactionManager transactionManager() {
    return new JpaTransactionManager(entityManagerFactory);
}

Spring 将负责调用 afterPropertiesSet()getObject() 以将 EntityManagerFactory bean 放入上下文中。

基本上你会得到两个 bean,一个 EntityManagerFactory 和一个 LocalContainerEntityManagerFactoryBean。您的 JPA 配置需要在上下文中使用 PersistenceExceptionTranslator bean。 LocalContainerEntityManagerFactoryBean 将满足这一要求。


仅供参考,您可以为您的 JndiObjectFactoryBean 或任何其他 FactoryBean 做同样的事情。

【讨论】:

  • JpaTransactionManager 期望 EntityManagerFactory 作为其构造函数类型。如果 entityManagerFactory() 返回 LocalContainerEntityManagerFactoryBean,如何实例化 transactionManager()?同样,如果我从 dataSource() 返回一个 JndiObjectFactoryBean,如何使用 JndiFactoryBean 设置 emf.setDataSource()?
  • @EricB。春天就是这么神奇。它代理@Bean 方法调用并返回FactoryBean 创建的bean,而不是FactoryBean 本身。
  • 我不明白。返回工厂 bean 会使编译器在 return new JpaTransactionManager(entityManagerFactory()) 上抱怨:The constructor JpaTransactionManager(LocalContainerEntityManagerFactoryBean) is undefined
  • @EricB。哦这个。我的错。一种解决方法是将您的FactoryBean bean 创建的对象类型的@Autowired bean 放入一些@Configuration 类字段中。然后使用它们而不是调用它们各自的方法。
  • 这看起来很复杂。你可以发布一个例子吗?我尝试了您的建议,但显然做错了,因为当它尝试自动装配我的 DataSource bean 时,我得到了 NoSuchBeanDefnExceptions。我正在编辑上面的问题以发布我的新代码和异常
【解决方案2】:

请参考以下链接 -

http://forum.spring.io/forum/spring-projects/container/724356-how-to-use-javaconfig-to-declare-a-jndi-datasource

需要像这样创建数据源 -

@Bean
    public DataSource dataSource() {
        final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
        dsLookup.setResourceRef(true);
        DataSource dataSource = dsLookup.getDataSource("jdbc/yourJdbcGoesHere");
        return dataSource;
    } 

【讨论】:

  • setResourceRef 在此上下文中不是必需的,因为 JndiDataSourceLookup 将其设置为 true。代码就是new JndiDataSourceLookup().getDataSource("jdbc/yourJdbcGoesHere")
  • 你应该实际使用@Bean(destroyMethod="")
猜你喜欢
  • 1970-01-01
  • 2019-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多