Java 如何使用 Spring @Configuration 而不是 XML 配置来检索 JNDI

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19431517/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 17:05:55  来源:igfitidea点击:

How to retrieve JNDI using Spring @Configuration instead of XML configuration

javaspringspring-annotations

提问by Eric B.

I've started development of a new Spring 3.2.4 application and am trying to use Java based configuration instead of XML files as I have used in the past. However, I am having trouble making the transition.

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

Using XML, I would code it as follows:

使用 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>

However, I am very much stuck trying to figure out how to do this in Java. I'm trying to replicate the configuration, but running into trouble:

但是,我一直在试图弄清楚如何在 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());
    }

}

However, I get the following error message:

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

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

What am I missing or doing wrong?

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

EDIT

编辑

Following @SotiriosDelimanolis response, I have modified my code to read the following:

在@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);
}

But am getting Autowired exceptions instead now:

但是现在我收到了 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

回答by Sotirios Delimanolis

This is a weird design (for PersistenceExceptionTranslator) that I don't immediately understand, but here is the solution.

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

Your LocalContainerEntityManagerFactoryBeanis a FactoryBeanbut also a PersistenceExceptionTranslator(implements both). But you aren't putting the LocalContainerEntityManagerFactoryBeaninto your context, you are only getting its created object.

LocalContainerEntityManagerFactoryBean是一个FactoryBean但也是一个PersistenceExceptionTranslator(同时实现)。但是您并没有将LocalContainerEntityManagerFactoryBean放入您的上下文中,您只是获得了它创建的对象。

Instead of

代替

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

do

@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 will take care of calling afterPropertiesSet()and getObject()to put a EntityManagerFactorybean into the context.

Spring将采取调用的照顾afterPropertiesSet(),并getObject()把一个EntityManagerFactoryBean注入的上下文。

Basically you end up with two beans, a EntityManagerFactoryand a LocalContainerEntityManagerFactoryBean. Your JPA configuration requires a PersistenceExceptionTranslatorbean in the context. That will be satisfied by LocalContainerEntityManagerFactoryBean.

基本上你最终会得到两个 bean, aEntityManagerFactory和 a LocalContainerEntityManagerFactoryBean。您的 JPA 配置需要PersistenceExceptionTranslator上下文中的bean。这将满足LocalContainerEntityManagerFactoryBean



FYI, you can do the same thing for your JndiObjectFactoryBeanor any other FactoryBean.

仅供参考,您可以为您的JndiObjectFactoryBean或任何其他FactoryBean.

回答by Raj

please refer below link -

请参考以下链接 -

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

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

the datasource need to be created like this -

需要像这样创建数据源 -

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