9 votes

comment définir EntityManagerFactory à travers le constructeur par l'annotation @PersistenceUnit

Quelqu'un sait-il comment définir EntityManagerFactory via le constructeur par l'annotation @PersistenceUnit. J'ai pu le faire grâce à la configuration xml. Mais je ne connais pas la configuration de l'annotation correspondante.

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
  <bean
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml" />
<property name="persistenceUnitName" value="myUnit"></property>

<bean id="handler" class="com.handler.LocalHTHandler">
<constructor-arg ref="entityManagerFactory"></constructor-arg>

Et cela fonctionne bien. Pouvons-nous le faire à travers une annotation pour mon handler bean. J'ai entendu parler de @persistanceunit, mais il ne peut pas être placé dans le constructeur pour le réaliser. Est-ce correct ?

6voto

luwojtaszek Points 435

Comme @Dherik l'a dit, vous pouvez le faire via le constructeur. Exemple de source de données multiples ci-dessous (testé sur SpringBoot 2.0.4) :

SomeRepository.java

@Repository
public class SomeRepository {

    private final EntityManager entityManager;

    public TestService(@Qualifier("someEntityManagerFactory") EntityManager entityManager) {
        this.entityManager = entityManager;
    }
}

SomeDatabaseConfig.java

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "someEntityManagerFactory")
@EnableConfigurationProperties(JpaProperties.class)
class SomeDatabaseConfig {

    private static final String PERSISTENCE_UNIT = "some";
    private static final String[] PACKAGES_TO_SCAN = {"package.where.you.store.your.entities"};

    @Bean(name = "someDataSourceProps")
    @ConfigurationProperties("some.datasource")
    DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean(name = "someDataSource")
    DataSource dataSource(@Qualifier("someDataSourceProps") DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }

    @Bean(name = "someEntityManagerFactory")
    LocalContainerEntityManagerFactoryBean entityManagerFactory(
            JpaProperties jpaProperties,
            @Qualifier("someDataSource") DataSource dataSource,
            @Qualifier("someJpaVendorAdapter") JpaVendorAdapter jpaVendorAdapter) {
        return createEntityManagerFactory(jpaProperties, dataSource, jpaVendorAdapter, PERSISTENCE_UNIT, PACKAGES_TO_SCAN);
    }

    @Bean("someJpaVendorAdapter")
    JpaVendorAdapter jpaVendorAdapter(JpaProperties jpaProperties) {
        final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setShowSql(jpaProperties.isShowSql());
        return vendorAdapter;
    }

    @Bean(name = "someTransactionManager")
    PlatformTransactionManager transactionManager(@Qualifier("someEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }

    static LocalContainerEntityManagerFactoryBean createEntityManagerFactory(JpaProperties jpaProperties, DataSource dataSource, JpaVendorAdapter jpaVendorAdapter, String persistenceUnit, String[] packagesToScan) {
        final LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        factoryBean.setJpaDialect(new HibernateJpaDialect());
        factoryBean.setJpaPropertyMap(getVendorProperties(jpaProperties));
        factoryBean.setPersistenceUnitName(persistenceUnit);
        factoryBean.setPackagesToScan(packagesToScan);
        return factoryBean;
    }

    private static Map<String, Object> getVendorProperties(JpaProperties jpaProperties) {
        return jpaProperties.getHibernateProperties(new HibernateSettings());
    }
}

Application.java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;

@SpringBootApplication(
        exclude = {
                DataSourceAutoConfiguration.class,
                HibernateJpaAutoConfiguration.class,
                DataSourceTransactionManagerAutoConfiguration.class
        }
)
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

5voto

Jarek Przygódzki Points 1215

Impossible avec Spring qui utilise les annotations JSR 330. Actuellement, il n'est pas possible d'injecter des EntityManagers dans les constructeurs en tant que @PersistenceContext est défini comme n'étant pas autorisé sur les paramètres. Voir JPA_SPEC-72 y Autoriser l'injection d'EntityManagers par l'intermédiaire de l'injection de constructeur (et aux points d'injection non@PersistenceContext en général) [SPR-10443]. .

4voto

Dherik Points 115

Actuellement, le L'équipe du printemps dit qui est possible injecter EntityManager par constructeur, comme ils le font déjà sur Spring JPA Repository.

Juste :

private final EntityManager em;

public YourRepository(EntityManager em) {
    this.em = em;
}

J'ai testé. Ça marche :). Plus d'injection de champ.

1voto

mihu86 Points 78

Si, pour une raison ou une autre, vous ne souhaitez pas utiliser Spring Data dans votre projet (par exemple, vous ne faites qu'améliorer un projet existant), vous pouvez créer l'élément suivant FactoryBean de faire EntityManager injectable via l'injection de constructeur :

/**
 * Makes the {@link EntityManager} injectable via <i>@Autowired</i>,
 * so it can be injected with constructor injection too.
 * (<i>@PersistenceContext</i> cannot be used for constructor injection.)
 */
public static class EntityManagerInjectionFactory extends AbstractFactoryBean<EntityManager> {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public Class<?> getObjectType() {
        return EntityManager.class;
    }

    @Override
    protected EntityManager createInstance() {
        return entityManager;
    }

}

Veuillez noter que, comme nous utilisons le @PersistenceContext en interne, l'annotation EntityManager sera un véritable proxy à sécurité thread, car il aurait été injecté directement à l'endroit de l'utilisation avec l'injection de champ.

0voto

Ido Cohn Points 461

Dans notre code, nous avons un objet dao de base qui utilise le gestionnaire d'entité injecté via PersistenceContext :

public abstract class BasicJpaDao<T> implements IBasicDao<T> {

    @PersistenceContext(type = PersistenceContextType.TRANSACTION, unitName = "default")
    protected EntityManager entityManager;

    // Default constructor for Spring
    public BasicJpaDao() {}

    //Use this constructor to set the entity manager yourself
    public BasicJpaDao(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    ...

}

L'unité de persistance est définie dans le fichier de contexte d'application de la manière suivante :

<!-- JPA -->
<!-- Creates an EntityManagerFactory for use with the Hibernate JPA provider -->
<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSourceGlobal" />
    <property name="packagesToScan" value="me.comocomo.nutrino.domain.jpa" />
    <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />

    <property name="jpaPropertyMap">
        <map merge="true">
            <entry key="hibernate.format_sql" value="${hibernate.format_sql}" />
        </map>
    </property>
</bean>

<!-- jpaVendorAdapter (works in conjunction with the persistence.xml) -->
<bean id="jpaVendorAdapter"
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="database" value="${jpa.database}" />
    <property name="showSql" value="${jpa.showSql}" />
    <property name="databasePlatform" value="${jpa.dialect}" />
    <property name="generateDdl" value="${jpa.generateDdl}" />
</bean>

<!-- In order to enable EntityManager injection -->
<bean id="persistenceAnnotation"
    class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<!-- Transactions -->
<tx:annotation-driven transaction-manager="transactionManager" />

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

De la même manière, vous pouvez créer une classe EntityManagerFactoryFactory qui obtient l'EntityManagerFactory en utilisant l'injection, et qui à son tour transmet la fabrique à votre bean :

@Component
public class EntityManagerFactoryFactory {

    @Inject
    private EntityManagerFactory factory;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X