Skip to content
Hyunjun Jeong edited this page Mar 1, 2023 · 8 revisions

1주차 오브젝트와 의존관계

  • A가 B라는 빈을 주입 받고 싶을 때 A도 빈으로 등록되어 있어야 하지만, A가 특정 상황으로 인해 빈으로 등록할 수 없을 때 getBean()으로 B를 조회할 수 있다
  • 여기서 말하는 인터페이스는 자바의 인터페이스를 뜻하는 것이 아니다
  • 빈은 꼭 인터페이스로 받아야할까?
    1. Serivce의 인터페이스가 없이 Service 클래스를 직접 주입받는다면 차라리 new로 생성하라고 할 만큼 의미 없다
  • 생성자 주입 방식이 왜 좋냐??
    1. 수정자 주입은 자바 빈의 특성 떔에 잠깐 나왔던 사용법인 것 같다? 생성자 주입을 쓰라고 한다
    2. 생성자 주입의 문제는 주입을 여러 개 받을 때 동일한 타입을 받는 상황이라면 순서가 뒤바뀌어도 문제를 알아차릴 수 없다
      1. 롬복의 생성자 어노테이션의 문제점과 관련있음
    3. 생성자 주입에서 동일한 타입을 받을 때의 문제점을 해결하기 위한 전략도 있다고 한다
  • 객체의 생명주기
  • 스프링이 추상 클래스를 상속받아 빈으로 등록해준다는데?? 🚩
  • 프로토타입 빈 (잘 안쓴다)
  • XML로 설정하는 것은 혁신적인 기술이었다
    1. 여러 명이 동시에 개발한다면 같은 설정 파일을 수정하는 상황이 문제다
    2. 타입체크를 런타임시에 하기 때문에 띄워봐야 안다는 부분은 요즘 ide가 해결해준다
  • 어노테이션은 자바보다 스프링이 먼저 나왔다
  • 엔티티의 의존정보는 어노테이션으로 DB 매핑 정보는 xml로 할려고 했다는 것이 JPA의 초기 컨셉
  • xml은 다 버리고 @Configuration
  • 코드 레벨에서 의존관계가 있는 것과 런타임시에 의존관계가 만들어지는 것은 차이가 있다 📌

2주차 테스트

블랙박스 테스트, 화이트박스 테스트
2장 테스트 (모임 중 든 생각, 기억에 남는 말말말)
2장 읽기모임 정리

  1. 테스트 결과는 항상 일관성 있어야 한다.
  2. 개인적으로 테스트 상황을 재현하는게 힘들다. 그리고 트랜잭션도 설정해보질 않아서 추후에 배우게 될 것 같은데 기대된다.
  3. 엣날 JUnit의 테스트 메소드는 왜 public이어야 할까요?
  4. johngrib 테스트 코드와 반증가능성에 대한 메모 (개인적으로 추천)
  5. 토비님 왈 "테스트 코드를 돌리면서 왜 멍때리냐 개발을 계속 진행하라고 화낸적이 있다"
  6. 학습 테스트 , 버그 테스트 , 포괄적인 테스트
  7. 성의 없이 테스트를 만들어 문제가 있는 코드인데도 테스트가 성공하는 테스트코드가 제일 위험하다.
  8. JUnit으로 테스트 코드를 작성하는 것과 TDD로 개발하는 것의 차이
    1. JUnit으로 테스트 코드를 작성하는건 개발한 코드를 검증하는 느낌
    2. TDD로 개발하는 것은 테스트 코드를 통과하기 위한 개발을 하는 느낌
  9. 스텁 , , 더미 , 스파이 , 페이크 . 테스트 더블 ,테스트 대역 , Stunt double , 임포스터
    1. 아는 건 굵은 글씨 밖에...
  10. 테스트 코드를 작성하면서 비즈니스 로직이 추가 될 떄
    1. 문제가 있는 상황이 확실하다
  11. AWS를 모킹하는 경우도 있네
  12. 목을 걸 지점을 잘 지정하자
  13. 모킹도 복잡한 과정을 거치기 때문에 시간이 오래 걸린다
    1. 빠른 줄 알았는데 처음 알았다 그럼 테스트 상황 재현, 테스트 대상 집중을 위한 것 같다
  14. 테스트는 독립적이고 격리되어야 한다.
  15. private도 테스트 코드를 만들고 싶으면 만들어라. private도 테스트 가능하게 지원하는 기능이 있다
  16. 균등 분할

3주차 템플릿

오라클 자바 튜토리얼
When to Use Nested Classes, Local Classes, Anonymous Classes, and Lambda Expressions

  1. 전략 패턴을 구성하는 것
  2. 템플릿 콜백 패턴은 전략 패턴의 한 가지이다.
  3. Marker Interface
    1. 종립님이 단순 테스트를 위한 클래스에 마킹용으로 사용하신다고 했었던 것 같다.
    2. 이펙티브 자바에도 나온다고 한다.
  4. "람다식을 받도록 구현해보는 가장 쉬운 방법은 retry 를 구현해보면 돼요"

4주차 예외

5주차 서비스 추상화

  • 트랜잭션의 경계가 어디여야 하는가?? 이번 5장의 핵심이다
  • 특별한 예외상황을 테스트 할 때 테스트하려는 서비스 클래스를 상속받아 테스트 하는 방법이 신박했다
    • mock과 관련있다
  • 옛날에는 PreparedStatement, ResultSet 등등을 Service계층에서 사용하기도 했다고 한다
  • TransactionSynchronizationManager
  • mock 라이브러리는 모킹할 때만 쓰는것이 아니다 stub이나 spy도 지원해준다
    • mocking,stub,spy의 의미를 구분 잘 해서 말해야한다
  • 6장은 프록시 팩토리 빈 까지는 읽기를 권장한다

6,7주차 AOP

  • 리플렉션은 메타프로그래밍을 하기위한 방법으로 나왔다
    • 메타프로그래밍 : 프로그래밍하면서 작성되었던 코드를 데이터로 취급할 수 있다
    • 리플렉션 패키지는 tool을 사용할 떄 많이 사용했다
  • CGLIB는 코드 제네레이션 라이브러리이다
    • 인터페이스를 구현하지 않은 클래스에 대해 프록시를 만들어야 할 떄
    • (JDK에서는 불가하기 때문에) CGLIB는 상속을 통해 프록시를 만드는 기법을 사용한다
    • 오버라이드 할 수 있는 모든 메소드를 프록시로 만든다
    • 스프링에서는 두 가지 다 쓰인다
    • 상속을 통해 프록시를 만들면 단점이 있다
      • final클래스로 만들 수 없다
      • 기본 생성자가 두 번 호출되는 점, 자바5부터 없어졌다
    • 인스턴스를 만들 때 생성자를 호출하지 않고 만드는 트릭을 쓰는 라이브러리가 등장했다
  • 프록시의 의미를 잘 이해해야 한다
    • 프록시 패턴의 프록시
    • 일반적으로 말하는 프록시
  • Q : 다이나믹 프록시를 생성할 때 애플리케이션 클래스로더를 넘기게 되는데, 이 클래스 로더로 무슨 일이 일어나는지?
  • A : 다이나믹 프록시는 새로운 클래스를 런타임에 동적으로 생성하여 만들고 연결 시키기 위해 클래스 로더를 필요로 한다.
    • 클래스 로더를 간단하게 스프링이 제공하는 방법도 있다
    • 클래스 로더 관련해서
      • 도진님이 링크를 공유해 주셨다
      • Kevin Lee님이 링크를 공유해 주셨다
  • JPA에서는 프록시를 어떻게 사용하는지
    • @Entity가 대표적이다
    • 인터페이스가 있다면 CGLIB을 사용하지 않지만 인터페이스가 없다면 CGLIB을 사용한다
  • 스프링 6
    • 그랄VM
    • 네이티브 컴파일
    • 스프링에서 CGLIB을 없애야 된다. (충돌이 많이 나서)
  • AspectJ
  • 코드위빙?
  • JSON을 인코딩하고 디코딩하는게 CPU를 제일 많이 먹는다
  • Mock도 성능에 큰 문제를 준다
AspectJ 책을 살펴보니 AOP 적용 예로 나오는게
Transaction, Security, Auditing, PerformanceMonitor 같은 것들이네요.
이게 가장 범용적인 듯하고, 그 이상은 애플리케이션 도메인에 특화된 필요에 따라 만들어질 것 같네요.

8,9주차 스프링 핵심 기술의 응용

  • 스프링부트에서는 java 아래 소스 코드는 컴파일 되어서 .class 파일이 되고 그거랑 resources 아래 있는 파일이랑 합쳐서 클래스 패스로 잡히게 된다.
  • resources폴더 안에 작성하지 않고 다른 곳에 작성한다면 다 무시한다.
  • 부트에서 하셨으면 자바 폴더와 리소스 폴더가 구분이 되어서 들어가야 한다. 소스 폴더에 넣은 일반 파일은 클래스패스로 잡히지 않는다.
  • 토비님은 너무 복잡하거나 어려우면(돈과 관련되어있다면 무조건) TDD로 진행한다고 하신다. 그리고 TDD로 하지 않았다면 테스트 코드를 최대한 빠른 시간안에 작성하려고 하신다

  • 기존에는 XmlSqlService 생성자에서 XML 언마샬링작업을 했다
  • XML에서 SQL 정보를 읽어오는 책임과 SQL들을 매핑하는 책임에 맞는 개별의 인터페이스를 추가했다
    • SqlRegistry, SqlReader
  • 위 두 개의 인터페이스를 XmlSqlService 한 클래스에서 모두 구현하여 자기 참조를 하도록 리팩토링했다
  • 자기 참조로 되어있는 각 책임들을 분리하기 위하여 구현 클래스들을 추가했다
    • SqlRegistry를 구현하는 HashMapSqlRegistry 추가
    • SqlReader를 구현하는 JaxbXmlSqlReader추가
  • 위의 구현체들을 DI하도록 디폴트 의존관계를 갖는 DefaultSqlService를 추가
  • 지금은 XML 정보를 읽어들이는 JAXB로 구체적인 기술과 API에 종속되어 있기 때문에 서비스 추상화 적용
    • Spring의 Jaxb2Marshaller 테스트
  • BaseSqlServiceOxmSqlService의 중복되는 메소드를 제거하기 위해 해당 메소드들은 BaseSqlService에게 실행하도록 위임했다
  • SQL을 조작하는 책임을 가진 UpdatableSqlRegistry인터페이스를 구현하는
    • ConcurrentHashMapSqlRegistry 클래스를 추가하였다
    • EmbeddedDbSqlRegistry클래스를 추가하였다
      • 내장형 디비는 H2를 사용, update(Map<String, String> sqlmap)에 트랜잭션을 적용하였다
public class EmbeddedDbSqlRegistry implements UpdatableSqlRegistry {
    JdbcTemplate jdbc;
    TransactionTemplate template;

    public void setDataSource(DataSource dataSource) {
        jdbc = new JdbcTemplate(dataSource);
        // DataSource로 TransactionManager를 만들고 이를 이용해 TransactionTemplate을 생성한다.
        template = new TransactionTemplate(new DataSourceTransactionManager(dataSource));
    }
    ...
}

dataSource로 JdbcTemplate을 생성하여 쿼리를 실행시키는 것과
dataSource로 TransactionManager를 생성하고 TransactionTemplate을 생성하여 쿼리를 실행시키는 것의
트랜잭션 동기화 저장소를 사용하는 차이점은 알겠지만 확실한 (각 클래스들의)차이점을 알진 못 하겠다.

7장에서 개인적으로 SQL을 수정하는 기능을 추가하면서 UpdatableSqlRegistry인터페이스를 추가하고
SqlRegistry를 추상화 한것이 인상깊었다.

  • ConcurrentHashMap을 사용한 구현체와 내장형 디비를 사용한 구현체를 추가한 것

10주차 스프링이란 무엇인가?