@Autowired does not work in SimpleJpaRepository ex

2019-08-02 19:04发布

When trying to override SimpleJpaRepository, adding other beans via @Autowired does not work. How can beans be injected in this case? Here is an implementation:

public class BaseDAO<T, ID extends Serializable>
             extends SimpleJpaRepository<T, ID>
             implements IDAO<T, ID> {
  @Autowired
  private SomeBean someBean; // NULL!
}

2条回答
乱世女痞
2楼-- · 2019-08-02 19:51

Instances of BaseDAO are not Spring-managed beans in themselves and therefore autowiring through @Autowired will not work out-of-the-box. Dependencies therefore need to be injected into BaseDAO instances.


Step 1: Have a Spring ApplicationContext available somewhere

@Component
class SpringContext implements ApplicationContextAware {
  private static ApplicationContext CONTEXT;

  public void setApplicationContext(final ApplicationContext context) throws BeansException {
    CONTEXT = context;
  }

  public static ApplicationContext getContext() { return CONTEXT; }
}

This will be required to autowire the dependencies for the custom repository implementation at the time of repository creation.

Step 2: Extend SimpleJpaRepository

class BaseDAO<T, ID extends Serializable>
      extends SimpleJpaRepository<T, ID> {
  @Autowired
  private Dependency dependency;
}

Step 3: Autowire dependencies through a JpaRepositoryFactoryBean

class ExtendedJPARepositoryFactoryBean<R extends JpaRepository<T, ID>, T, ID extends Serializable>
      extends JpaRepositoryFactoryBean<R, T, ID> {
  private static class ExtendedJPARepositoryFactory<T, ID extends Serializable> extends JpaRepositoryFactory {
    public ExtendedJPARepositoryFactory(final EntityManager entityManager) {
      super(entityManager);
    }

    protected Class<?> getRepositoryBaseClass(final RepositoryMetadata metadata) {
      return isQueryDslExecutor(metadata.getRepositoryInterface())
             ? QueryDSLJPARepository.class
             // Let your implementation be used instead of SimpleJpaRepository.
             : BaseDAO.class;
    }

    protected <T, ID extends Serializable> SimpleJpaRepository<?, ?> getTargetRepository(
        RepositoryInformation information, EntityManager entityManager) {
      // Let the base class create the repository.
      final SimpleJpaRepository<?, ?> repository = super.getTargetRepository(information, entityManager);

      // Autowire dependencies, as needed.
      SpringContext.getContext()
                   .getAutowireCapableBeanFactory()
                   .autowireBean(repository);

      // Return the fully set up repository.
      return repository;
    }
  }

  protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
    return new ExtendedJPARepositoryFactory(entityManager);
  }
}

Step 4a: Configure Spring Data JPA to use your factory bean (XML configuration)

<jpa:repositories base-package="org.example.jpa"
                  factory-class="org.example.jpa.ExtendedJPARepositoryFactoryBean"/>

Step 4b: Configure Spring Data JPA to use your factory bean (Java configuration)

@EnableJpaRepositories(repositoryFactoryBeanClass = ExtendedJPARepositoryFactoryBean.class)
查看更多
Root(大扎)
3楼-- · 2019-08-02 19:53

In order to let Spring know that it needs to inject something inside your DAO you need to annotate it with @Component.

You can read more about this here: http://docs.spring.io/autorepo/docs/spring-boot/current/reference/html/using-boot-spring-beans-and-dependency-injection.html.

查看更多
登录 后发表回答