3. ํ์ ๊ด๋ฆฌ ์์ - ๋ฐฑ์๋ ๊ฐ๋ฐ
๋น์ฆ๋์ค ์๊ตฌ์ฌํญ
- ๋ฐ์ดํฐ : ํ์ ID, ์ด๋ฆ
- ๊ธฐ๋ฅ : ํ์ ๋ฑ๋ก, ์กฐํ
- ์์ง ๋ฐ์ดํฐ ์ ์ฅ์๊ฐ ์ ์ ๋์ง ์์
์ผ๋ฐ์ ์ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ณ์ธต ๊ตฌ์กฐ
- ์ปจํธ๋กค๋ฌ : ์น MVC์ ์ปจํธ๋กค๋ฌ ์ญํ
- ์๋น์ค : ํต์ฌ ๋น์ฆ๋์ค ๋ก์ง ๊ตฌํ
- ๋ ํฌ์งํ ๋ฆฌ : ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผ, ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ DB์ ์ ์ฅํ๊ณ ๊ด๋ฆฌ
- ๋๋ฉ์ธ : ๋น์ฆ๋์ค
ํด๋์ค ์์กด ๊ด๊ณ
ํ์์ ์ ์ฅํ๋ ๊ฒ์ Repository ์ธํฐํ์ด์ค.
์ผ๋จ์ ๋ฉ๋ชจ๋ฆฌ ๊ตฌํ์ฒด.
DBMS๋ฅผ ์์ ๋กญ๊ฒ ๋ฐ๊ฟ ๋ผ์ฐ๊ธฐ ์ํด ์ธํฐํ์ด์ค๋ก ๊ตฌํํ์์.
Member Domain
public class Member {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
MemberRepository
public interface MemberRepository {
Member save(Member member);
Optional<Member> findById(Long id);
Optional<Member> findByNames(String name);
List<Member> findAll();
}
findById()
,findByNames()
์ null์ ๋ฐํํ ์ ์์ผ๋ Optional๋ก ๊ฐ์ธ์ ๋ฐํํ๋ค.
MemoryMemberRepository
public class MemoryMemberRepository implements MemberRepository {
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
@Override
public Member save(Member member) {
member.setId(++sequence);
store.put(member.getId(), member);
return member;
}
@Override
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id)); // null์ด์ด๋ ๊ฐ์ ์ ์๋ค. ํด๋ผ์์ ๋ฌด์ธ๊ฐ ํ ์ ์
}
@Override
public Optional<Member> findByNames(String name) {
return store.values().stream()
.filter(member -> member.getName().equals(name))
.findAny(); // ๋ฃจํ๋ฅผ ๋๋ฉด์ ์์ผ๋ฉด optional์ null์ด ํฌํจ๋์ ๋ฐํ
}
@Override
public List<Member> findAll() {
return new ArrayList<>(store.values());
}
}
MemoryMemberRepositoryTest
public class MemoryMemberRepositoryTest {
MemoryMemberRepository repository = new MemoryMemberRepository();
@Test
void save() {
Member member = new Member();
member.setName("spring");
repository.save(member);
Member result = repository.findById(member.getId()).get();
assertThat(member).isEqualTo(result);
}
@Test
void findByName() {
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
Member result = repository.findByNames("spring1").get();
assertThat(result).isEqualTo(member1);
}
@Test
void findAll() {
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
}
}
๋ชจ๋ ํ
์คํธ๋ ๋ฉ์๋๋ง๋ค ๋
๋ฆฝ์ ์ผ๋ก ์คํ๋์ด์ผ ํ๋ค.
์์์ ์์กด๋๊ฐ ์๊ธฐ๋ฉด ์๋๋ค.
@AfterEach
void afterAll() {
repository.clearStore();
}
๋๋ฌธ์ ํ๋์ ํ ์คํธ๊ฐ ์คํ๋ ๋ ๋ง๋ค ์ด๊ธฐํ๋ฅผ ์งํํด์ค๋ค.
ํ ์คํธ ์ฝ๋์์ด ๊ฐ๋ฐ์ ๋ถ๊ฐ๋ฅํ๋ค.
MemberService
public class MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
public long join(Member member) {
validateDuplicatedMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicatedMember(Member member) {
// ์ค๋ณต ํ์์ ์๋๋ค.
memberRepository.findByNames(member.getName())
.ifPresent(m -> {
throw new IllegalArgumentException("์ด๋ฏธ ์กด์ฌํ๋ ํ์์
๋๋ค.");
});
}
public List<Member> findMembers() {
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId) {
return memberRepository.findById(memberId);
}
}
ํ์ง๋ง Optional์ ๋ฐ๋ก ๋ฐํํ๋ ๊ฒ์ ์ข์ง ์๋ค.
// ์ค๋ณต ํ์์ ์๋๋ค.
memberRepository.findByNames(member.getName())
.ifPresent(m -> {
throw new IllegalArgumentException("์ด๋ฏธ ์กด์ฌํ๋ ํ์์
๋๋ค.");
});
ifPresent()
๋ฅผ ์ฌ์ฉํด ๋ฐ๋ก ํ์ธ.
- ์๋น์ค ํด๋์ค๋ ๋น์ฆ๋์ค์ ์ธ ๋ค์ด๋ฐ์ ์จ์ผํ๋ค.
๊ทธ๋ฐ๋ฐ ์๋น์ค ํ
์คํธ์ ๋ ํฌ์งํ ๋ฆฌ ํ
์คํธ์์ ๊ฐ๊ฐ์ MemoryMemberRepository ์ธ์คํด์ค๋ฅผ ์์ฑํด ํ
์คํธํ๊ณ ์๋ค.
ํ์ฌ๋ static์ผ๋ก ์ ์ธ๋์ด ์์ง๋ง, ์ด์น์ ๋ง์ง ์๋ ํ์.
์์ฑ์๋ฅผ ํตํด ์ธ๋ถ์์ ์ฃผ์
ํ๋๋ก ํ๋ค.
์์ฑ์ ์ฃผ์ (DI)
@BeforeEach
void beforeEach() {
memberRepository = new MemoryMemberRepository();
memberService = new MemberService(memberRepository);
}
๊ฐ ํ ์คํธ ์คํ ์ ์ ํธ์ถ๋๋ฉฐ ํ ์คํธ๊ฐ ์๋ก ์ํฅ ์์ด ํญ์ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์์กด๊ด๊ณ๋ ์๋ก ๋งบ์ด์ค๋ค.
Controller ์์ ์์ฒญ์ ๋ฐ๊ณ , Service์์ ๋น์ฆ๋์ค ๋ก์ง์ ์ฒ๋ฆฌํ๊ณ , Repository์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ์ด๊ฒ ์ ํํ๋ ๋ก์ง์ด๋ค.
์คํ๋ง์ด ๊ด๋ฆฌ๋ฅผ ํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์
์ด ํฌํจ๋ ํ์ ํจํค์ง ๋ด์์ ์คํ๋ง์ด ์ปดํฌ๋ํธ๋ฅผ ์ค์บํ๋ค.
์คํ๋ง์ ์คํ๋ง ์ปจํ
์ด๋์ ์คํ๋ง ๋น์ ๋ฑ๋กํ ๋, ๊ธฐ๋ณธ์ผ๋ก ์ฑ๊ธํค์ผ๋ก ๋ฑ๋กํ๋ค. (๋ฉ๋ชจ๋ฆฌ๋ ์ ์ฝ๋๋ค.)
4. ์คํ๋ง ๋น๊ณผ ์์กด๊ด๊ณ
์ปดํฌ๋ํธ ์ค์บ๊ณผ ์๋ ์์กด๊ด๊ณ ์ค์
์์ฑ์์ @Autowired
๊ฐ ์์ผ๋ฉด ์คํ๋ง์ด ์ฐ๊ด๋ ๊ฐ์ฒด๋ฅผ ์คํ๋ง ์ปจํ
์ด๋์์ ์ฐพ์์ ๋ฃ์ด์ค๋ค.
๊ฐ์ฒด ์์กด ๊ด๊ณ๋ฅผ ์ธ๋ถ์์ ๋ฃ์ด์ฃผ๋ ๊ฒ์ DI๋ผ๊ณ ํ๋ค.
์คํ๋ง ๋น์ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ
- ์ปดํฌ๋ํธ ์ค์บ๊ณผ ์๋ ์์กด๊ด๊ณ ์ค์
- ์๋ฐ ์ฝ๋๋ก ์ง์ ์คํ๋ง ๋น ๋ฑ๋กํ๊ธฐ
@Component
๊ฐ ์์ผ๋ฉด ์คํ๋ง ๋น์ผ๋ก ์๋ ๋ฑ๋ก๋๋ค. (@Controller, @Service, @Repository).
์์ฑ์์ @Autowired
๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด ์์ฑ ์์ ์ ์คํ๋ง ์ปจํ
์ด๋์์ ํด๋น ์คํ๋ง ๋น์ ์ฐพ์์ ์ฃผ์
ํ๋ค.
์์ฑ์๊ฐ 1๊ฐ๋ง ์์ผ๋ฉด @Autowired
๋ ์๋ต ๊ฐ๋ฅํ๋ค.
์คํ๋ง์ ์คํ๋ง ๋น์ ๋ฑ๋กํ ๋ ๊ธฐ๋ณธ์ผ๋ก ์ฑ๊ธํค์ผ๋ก ๋ฑ๋กํ๋ค. (์ ์ผํ๊ฒ ํ๋๋ง ๋ฑ๋ก).
๋ฐ๋ผ์ ๊ฐ์ ์คํ๋ง ๋น์ด๋ฉด ๋ชจ๋ ๊ฐ์ ์ธ์คํด์ค๋ค.
@Autowired
๋ฅผ ํตํ DI๋ ์คํ๋ง์ด ๊ด๋ฆฌํ๋ ๊ฐ์ฒด(๋น)์์๋ง ๋์ํ๋ค.
DI์๋ ํ๋ ์ฃผ์
, setter ์ฃผ์
, ์์ฑ์ ์ฃผ์
3๊ฐ์ง๊ฐ ์๋๋ฐ,
์์กด ๊ด๊ณ๊ฐ ๋์ ์ผ๋ก ๋ณํ๋ ๊ฒฝ์ฐ๋ ๊ฑฐ์ ์์ผ๋ฏ๋ก ์์ฑ์ ์ฃผ์
์ ๊ถ์ฅํ๋ค.
5. ํ์ ๊ด๋ฆฌ ์์ - ์น MVC ๊ฐ๋ฐ
์์ฒญ์ด ์ฌ ๊ฒฝ์ฐ ์คํ๋ง ์ปจํ ์ด๋์์ ์ปจํธ๋กค๋ฌ๋ฅผ ์ฐพ๊ณ ์์ผ๋ฉด static ํ์ผ์ ์ฐพ๋๋ค.
6. ์คํ๋ง DB ์ ๊ทผ ๊ธฐ์
jdbc๋ง ์ฌ์ฉํ ๊ฒฝ์ฐ ์ค๋ณต์ด ๋๋ฌด ๋ง์ผ๋ spring์์๋ jdbc templates๋ฅผ ์ ๊ณตํ๋ค.
sql์ ๋ค๋ฃจ์ง ์๊ณ , ์ฟผ๋ฆฌ ์์ด ๊ฐ์ฒด๋ฅผ db์ ์ ์ฅํ ์ ์๋ค.
jpa๋ฅผ ํธ๋ฆฌํ๊ฒ ์ธ ์ ์๋๋ก ๊ฐ์ผ ๊ฒ์ด ์คํ๋ง JPA
SOLID - ๊ฐ๋ฐฉ ํ์ ์์น(OCP)
ํ์ฅ์๋ ์ด๋ ค์๊ณ , ์์ ๊ณผ ๋ณ๊ฒฝ์๋ ๋ซํ์๋ค.
์คํ๋ง์ DI๋ฅผ ์ฌ์ฉํ๋ฉด ๊ธฐ์กด ์ฝ๋๋ ์ ํ ์๋์ง ์๊ณ , ์ค์ ๋ง์ผ๋ก ๊ตฌํ ํด๋์ค๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค.
์คํ๋ง ํตํฉ ํ ์คํธ
์ง๊ธ๊น์ง๋ ์์ ์๋ฐ ์ฝ๋๋ง์ผ๋ก ํ
์คํธ๋ฅผ ์งํํ๋๋ฐ,
์คํ๋ง ๋ถํธ๊ฐ ๋ชจ๋ ์ ๋ณด๊ฐ ๋ค๊ณ ์์ผ๋ ์คํ๋ง ์ปจํ
์ด๋์ DB๊น์ง ์ฐ๊ฒฐํ ํตํฉ ํ
์คํธ๋ฅผ ์งํํด์ผ ํ๋ค.
์คํ๋ง ํตํฉ ํ
์คํธ๋ DI๊ฐ ์๋ ํ๋ ์ธ์ ์
์ ์ฌ์ฉํ๋ค.
ํ
์คํธ๋ฅผ ๋ค๋ฅธ๋ฐ์๋ ์ฐ์ด๋ ๊ฒ์ด ์๋๋ผ ํ ํด๋์ค ๋ด์์ ์ฌ์ฉํ๊ณ ๋์ด๊ธฐ ๋๋ฌธ์ด๋ค.
@SpringBootTest
@Transactional
public class MemberServiceIntegrationTest {
@Autowired
MemberService memberService;
@Autowired
MemberRepository memberRepository;
@Test
void ํ์๊ฐ์
() {
// given
Member member = new Member();
member.setName("hello");
// when
Long saveId = memberService.join(member);
// then
Member findMember = memberService.findOne(saveId).get();
assertThat(member.getName()).isEqualTo(findMember.getName());
}
@Test
void ์ค๋ณตํ์์์ธ() {
//given
Member member1 = new Member();
member1.setName("spring");
Member member2 = new Member();
member2.setName("spring");
// when
memberService.join(member1);
// then
assertThatThrownBy(() -> {
memberService.join(member2);
}).isInstanceOf(IllegalArgumentException.class);
IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> memberService.join(member2));
assertThat(e.getMessage().equals("์ด๋ฏธ ์กด์ฌํ๋ ํ์์
๋๋ค.")).isTrue();
}
}
@SpringBootTest
: ์คํ๋ง ์ปจํ ์ด๋์ ํ ์คํธ๋ฅผ ํจ๊ป ์คํํ๋ค.@Transactional
: ๊ฐ๊ฐ์ ํ ์คํธ ์์ ์ ์ ํธ๋์ญ์ ์ ์์ํ๊ณ , ํ ์คํธ ์๋ฃ ํ์ ํญ์ ๋กค๋ฐฑํ๋ค. ์ด๋ ๊ฒ ํ๋ฉด DB์ ๋ฐ์ดํฐ๊ฐ ๋จ์ง ์์ผ๋ฏ๋ก ๋ค์ ํ ์คํธ์ ์ํฅ์ ์ฃผ์ง ์๋๋ค@Commit
: ํ ์คํธ ์ผ์ด์ค๊ฐ ๋๋๋ฉด ์ปค๋ฐํ๋ค.
JDBC Templates
JDBC Templates๋ฅผ ๋ฐ๋ก ์ฃผ์ ๋ฐ์ ์ ์๋ค.
public JdbcTemplateMemberRepository(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
JDBC Template์ ํ ํ๋ฆฟ ๋ฉ์๋ ํจํด์ด๋ค.
@Override
public Optional<Member> findById(Long id) {
List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
return result.stream().findAny();
}
private RowMapper<Member> memberRowMapper() {
return (rs, rowNum) -> {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return member;
};
}
query ์ํ ๊ฒฐ๊ณผ๋ RowMapper๋ก ๋งตํ์ ํด์ฃผ์ด์ผ ํ๋ค.
๊ฐ์ฒด ์์ฑ์ RowMapper์์ ํ๋ค.
JPA
๊ธฐ์กด์ ๋ฐ๋ณต ์ฝ๋๋ ๋ฌผ๋ก , SQL๋ JPA๊ฐ ์ง์ ๋ง๋ค์ด์ ์คํํด์ค๋ค.
SQL๊ณผ ๋ฐ์ดํฐ ์ค์ฌ์ ์ค๊ณ์์ ๊ฐ์ฒด ์ค์ฌ์ ์ค๊ณ๋ก ํจ๋ฌ๋ค์์ ์ ํ ํ ์ ์๋ค.
JPA๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ๋ฐ ์์ฐ์ฑ์ ํฌ๊ฒ ๋์ผ ์ ์๋ค.
JPA๋ ๊ฐ์ฒด์ ๊ด๊ณํ ๋ฐ์ดํฐ ๋ฒ ์ด์ค๋ฅผ ๋งตํํ๋ ORM์ด๋ค.
build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
spring-boot-starter-data-jpa ๋ ๋ด๋ถ์ jdbc ๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํฌํจํ๊ธฐ ๋๋ฌธ์ jdbc๋ ์ ๊ฑฐํด๋ ๋๋ค.
JPA๋ ์ธํฐํ์ด์ค๋ค. Hibernate๋ ์ด์ ๊ตฌํ์ฒด์ด๋ค.
Member
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
๋ฐ์ดํฐ์ id๋ฅผ ์๋์ผ๋ก ์์ฑํด์ฃผ๋ ๊ฒ์ identity ์ ๋ต์ด๋ผ๊ณ ํ๋ค.
JpaMemberRepository
@Override
public List<Member> findAll() {
return em.createQuery("select m from Member m", Member.class)
.getResultList();
}
"select m from Member m"
: jpql์ด๋ผ๋ ์ฟผ๋ฆฌ. ๊ฐ์ฒด๋ฅผ ๋์์ผ๋ก ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆฐ๋ค. ์๋์ผ๋ก ์ฟผ๋ฆฌ๋ฌธ์ด ๋๋ค.
JPA๋ฅผ ์ฌ์ฉํ๋ฉด ํญ์ Transaction์ด ์์ด์ผ ํ๋ค. ์๋น์ค ๊ณ์ธต์ ํธ๋์ญ์
์ ์ถ๊ฐํ๋ค.
์คํ๋ง์ ํด๋น ํด๋์ค์ ๋ฉ์๋๋ฅผ ์คํํ ๋ ํธ๋์ญ์
์ ์์ํ๊ณ , ๋ฉ์๋๊ฐ ์ ์ ์ข
๋ฃ๋๋ฉด ํธ๋์ญ์
์ ์ปค๋ฐํ๋ค. ๋ง์ฝ ๋ฐํ์ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ๋กค๋ฐฑํ๋ค. JPA๋ฅผ ํตํ ๋ชจ๋ ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ํธ๋์ญ์
์์์ ์คํํด์ผ ํ๋ค.
์คํ๋ง Data JPA
์คํ๋ง ๋ถํธ์ JPA๋ง ์ฌ์ฉํด๋ ๊ฐ๋ฐ ์์ฐ์ฑ์ด ์ ๋ง ๋ง์ด ์ฆ๊ฐํ๊ณ , ๊ฐ๋ฐํด์ผํ ์ฝ๋๋ ํ์ฐํ ์ค๋ค.
์ฌ๊ธฐ์ ์คํ๋ง ๋ฐ์ดํฐ JPA๋ฅผ ์ฌ์ฉํ๋ฉด, ๋ฆฌํฌ์งํ ๋ฆฌ์ ๊ตฌํ ํด๋์ค ์์ด ์ธํฐํ์ด์ค ๋ง์ผ๋ก ๊ฐ๋ฐ์ ์๋ฃํ ์ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ฐ๋ณต ๊ฐ๋ฐํด์จ ๊ธฐ๋ณธ CRUD ๊ธฐ๋ฅ๋ ์คํ๋ง ๋ฐ์ดํฐ JPA๊ฐ ๋ชจ๋ ์ ๊ณตํฉ๋๋ค.
๋ฐ๋ผ์ ๊ฐ๋ฐ์๋ ํต์ฌ ๋น์ฆ๋์ค ๋ก์ง์ ๊ฐ๋ฐํ๋๋ฐ, ์ง์คํ ์ ์์ต๋๋ค.
์ค๋ฌด์์ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์คํ๋ง ๋ฐ์ดํฐ JPA๋ ์ด์ ์ ํ์ด ์๋๋ผ ํ์ ์
๋๋ค
์คํ๋ง ๋ฐ์ดํฐ JPA๋ JPA๋ฅผ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ๋๋ก ๋์์ฃผ๋ ๊ธฐ์ ์ด๋ค.
์คํ๋ง JPA๊ฐ ์ธํฐํ์ด์ค์ ๋ํ ๊ตฌํ์ฒด๋ฅผ ์๋์ผ๋ก ๋ง๋ค์ด๋ธ๋ค.
๊ตฌํ ํด๋์ค ์์ฑ ํ์ ์์ด ์ธํฐํ์ด์ค ์ด๋ฆ ๋ง์ผ๋ก๋ ๊ฐ๋ฐ์ด ๊ฐ๋ฅํ๋ค.
์ค๋ฌด์์๋ JPA์ ์คํ๋ง ๋ฐ์ดํฐ JPA๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ๊ณ , ๋ณต์กํ ๋์ ์ฟผ๋ฆฌ๋ Querydsl์ด๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. Querydsl์ ์ฌ์ฉํ๋ฉด ์ฟผ๋ฆฌ๋ ์๋ฐ ์ฝ๋๋ก ์์ ํ๊ฒ ์์ฑํ ์ ์๊ณ , ๋์ ์ฟผ๋ฆฌ๋ ํธ๋ฆฌํ๊ฒ ์์ฑํ ์ ์๋ค. ์ด ์กฐํฉ์ผ๋ก ํด๊ฒฐํ๊ธฐ ์ด๋ ค์ด ์ฟผ๋ฆฌ๋ JPA๊ฐ ์ ๊ณตํ๋ ๋ค์ดํฐ๋ธ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋, ์์ ํ์ตํ ์คํ๋ง JdbcTemplate๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
7. AOP
ํ์ํ ์ํฉ
- ๋ชจ๋ ๋ฉ์๋์ ํธ์ถ ์๊ฐ์ ์ธก์ ํ๊ณ ์ถ์ ๋
- ๊ณตํต ๊ด์ฌ ์ฌํญ vs ํต์ฌ ๊ด์ฌ ์ฌํญ
- ํ์ ๊ฐ์ ์๊ฐ, ํ์ ์กฐํ ์๊ฐ์ ์ธก์ ํ๊ณ ์ถ์ ๋
๋ฉ์๋ ๋ณ๋ก ์ํ ์๊ฐ์ ์ฐ์ด๋ณธ๋ค.
public Long join(Member member) {
long start = System.currentTimeMillis();
try {
validateDuplicateMember(member); //์ค๋ณต ํ์ ๊ฒ์ฆ
memberRepository.save(member);
return member.getId();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("join " + timeMs + "ms");
}
}
public List<Member> findMembers() {
long start = System.currentTimeMillis();
try {
return memberRepository.findAll();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("findMembers " + timeMs + "ms");
}
}
๋ฌธ์
- ํ์๊ฐ์ , ํ์ ์กฐํ ์๊ฐ์ ์ธก์ ํ๋ ๊ธฐ๋ฅ์ ํต์ฌ ๊ด์ฌ ์ฌํญ์ด ์๋๋ค.
- ์๊ฐ์ ์ธก์ ํ๋ ๋ก์ง์ ๊ณตํต ๊ด์ฌ ์ฌํญ์ด๋ค.
- ์๊ฐ์ ์ธก์ ํ๋ ๋ก์ง๊ณผ ํต์ฌ ๋น์ฆ๋์ค์ ๋ก์ง์ด ์์ฌ์ ์ ์ง๋ณด์๊ฐ ์ด๋ ต๋ค.
- ์๊ฐ์ ์ธก์ ํ๋ ๋ก์ง์ ๋ณ๋์ ๊ณตํต ๋ก์ง์ผ๋ก ๋ง๋ค๊ธฐ ๋งค์ฐ ์ด๋ ต๋ค.
- ์๊ฐ์ ์ธก์ ํ๋ ๋ก์ง์ ๋ณ๊ฒฝํ ๋ ๋ชจ๋ ๋ก์ง์ ์ฐพ์๊ฐ๋ฉด์ ๋ณ๊ฒฝํด์ผ ํ๋ค.
AOP (Aspect Oriented Programming) ์ ์ฉ
๊ณตํต ๊ด์ฌ ์ฌํญ๊ณผ ํต์ฌ ๊ด์ฌ ์ฌํญ์ ๋ถ๋ฆฌํ๋ค.
@Aspect
@Component
public class TimeTraceAop {
@Around("execution(* hello.hellospring..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("START: " + joinPoint.toString());
try {
return joinPoint.proceed();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("END: " + joinPoint.toString() + " " + timeMs + "ms");
}
}
}
- ํ์๊ฐ์ , ํ์ ์กฐํ๋ฑ ํต์ฌ ๊ด์ฌ์ฌํญ๊ณผ ์๊ฐ์ ์ธก์ ํ๋ ๊ณตํต ๊ด์ฌ ์ฌํญ์ ๋ถ๋ฆฌํ๋ค.
- ์๊ฐ์ ์ธก์ ํ๋ ๋ก์ง์ ๋ณ๋์ ๊ณตํต ๋ก์ง์ผ๋ก ๋ง๋ค์๋ค.
- ํต์ฌ ๊ด์ฌ ์ฌํญ์ ๊น๋ํ๊ฒ ์ ์งํ ์ ์๋ค.
- ๋ณ๊ฒฝ์ด ํ์ํ๋ฉด ์ด ๋ก์ง๋ง ๋ณ๊ฒฝํ๋ฉด ๋๋ค.
- ์ํ๋ ์ ์ฉ ๋์์ ์ ํํ ์ ์๋ค (@Around(โexecution(* hello.hellospring.service.*(..))โ))
AOP๊ฐ ์์ผ๋ฉด ํ๋ก์๋ฅผ ๋ง๋ค์ด ๊ฐ์ง ๋น์ ๋ง๋ ๋ค.
๊ฐ์ง ๋น์์ joinPoint.proceed()๊ฐ ์ผ์ด๋๋ฉด ์ค์ ๋น์ ํธ์ถํด์ค๋ค.
์ฝ์์ ์ถ๋ ฅํด๋ณด๋ฉด ์ค์ MemberService๊ฐ ์๋ Proxy๊ฐ ์ถ๋ ฅ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.