스프링/5. 스프링 DB-1

29. 스프링 부트 자동 리소스 등록

sdafdq 2023. 10. 1. 21:53

스프링 부트가 자동으로 등록해 주는 게 꽤 많이 있다.

그 중

DataSource

이름 : dataSource

 

이것도 자동으로 등록된다. 물론 개발자가 직접 DataSource를 빈으로 등록하면 이 기본은 등록되지 않는다.

 

근데 우리가 이거 등록할 때는, URL, 아이디, 패스워드 이런 거 다 넣어 줬었다.

근데, 자동으로 등록할 때에는 이런 정보들을 application.properties에 쓰면 된다.

spring.datasource.url=jdbc:h2:tcp://localhost/./test
spring.datasource.username=sa
spring.datasource.password=1234

물론, 기타, 커넥션 풀 관련 설정이라던지도 저기다 쓰면 된다.

만약 url을 명시하지 않았다면, 내장 DB(메모리DB)를 생성하려고 시도한다.

 

스프링 부트가 기본으로 등록하면 데이터소스는 커넥션풀을 제공하는 HikariDataSource이다.

 

 

또, 트랜잭션 매니저도 자동으로 등록해 준다. 

트랜잭션 매니저에 필요한 DataSource도 자동으로 등록해주고, 그것이 필요한 트랜잭션 매니저도 자동으로 등록해주니 편리하다.

이름 : transactionManager

뭔가 기본적으로 등록되는 것의 이름들은 소문자로 시작하는 최상위..? 라기 보다는 좀.. 종류의 많이 받아 들일 수 있는 상위에 있는 인터페이스의 이름을 소문자로 시작하는 것 같다. 이름이.

 

마찬가지로 개발자가 트랜잭션매니저를 등록하면 자동등록 하지 않는다.

 

스프링 기본 매커니즘이 자동 등록 되어지는 것들 중 개발자가 뭔가 등록하면 그 종류에 맞춘 자동등록 되어지는 것을 등록하지 않는다.

 

자동등록 되어질 때, 사용하는 라이브러리를 보고 판단하는데, 만약 JDBC 기술을 사용하면 DataSourceTransactionManager를 빈으로 등록하고, JPA 라이브러리로 그 기술들을 사용하고 있다면 JpaTransactionManager를 빈으로 등록한다.

 

둘 다 사용하는 경우, JpaTransactionManager가 DataSourceTransactionManager의 대부분의 기능을 제공하기에, JpaTransactionManager가 자동으로 등록된다.

 

 

테스트코드

@Slf4j
@SpringBootTest
public class MemberServiceV3_4Test {
    private static final String MEMBER_A = "memberA";
    private static final String MEMBER_B = "memberB";
    private static final String MEMBER_EX = "ex";

    @Autowired
    private MemberRepositoryV3 memberRepository;

    @Autowired
    private MemberServiceV3_3 memberService;

    @TestConfiguration
    static class TestConfig{
        private final DataSource dataSource;

        public TestConfig(DataSource dataSource) {
            this.dataSource = dataSource;
        }

        @Bean
        MemberRepositoryV3 memberRepository(){
            return new MemberRepositoryV3(dataSource);
        }

        @Bean
        MemberServiceV3_3 memberSerivce(){
            return new MemberServiceV3_3(memberRepository());
        }
    }

    @AfterEach
    private void after() throws SQLException {
        memberRepository.delete(MEMBER_A);
        memberRepository.delete(MEMBER_B);
        memberRepository.delete(MEMBER_EX);
    }

    @Test
    @DisplayName("AOP 체크")
    public void aopCheck(){
        assertThat(AopUtils.isAopProxy(memberService)).isTrue();
        assertThat(AopUtils.isAopProxy(memberRepository)).isFalse();
    }

    @Test
    @DisplayName("정상 이체")
    void accountTransfer() throws SQLException {
        Member memberA = new Member(MEMBER_A, 10000);
        Member memberB = new Member(MEMBER_B, 10000);
        int transferMoney = 2000;
        memberRepository.save(memberA);
        memberRepository.save(memberB);

        memberService.accountTransfer(memberA.getMemberId(), memberB.getMemberId(), transferMoney);

        Member findedMemberA = memberRepository.findById(memberA.getMemberId());
        Member findedMemberB = memberRepository.findById(memberB.getMemberId());

        assertThat(findedMemberA.getMoney()).isEqualTo(memberA.getMoney() - transferMoney);
        assertThat(findedMemberB.getMoney()).isEqualTo(memberB.getMoney() + transferMoney);
    }

    @Test
    @DisplayName("이체 중 예외 발생")
    void accountTransferEx() throws SQLException {
        Member memberA = new Member(MEMBER_A, 10000);
        Member memberB = new Member(MEMBER_EX, 10000);
        int transferMoney = 2000;
        memberRepository.save(memberA);
        memberRepository.save(memberB);

        assertThatThrownBy(()->memberService.accountTransfer(memberA.getMemberId(), memberB.getMemberId(), transferMoney))
                .isInstanceOf(IllegalStateException.class);

        Member findedMemberA = memberRepository.findById(memberA.getMemberId());
        Member findedMemberB = memberRepository.findById(memberB.getMemberId());

        assertThat(findedMemberA.getMoney()).isEqualTo(memberA.getMoney());
        assertThat(findedMemberB.getMoney()).isEqualTo(memberB.getMoney());
    }
}

긴데, 우리가 볼 부분은 @TestConfiguration 이 부분이다.

보면 우리가 DataSource나 TransactionManager를 등록해 주지 않아도 정상적으로 작동이 된다.

 

dataSource는 우리가 의존관계 주입할 때도 사용하여야 하므로, 생성자로 해서 주입받았다.

이름이 주입받을 객체 이름이 dataSource라 스프링 빈 이름이 dataSource인 것이 주입될 것이다.

물론 생성자로 안하고, @AutoWired로 해도 된다.

 

 

application.properties의 여러 설정들

https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#appendix.application-properties.core

'스프링 > 5. 스프링 DB-1' 카테고리의 다른 글

31. 예외 기본 규칙  (0) 2023.10.02
30. 자바 예외  (0) 2023.10.02
28. 트랜잭션 AOP 적용.  (0) 2023.10.01
27. 트랜잭션 AOP  (0) 2023.10.01
26. 트랜잭션 템플릿  (0) 2023.10.01