it-roy-ru.com

Не удается разрешить ссылку на bean-компонент "entityManagerFactory" при установке аргумента конструктора;

Я получаю эту ошибку в моем коде.

org.springframework.beans.factory.BeanCreationException: Ошибка создание компонента с именем roleRepository: невозможно создать внутренний компонент '(внутренний бин) # 7540dc57' типа [org.springframework.orm.jpa.SharedEntityManagerCreator] при настройке свойство бина 'entityManager'; Вложенное исключение org.springframework.beans.factory.BeanCreationException: Ошибка создание компонента с именем '(внутренний компонент) # 7540dc57': невозможно разрешить ссылка на bean-компонент "entityManagerFactory" во время установки конструктора аргумент; Вложенное исключение org.springframework.beans.factory.NoSuchBeanDefinitionException: № доступен компонент с именем entityManagerFactory

Я видел это: 

Не удается разрешить ссылку на bean-компонент "entityManagerFactory" при установке аргумента конструктора

NoSuchBeanDefinitionException: недоступен бин с именем entityManagerFactory

NoSuchBeanDefinitionException: не определен бин с именем entityManagerFactory

Никто из них не отвечает на мой вопрос. Дело в том, что я смог решить проблему, но у меня есть вопрос по этому поводу.

Позвольте мне поделиться своим связанным кодом и затем задать вопрос, который у меня есть.

@Configuration
@EnableTransactionManagement 
public class HibernateConfig {

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerF() {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource());
    em.setPackagesToScan(new String[] {"com.gitreporter"});
    JpaVendorAdapter jpaAdapter = new HibernateJpaVendorAdapter();
    em.setJpaVendorAdapter(jpaAdapter);
    em.setJpaProperties(jpaProperties());

    return em;
}

@Bean
public PlatformTransactionManager jpaTransactionManager(EntityManagerFactory emf) {
    JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
    jpaTransactionManager.setEntityManagerFactory(emf);

    return jpaTransactionManager;
}

private final Properties jpaProperties() {
    Properties properties = new Properties();
    properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");

    return properties;
}


@Bean
public DataSource dataSource() {
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/MyDBNAME?useSSL=false");
    dataSource.setUsername("username");
    dataSource.setPassword("password");

    return dataSource;
}

Проблема была в этой строке:

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerF() {

Я изменил имя medhod на entityManagerFactory следующим образом:

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

Создание имени фабричного компонента в контексте равным «entityManagerFactory», так как по умолчанию имя компонента будет равно имени метода, если это не указано явно. 

Мой вопрос: есть ли место в JPA API, где "по соглашению" он ищет объект EntityManagerFactory с именем "entityManagerFactory" внутри контейнера Spring? Почему он не работает, если имя метода - entityManagerF?

Вот остальная часть кода:

@NoRepositoryBean
public interface GenericRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {

public List<T> findByAttributeContainsText(String attributeName, String text);

}

public class GenericRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
    implements GenericRepository<T, ID> {

private EntityManager entityManager;

public GenericRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
    super(entityInformation, entityManager);
    this.entityManager = entityManager;
 }
}


public interface RoleRepository extends GenericRepository<Role, Long> {

}
4
SoftwareTheory

Я нашел ответ.

Ознакомьтесь с документацией для аннотации @EnableJpaRepositories. 

В дополнительных элементах вы увидите это:

entityManagerFactoryRef Настраивает имя определения компонента EntityManagerFactory, которое будет использоваться для создания хранилищ, обнаруженных с помощью этой аннотации.

Перейдите по странице к деталям, и вы увидите это:

entityManagerFactoryRef

публичная абстрактная строка entityManagerFactoryRef 

Настраивает имя определение bean-компонента EntityManagerFactory должно быть используется для создания репозитории, обнаруженные с помощью этой аннотации, По умолчанию entityManagerFactory

Возвращает: 

По умолчанию: "entityManagerFactory"

Так что эта «обычная» конфигурация по умолчанию взята из самой аннотации @EnableJpaRepositories.

1
SoftwareTheory

Да, я верю в это. В вашем случае Spring предварительно настроил бин entityManagerFactory.

Отрывок из Javadoc для @EnableAutoConfiguration говорит 

        Enable auto-configuration of the Spring Application Context, attempting to guess and configure beans that you are likely to need. Auto-configuration classes are usually applied based on your classpath and what beans you have defined. For example, if you have Tomcat-embedded.jar on your classpath you are likely to want a TomcatServletWebServerFactory (unless you have defined your own ServletWebServerFactory bean).

И, увидев вашу спящую конфигурацию, 

private final Properties jpaProperties() {
    Properties properties = new Properties();
    properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");

    return properties;

... Я считаю, что это должно быть вызвано, который является производным от JpaBaseConfiguration

@Configuration
@ConditionalOnSingleCandidate(DataSource.class)
class HibernateJpaConfiguration extends JpaBaseConfiguration {

И у JpaBaseConfiguration было определение бина для entityManagerFactory, которое вы пытаетесь переопределить.

@Bean
@Primary
@ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class,
        EntityManagerFactory.class })
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
        EntityManagerFactoryBuilder factoryBuilder) {
    Map<String, Object> vendorProperties = getVendorProperties();
    customizeVendorProperties(vendorProperties);
    return factoryBuilder.dataSource(this.dataSource).packages(getPackagesToScan())
            .properties(vendorProperties).mappingResources(getMappingResources())
            .jta(isJta()).build();
}

Edit: - Благодаря ответу OP. Таким образом, его даже можно использовать для предоставления собственного имени бина через объявление типа 

@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerF",
)         

Другой поток stackoverflow по адресу https://stackoverflow.com/a/45665826/5107365 предоставляет более глубокое понимание этой проблемы. 

0
Raj