Spring Data ๊ด๋ จ ํด๋์ค ์ ๋ฆฌ
Spring Data ๋?
Spring ํ๋ ์์ํฌ์ ํ์ ํ๋ก์ ํธ ์ค ํ๋๋ก ๋ชจ๋ธ์ ๊ธฐ๋ฐ์ผ๋ก ๋ค์ํ ๋ฐ์ดํฐ ์ ๊ทผ ๊ธฐ์ ์ ์ง์ํ๋ค.
Repository ์ธํฐํ์ด์ค๋ฅผ ํตํด ๊ฐ์ฒด ๋งคํ์ ์ถ์ํ ํํ๋ก ์ง์ํ๊ธฐ ๋๋ฌธ์ ์ข ๋ ์ฝ๊ฒ ๋ฐ์ดํฐ์ ์ ๊ทผ ๋ฐ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
Main Module
- Spring Data Commons : ๋ชจ๋ Spring Module์ ๋ท๋ฐ์นจํ๋ ํต์ฌ Spring ๊ฐ๋
- CrudRepository, PagingAndSortingRepository
- Spring Data JDBC : spring-jdbc์ ๋ํ Spring Data ์ถ์ํ๋ฅผ ์ ๊ณตํ๋ ๋ชจ๋
- CrudRepository๋ฅผ ๊ตฌํํ๋ SimpleJdbcRepository ํด๋์ค
- Spring Data JPA : JPA๋ฅผ ์ํ ์คํ๋ง ๋ฐ์ดํฐ ์ ์ฅ์ ์ง์
- JpaRepository ์ธํฐํ์ด์ค, SimpleJpaRepository ํด๋์ค
- Spring Data R2dbc : R2dbc ๋ฅผ ์ํ ์คํ๋ง ๋ฐ์ดํฐ ์ ์ฅ์ ์ง์
- R2dbcRepository ์ธํฐํ์ด์ค, SimpleR2dbcRepository ํด๋์ค
- Spring Data REST
- Spring Data Redis
- Spring Data MongoDB
- ...
๋ฑ ๋ค์ํ ๋ชจ๋์ ์ง์ํ๋ค.
๊ทธ ์ธ์ ๋ชจ๋์ ์๋ ๊ณต์ ๋ฌธ์๋ฅผ ํตํด ํ์ธ์ด ๊ฐ๋ฅํ๋ค.
https://spring.io/projects/spring-data#overview
Spring ์ ๊ฐ๋ฐ์๊ฐ ์ฌ์ฉํ๊ธฐ ์ฌ์ด ํํ๋ก Repository๋ฅผ ์ธํฐํ์ด์ค ํํ๋ก ์ถ์ํํ์ฌ ์ ๊ณตํ๋ค.
์ด๋ ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ํ์ ์ธ ํด๋์ค๋ค์ ๋ช ๊ฐ ์์๋ณด๊ณ ์ ํ๋ค.
RepositoryFactorySupport ์ถ์ ํด๋์ค
- ์ฃผ์ด์ง Repository ์ธํฐํ์ด์ค์ ์ค์ ํ๋ก์ ์ธ์คํด์ค๋ฅผ ์์ฑ
- ์ด ์ถ์ ํด๋์ค๋ฅผ ํ์ฅํ์ฌ ๋ค์ํ spring-data-xxx ์์ Repository๋ฅผ ์์ฑ
- getRepository ํจ์์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌํํ repository ์ธํฐํ์ด์ค๋ฅผ ์ธ์๋ก ๋ฐ์ ๋ด๋ถ์ ์ผ๋ก proxy ๋ฅผ ์์ฑํ๊ณ ์ธ์คํด์ค๋ฅผ ๋ฐํ
public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, BeanFactoryAware {
public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) {
... (์๋ต)
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.addAdvisor(ExposeInvocationInterceptor.ADVISOR);
postProcessors.forEach(processor -> processor.postProcess(result, information));
if (DefaultMethodInvokingMethodInterceptor.hasDefaultMethods(repositoryInterface)) {
result.addAdvice(new DefaultMethodInvokingMethodInterceptor());
}
ProjectionFactory projectionFactory = getProjectionFactory(classLoader, beanFactory);
Optional<QueryLookupStrategy> queryLookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey,
evaluationContextProvider);
result.addAdvice(new QueryExecutorMethodInterceptor(information, projectionFactory, queryLookupStrategy,
namedQueries, queryPostProcessors));
composition = composition.append(RepositoryFragment.implemented(target));
result.addAdvice(new ImplementationMethodExecutionInterceptor(composition));
T repository = (T) result.getProxy(classLoader);
... (์๋ต)
return repository;
}
RepositoryFactorySupport ์์ ํด๋์ค ์์
JpaRepositoryFactory
- ๋ด๋ถ์ ์ผ๋ก SimpleJpaRepository(๊ตฌํ์ฒด) ๋ฐํ
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return SimpleJpaRepository.class;
}
- JpaRepositoryFactoryBean ํด๋์ค๋ฅผ ํตํด RepositoryFactory ๊ฐ์ฒด ์์ฑ ๋ฐ entityManager ์ฃผ์ (RepositoryFactoryBeanSupport ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด Factory ์ปค์คํ ๋ ๊ฐ๋ฅํ๋ค.)
R2dbcRepositoryFactory
- ๋ด๋ถ์ ์ผ๋ก SimpleR2dbcRepository(๊ตฌํ์ฒด) ๋ฐํ
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return SimpleR2dbcRepository.class;
}
Repository ์ปค์คํ ํ๊ธฐ
1. RepositoryFactorySupport ํ์ ์ปค์คํ Factory ํด๋์ค ๊ตฌํ
2. RepositoryFactoryBeanSupport ์ ํ์ ์ธํฐํ์ด์ค๋ค์ด ์กด์ฌ.
- ํด๋น Bean์ ์์๋ฐ์ getFactoryInstance๋ฅผ ์ค๋ฒ๋ผ์ด๋ํ์ฌ RepositoryFactory ๋ฅผ ๋ณ๊ฒฝํด์ค ์ ์๋ค.
ex) JPARepositoryFactoryBean, R2dbcRepositoryFactoryBean ..
3. RepositoryFactoryBeanSupport ํด๋์ค ๋๋ ํ์ ํด๋์ค ์์๋ฐ์ ๊ตฌ์ฒด์ ์ธ ํ๋ก์ ์ธ์คํด์ค ์์ฑ
4. getFactoryInstance ํจ์์ ์ปค์คํ ํ Factory ํด๋์ค๋ฅผ ๋ฐํ
class CustomRepositoryFactoryBean<T : Repository<S, ID>, S, ID : Serializable>(
repositoryInterface: Class<T>
) : R2dbcRepositoryFactoryBean<T, S, ID>(repositoryInterface) {
override fun setMappingContext(mappingContext: MappingContext<*, *>) {
super.setMappingContext(mappingContext)
}
override fun getFactoryInstance(operations: R2dbcEntityOperations): RepositoryFactorySupport {
return CustomRepositoryFactory(operations)
}
}
/*
* Ex) R2dbcRepository๋ฅผ ์ปค์คํ
ํ๋ค๋ฉด
*/
class CustomRepositoryFactory(
operations: R2dbcEntityOperations
) : R2dbcRepositoryFactory(operations) {
override fun getRepositoryBaseClass(metadata: RepositoryMetadata): Class<*> {
// ์ปค์คํ
ํ Repository ๊ตฌํ์ฒด (๋ฐํ์์ ๋์ ์ผ๋ก ์คํ๋ Repository ๊ตฌํ์ฒด)
return R2dbcCoroutineRepository::class.java
}
}
์ฐธ๊ณ
https://imbf.github.io/spring/2020/04/30/Spring-Data.html
https://brunch.co.kr/@anonymdevoo/40