스프링 부트(핵심 원리와 활용)

Ch04. 자동 구성(Auto Configuration) - 예제 만들기

webmaster 2023. 3. 8. 23:47
728x90

build.gradle

plugins {
    id 'org.springframework.boot' version '3.0.2'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'hello'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    //테스트에서 lombok 사용
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
}

tasks.named('test') {
    useJUnitPlatform()
}
  • 스프링 부트에서 다음 라이브러리를 선택했다.
    • Lombok , Spring Web , H2 Database , JDBC API
  • 테스트 코드에서 lombok을 사용할 수 있도록 설정을 추가했다.

예제 만들기

스프링 부트가 제공하는 자동 구성(Auto Configuration)을 이해하기 위해 간단한 예제를 만들어보자. JdbcTemplate을 사용해서 회원 데이터를 DB에 저장하고 조회하는 간단한 기능이다.

Member

@Data
public class Member {

  private String memberId;
  private String name;

  public Member() {
  }

  public Member(String memberId, String name) {
    this.memberId = memberId;
    this.name = name;
  }
}
  • memberId , name 필드가 있는 간단한 회원 객체이다.
  • 기본 생성자, memberId, name 을 포함하는 생성자 이렇게 2개의 생성자를 만들었다.

DbConfig

@Slf4j
@Configuration
public class DbConfig {

  @Bean
  public DataSource dataSource() {
    log.info("dataSource 빈 등록");
    HikariDataSource dataSource = new HikariDataSource();
    dataSource.setDriverClassName("org.h2.Driver");
    dataSource.setJdbcUrl("jdbc:h2:mem:test");
    dataSource.setUsername("sa");
    dataSource.setPassword("");
    return dataSource;
  }

  @Bean
  public TransactionManager transactionManager(){
    log.info("transactionManager 빈 등록");
    return new JdbcTransactionManager(dataSource());
  }

  @Bean
  public JdbcTemplate jdbcTemplate(){
    log.info("jdbcTemplate 빈 등록");
    return new JdbcTemplate(dataSource());
  }

}
  • JdbcTemplate 을 사용해서 회원 데이터를 DB에 보관하고 관리하는 기능이다.
  • DataSource , TransactionManager , JdbcTemplate 을 스프링 빈으로 직접 등록한다.
  • 빈 등록이 실제 호출되는지 확인하기 위해 로그를 남겨두었다.
  • DB는 별도의 외부 DB가 아니라 JVM 내부에서 동작하는 메모리 DB를 사용한다.
    • 메모리 모드로 동작 옵선: jdbc:h2:mem:test
  • JdbcTransactionManager 는 DataSourceTransactionManager 와 같은 것으로 생각하면 된다. 여기에 예외 변환 기능이 보강되었다.

MemberRepository

@Repository
public class MemberRepository {

  public final JdbcTemplate template;

  public MemberRepository(JdbcTemplate template) {
    this.template = template;
  }

  public void initTable() {
    template.execute("create table member(member_id varchar primary key, name varchar)");
  }

  public void save(Member member) {
    template.update("insert into member(member_id, name) values (?, ?)",
        member.getMemberId(),
        member.getName());
  }

  public Member find(String memberId) {
    return template.queryForObject("select member_id, name from member where member_id=?",
        BeanPropertyRowMapper.newInstance(Member.class),
        memberId
    );
  }

  public List<Member> findAll() {
    return template.query("select member_id, name from member",
        BeanPropertyRowMapper.newInstance(Member.class));
  }
}
  • JdbcTemplate 을 사용해서 회원을 관리하는 리포지토리이다.
  • DbConfig 에서 JdbcTemplate 을 빈으로 등록했기 때문에 바로 주입받아서 사용할 수 있다.
  • initTable : 보통 리포지토리에 테이블을 생성하는 스크립트를 두지는 않는다. 여기서는 예제를 단순화하기 위해 이곳에 사용했다.

MemberRepositoryTest

@SpringBootTest
public class MemberRepositoryTest {

  @Autowired MemberRepository memberRepository;


  @Transactional
  @Test
  public void memberTest(){
    Member member = new Member("idA", "memberA");
    memberRepository.initTable();

    memberRepository.save(member);
    Member findMember = memberRepository.find(member.getMemberId());
    Assertions.assertThat(findMember.getMemberId()).isEqualTo(member.getMemberId());
    Assertions.assertThat(findMember.getName()).isEqualTo(member.getName());
  }
}
  • @Transactional 을 사용해서 트랜잭션 기능을 적용했다.
    • 참고로 @Transactional 을 사용하려면 TransactionManager 가 스프링 빈으로 등록되어 있어야 한다.
  • 테이블을 생성하고, 회원 데이터를 저장한 다음 다시 조회해서, 기존 데이터와 같은지 간단히 검증한다

정리

회원 데이터를 DB에 보관하고 관리하기 위해 앞서 빈으로 등록한 JdbcTemplate , DataSource , TransactionManager 가 모두 사용되었다.

그런데 생각해 보면 DB에 데이터를 보관하고 관리하기 위해 이런 객체들을 항상 스프링 빈으로 등록해야 하는 번거로움이 있다.

만약 DB를 사용하는 다른 프로젝트를 진행한다면 이러한 객체들을 또 스프링 빈으로 등록해야 할 것이다.

728x90