sequence

This article focuses on the SimpleJpaRepository of Spring Data JPA

JpaRepositoryImplementation

Spring – data – jpa – 2.1.6. RELEASE – sources. The jar! /org/springframework/data/jpa/repository/support/JpaRepositoryImplementation.java

/** * SPI interface to be implemented by {@link JpaRepository} implementations. * * @author Oliver Gierke * @author Stefan Fussenegger */ @NoRepositoryBean public interface JpaRepositoryImplementation<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> { /** * Configures the {@link CrudMethodMetadata} to be used with the repository. * * @param  crudMethodMetadata must not be {@literal null}. */ voidsetRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata);
}
Copy the code
  • Inherited JpaRepository and JpaSpecificationExecutor JpaRepositoryImplementation interface, it is JpaRepository interface implementation class of SPI interface; It defines the setRepositoryMethodMetadata method

SimpleJpaRepository

Spring – data – jpa – 2.1.6. RELEASE – sources. The jar! /org/springframework/data/jpa/repository/support/SimpleJpaRepository.java

@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {

	private static final String ID_MUST_NOT_BE_NULL = "The given id must not be null!"; private final JpaEntityInformation<T, ? > entityInformation; private final EntityManager em; private final PersistenceProvider provider; private @Nullable CrudMethodMetadata metadata; /** * Creates a new {@link SimpleJpaRepository} to manage objects of the given {@link JpaEntityInformation}. * * @param entityInformation must not be {@literal null}. * @param entityManager must not be {@literal null}. */ public SimpleJpaRepository(JpaEntityInformation<T, ? > entityInformation, EntityManager entityManager) { Assert.notNull(entityInformation,"JpaEntityInformation must not be null!");
		Assert.notNull(entityManager, "EntityManager must not be null!");

		this.entityInformation = entityInformation;
		this.em = entityManager;
		this.provider = PersistenceProvider.fromEntityManager(entityManager);
	}

	/**
	 * Creates a new {@link SimpleJpaRepository} to manage objects of the given domain type.
	 *
	 * @param domainClass must not be {@literal null}.
	 * @param em must not be {@literal null}.
	 */
	public SimpleJpaRepository(Class<T> domainClass, EntityManager em) {
		this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);
	}

	/**
	 * Configures a custom {@link CrudMethodMetadata} to be used to detect {@link LockModeType}s and query hints to be
	 * applied to queries.
	 *
	 * @param crudMethodMetadata
	 */
	public void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata) {
		this.metadata = crudMethodMetadata;
	}

	@Nullable
	protected CrudMethodMetadata getRepositoryMethodMetadata() {
		returnmetadata; } / /... /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#delete(java.io.Serializable)
	 */
	@Transactional
	public void deleteById(ID id) {

		Assert.notNull(id, ID_MUST_NOT_BE_NULL);

		delete(findById(id).orElseThrow(() -> new EmptyResultDataAccessException(
				String.format("No %s entity with id %s exists!", entityInformation.getJavaType(), id), 1)));
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.CrudRepository#delete(java.lang.Object)
	 */
	@Transactional
	public void delete(T entity) {

		Assert.notNull(entity, "The entity must not be null!");
		em.remove(em.contains(entity) ? entity : em.merge(entity));
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.CrudRepository#delete(java.lang.Iterable)
	 */
	@Transactional
	public void deleteAll(Iterable<? extends T> entities) {

		Assert.notNull(entities, "The given Iterable of entities not be null!");

		for (T entity : entities) {
			delete(entity);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.jpa.repository.JpaRepository#deleteInBatch(java.lang.Iterable)
	 */
	@Transactional
	public void deleteInBatch(Iterable<T> entities) {

		Assert.notNull(entities, "The given Iterable of entities not be null!");

		if(! entities.iterator().hasNext()) {return;
		}

		applyAndBind(getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName()), entities, em)
				.executeUpdate();
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.Repository#deleteAll()
	 */
	@Transactional
	public void deleteAll() {

		for (T element : findAll()) {
			delete(element);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.jpa.repository.JpaRepository#deleteAllInBatch()
	 */
	@Transactional
	public void deleteAllInBatch() { em.createQuery(getDeleteAllQueryString()).executeUpdate(); } / /... /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
	 */
	@Transactional
	public <S extends T> S save(S entity) {

		if (entityInformation.isNew(entity)) {
			em.persist(entity);
			return entity;
		} else {
			return em.merge(entity);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.jpa.repository.JpaRepository#saveAndFlush(java.lang.Object)
	 */
	@Transactional
	public <S extends T> S saveAndFlush(S entity) {

		S result = save(entity);
		flush();

		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.jpa.repository.JpaRepository#save(java.lang.Iterable)
	 */
	@Transactional
	public <S extends T> List<S> saveAll(Iterable<S> entities) {

		Assert.notNull(entities, "The given Iterable of entities not be null!");

		List<S> result = new ArrayList<S>();

		for (S entity : entities) {
			result.add(save(entity));
		}

		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.jpa.repository.JpaRepository#flush()
	 */
	@Transactional
	public void flush() { em.flush(); } / /... /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#findById(java.io.Serializable)
	 */
	public Optional<T> findById(ID id) {

		Assert.notNull(id, ID_MUST_NOT_BE_NULL);

		Class<T> domainType = getDomainClass();

		if (metadata == null) {
			return Optional.ofNullable(em.find(domainType, id));
		}

		LockModeType type = metadata.getLockModeType();

		Map<String, Object> hints = getQueryHints().withFetchGraphs(em).asMap();

		return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.jpa.repository.JpaRepository#getOne(java.io.Serializable)
	 */
	@Override
	public T getOne(ID id) {

		Assert.notNull(id, ID_MUST_NOT_BE_NULL);
		return em.getReference(getDomainClass(), id);
	}

	/**
	 * Applies the given {@link Specification} to the given {@link CriteriaQuery}.
	 *
	 * @param spec can be {@literal null}.
	 * @param domainClass must not be {@literal null}.
	 * @param query must not be {@literal null}.
	 * @return
	 */
	private <S, U extends T> Root<U> applySpecificationToCriteria(@Nullable Specification<U> spec, Class<U> domainClass,
			CriteriaQuery<S> query) {

		Assert.notNull(domainClass, "Domain class must not be null!");
		Assert.notNull(query, "CriteriaQuery must not be null!");

		Root<U> root = query.from(domainClass);

		if (spec == null) {
			return root;
		}

		CriteriaBuilder builder = em.getCriteriaBuilder();
		Predicate predicate = spec.toPredicate(root, query, builder);

		if(predicate ! = null) { query.where(predicate); }returnroot; } / /... }Copy the code
  • Realizing SimpleJpaRepository JpaRepositoryImplementation interface, it is the default implementation CrudRepository; Its constructors all require an EntityManager passed in
  • Its class annotates @Transactional(readOnly = true); The @Transactional annotation is added to deleteById, delete, deleteAll, deleteInBatch, deleteAllInBatch, save, saveAndFlush, saveAll, and Flush
  • Can see from the various methods will SimpleJpaRepository is the method of using EntityManager to accomplish specific functions, to many query function with the aid of applySpecificationToCriteria method, Translate the Specification of Spring Data into the CriteriaQuery of Javax. persistence

JpaRepositoryFactory

Spring – data – jpa – 2.1.6. RELEASE – sources. The jar! /org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java

public class JpaRepositoryFactory extends RepositoryFactorySupport {

	private final EntityManager entityManager;
	private final QueryExtractor extractor;
	private final CrudMethodMetadataPostProcessor crudMethodMetadataPostProcessor;

	private EntityPathResolver entityPathResolver;
	private EscapeCharacter escapeCharacter = EscapeCharacter.of('\ \');

	/**
	 * Creates a new {@link JpaRepositoryFactory}.
	 *
	 * @param entityManager must not be {@literal null}
	 */
	public JpaRepositoryFactory(EntityManager entityManager) {

		Assert.notNull(entityManager, "EntityManager must not be null!");

		this.entityManager = entityManager;
		this.extractor = PersistenceProvider.fromEntityManager(entityManager);
		this.crudMethodMetadataPostProcessor = new CrudMethodMetadataPostProcessor();
		this.entityPathResolver = SimpleEntityPathResolver.INSTANCE;

		addRepositoryProxyPostProcessor(crudMethodMetadataPostProcessor);

		if(extractor.equals(PersistenceProvider.ECLIPSELINK)) { addQueryCreationListener(new EclipseLinkProjectionQueryCreationListener(entityManager)); }} / /... /* * (non-Javadoc) * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryMetadata)*/ @Override protected final JpaRepositoryImplementation<? ,? > getTargetRepository(RepositoryInformation information) { JpaRepositoryImplementation<? ,? > repository = getTargetRepository(information, entityManager); repository.setRepositoryMethodMetadata(crudMethodMetadataPostProcessor.getCrudMethodMetadata());return repository;
	}

	/**
	 * Callback to create a {@link JpaRepository} instance with the given {@link EntityManager}
	 *
	 * @param information will never be {@literal null}.
	 * @param entityManager will never be {@literal null}.
	 * @return*/ protected JpaRepositoryImplementation<? ,? > getTargetRepository(RepositoryInformation information, EntityManager entityManager) { JpaEntityInformation<? , Serializable> entityInformation = getEntityInformation(information.getDomainType()); Object repository = getTargetRepositoryViaReflection(information, entityInformation, entityManager); Assert.isInstanceOf(JpaRepositoryImplementation.class, repository);return(JpaRepositoryImplementation<? ,? >) repository; } / /... }Copy the code
  • JpaRepositoryFactory getTargetRepository will according to create JpaRepositoryImplementation RepositoryInformation, The default is to create the SimpleJpaRepository instance

RepositoryFactorySupport

Spring – data – Commons – 2.1.6. RELEASE – sources. The jar! /org/springframework/data/repository/core/support/RepositoryFactorySupport.java

public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, BeanFactoryAware {

	//......

	/**
	 * Returns a repository instance for the given interface backed by an instance providing implementation logic for
	 * custom logic.
	 *
	 * @param repositoryInterface must not be {@literal null}.
	 * @param fragments must not be {@literal null}.
	 * @return* @since 2.0 */ @suppressWarnings ({"unchecked" })
	public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) {

		if (LOG.isDebugEnabled()) {
			LOG.debug("Initializing repository instance for {}...", repositoryInterface.getName());
		}

		Assert.notNull(repositoryInterface, "Repository interface must not be null!");
		Assert.notNull(fragments, "RepositoryFragments must not be null!");

		RepositoryMetadata metadata = getRepositoryMetadata(repositoryInterface);
		RepositoryComposition composition = getRepositoryComposition(metadata, fragments);
		RepositoryInformation information = getRepositoryInformation(metadata, composition);

		validate(information, composition);

		Object target = getTargetRepository(information);

		// Create proxy
		ProxyFactory result = new ProxyFactory();
		result.setTarget(target);
		result.setInterfaces(repositoryInterface, Repository.class, TransactionalProxy.class);

		if (MethodInvocationValidator.supports(repositoryInterface)) {
			result.addAdvice(new MethodInvocationValidator());
		}

		result.addAdvice(SurroundingTransactionDetectorMethodInterceptor.INSTANCE);
		result.addAdvisor(ExposeInvocationInterceptor.ADVISOR);

		postProcessors.forEach(processor -> processor.postProcess(result, information));

		result.addAdvice(new DefaultMethodInvokingMethodInterceptor());

		ProjectionFactory projectionFactory = getProjectionFactory(classLoader, beanFactory);
		result.addAdvice(new QueryExecutorMethodInterceptor(information, projectionFactory));

		composition = composition.append(RepositoryFragment.implemented(target));
		result.addAdvice(new ImplementationMethodExecutionInterceptor(composition));

		T repository = (T) result.getProxy(classLoader);

		if (LOG.isDebugEnabled()) {
			LOG.debug("Finished creation of repository instance for {}.", repositoryInterface.getName());
		}

		returnrepository; } / /... }Copy the code
  • After RepositoryFactorySupport’s getRepository method creates the SimpleJpaRepository instance by calling the subclass’s getTargetRepository, it proxies it, Set its interface to user-defined DAO interface, Repository, TransactionalProxy, And add the SurroundingTransactionDetectorMethodInterceptor, DefaultMethodInvokingMethodInterceptor, QueryExecutorMethodIntercepto R, ImplementationMethodExecutionInterceptor MethodInterceptor, finally produce the final implementation class

summary

  • Inherited JpaRepository and JpaSpecificationExecutor JpaRepositoryImplementation interface, it is JpaRepository interface implementation class of SPI interface; It defines the setRepositoryMethodMetadata method
  • Realizing SimpleJpaRepository JpaRepositoryImplementation interface, it is the default implementation CrudRepository; Its constructors all require passing in an EntityManager; Can see from the various methods will SimpleJpaRepository is the method of using EntityManager to accomplish specific functions, to many query function with the aid of applySpecificationToCriteria method, Translate the Specification of Spring Data into the CriteriaQuery of Javax. persistence
  • JpaRepositoryFactory getTargetRepository will according to create JpaRepositoryImplementation RepositoryInformation, The default is to create the SimpleJpaRepository instance; After RepositoryFactorySupport’s getRepository method creates the SimpleJpaRepository instance by calling the subclass’s getTargetRepository, it proxies it, Set its interface to user-defined DAO interface, Repository, TransactionalProxy, And add the SurroundingTransactionDetectorMethodInterceptor, DefaultMethodInvokingMethodInterceptor, QueryExecutorMethodIntercepto R, ImplementationMethodExecutionInterceptor MethodInterceptor, finally produce the final implementation class

doc

  • SimpleJpaRepository
  • SimpleJpaRepository.java
  • Customizing Spring Data JPA Repository
  • Spring Data JPA – Adding a Method in All Repositories
  • Spring Data JPA Tutorial: Adding Custom Methods to All Repositories