JpaRepositoryFactoryBean

JpaRepositoryFactory

JpaRepositoryConfigurationExtension

스프링 데이터는 리포지토리 스캔 및 등록 과정을 추상화하여 공통 로직으로 처리하면서, 각 데이터 모듈 별 확장 설정을 할 수 있는 RepositoryConfigurationExtension 인터페이스를 제공한다

스프링 데이터 JPA는 JpaRepositoryConfigurationExtension을 통해 리포지토리 자동 생성 과정에서 스프링 데이터 JPA만의 확장 설정을 진행한다

JpaRepositoryConfigurationExtension에서 등록하는 빈 목록

필드

/* -------------- 문자열 전역 상수 필드 --------------*/
private static final Class<?> PAB_POST_PROCESSOR = PersistenceAnnotationBeanPostProcessor.class;
private static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
private static final String ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE = "enableDefaultTransactions";
private static final String JPA_METAMODEL_CACHE_CLEANUP_CLASSNAME = "org.springframework.data.jpa.util.JpaMetamodelCacheCleanup";
private static final String ESCAPE_CHARACTER_PROPERTY = "escapeCharacter";

/* -------------- 필드 --------------*/
private final Map<Object, String> entityManagerRefs = new LinkedHashMap<>();

정보 제공 구현 메서드

RepositoryConfigurationExtension 구현 메서드

// 스프링 데이터 JPA 모듈 이름 반환(jpa)
@Override
public String getModuleName() {
    return "JPA";
}

// RepositoryFactoryBean 구현체 이름 반환
@Override
public String getRepositoryFactoryBeanClassName() {
    return JpaRepositoryFactoryBean.class.getName();
}

@Override
protected String getModulePrefix() {
    return getModuleName().toLowerCase(Locale.US);
}

// 리포지토리 인터페이스를 평가할 때 스캔해야 될 도메인 타입 어노테이션 반환
// @Entity @MappedSuperClass
@Override
protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
    return Arrays.asList(Entity.class, MappedSuperclass.class);
}

// 엄격하게 리포지토리 매치를 할 때 매치돼야 할 리포지토리 인터페이스 타입 반환
// JpaRepository
@Override
protected Collection<Class<?>> getIdentifyingTypes() {
    return Collections.<Class<?>> singleton(JpaRepository.class);
}

// aot 컴파일러 관련
@Override
public Class<? extends BeanRegistrationAotProcessor> getRepositoryAotProcessor() {
    return JpaRepositoryRegistrationAotProcessor.class;
}

빈 등록 구현 메서드

RepositoryConfigurationExtension.registerBeansForRoot와 postProcess 구현

SharedEntityManagerCreator 및 스프링 데이터 JPA 관련 빈들을 등록함

registerIfNotAlreadyRegistered

@Override
public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource config) {

    super.registerBeansForRoot(registry, config);

    // SharedEntityManagerCreator
    registerSharedEntityMangerIfNotAlreadyRegistered(registry, config);

    Object source = config.getSource();

    /* ------------------ spring data jpa 관련 빈 등록 ------------------ */
    
    registerLazyIfNotAlreadyRegistered(
            () -> new RootBeanDefinition(EntityManagerBeanDefinitionRegistrarPostProcessor.class), registry,
            EM_BEAN_DEFINITION_REGISTRAR_POST_PROCESSOR_BEAN_NAME, source);

    registerLazyIfNotAlreadyRegistered(() -> new RootBeanDefinition(JpaMetamodelMappingContextFactoryBean.class),
            registry, JPA_MAPPING_CONTEXT_BEAN_NAME, source);

    registerLazyIfNotAlreadyRegistered(() -> new RootBeanDefinition(PAB_POST_PROCESSOR), registry,
            AnnotationConfigUtils.PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME, source);

    registerLazyIfNotAlreadyRegistered(() -> {

        RootBeanDefinition contextDefinition = new RootBeanDefinition(DefaultJpaContext.class);
        contextDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);

        return contextDefinition;

    }, registry, JPA_CONTEXT_BEAN_NAME, source);

    registerIfNotAlreadyRegistered(() -> new RootBeanDefinition(JPA_METAMODEL_CACHE_CLEANUP_CLASSNAME), registry,
            JPA_METAMODEL_CACHE_CLEANUP_CLASSNAME, source);

    registerIfNotAlreadyRegistered(() -> {

        Object value = config instanceof AnnotationRepositoryConfigurationSource //
                ? config.getRequiredAttribute(ESCAPE_CHARACTER_PROPERTY, Character.class) //
                : config.getAttribute(ESCAPE_CHARACTER_PROPERTY).orElse("\\");

        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(JpaEvaluationContextExtension.class);
        builder.addConstructorArgValue(value);

        return builder.getBeanDefinition();

    }, registry, JpaEvaluationContextExtension.class.getName(), source);
}