전체 글

전체 글

    스프링 핵심 원리 - 고급편 - 섹션6. 스프링이 지원하는 프록시

    전 섹션에서의 문제는 인터페이스가 있을때랑 없을때랑 적용 방법이 달랐다. 이런걸 추상화해서 통일해준게 스프링. 프록시 팩토리를 만들어줬다. 예시코드를 작성해보자. 이 MethodInterceptor의 맨 상위 부모가 Advice다. 이미 invocation 안에 어떤 클래스를 타켓으로 하는지 생성할 때 저장해놓았기 때문에 그냥 proceed()만 하면 된다. 감싸지길 원하는 실제 비즈니스 클래스를 타켓으로 하고 프록시 팩토리 안에 넣어준 뒤 프록시 받아오면 된다. 프록시 팩토리로 만들어진 프록시 클래스인지와 이게 동적으로 만들었는지 정적으로 만들어졌는지 조차도 알 수 있다. 구체 클래스로도 만들어보자. 그리고 인터페이스가 있어도 구체클래스처럼 CGLIB를 만들도록 설정할 수도 있다. 참고로 스프링 부트에..

    스프링 핵심 원리 - 고급편 - 섹션5. 동적 프록시 기술

    동적 프록시를 이해하려면 일단 자바의 리플렉션 기술이 뭔지부터 알아야 한다. @Slf4j public class ReflectionTest { @Test void reflection0() { Hello target = new Hello(); // 공통 로직1 시작 log.info("start"); String result1 = target.callA(); // 호출하는 메소드가 다름 log.info("result1={}", result1); // 공통 로직1 끝 // 공통 로직2 시작 log.info("start"); String result2 = target.callB(); // 호출하는 메소드가 다름 log.info("result2={}", result2); // 공통 로직2 끝 } @Test voi..

    스프링 핵심 원리 - 고급편 - 섹션4. 프록시 패턴과 데코레이터 패턴

    일단 v1, v2, v3를 만든다. v2 수동으로 빈에 등록하려고 여기선 @Controller를 사용하지 않음 v3 얘내들은 컴포넌트 스캔에 걸리도록 정직하게 어노테이션을 걸어준다. 새로운 요구사항으로 원본 코드는 건들지 말고 추적 기능을 추가해야 한다. 근데 앞뒤로 있어야 넣을 수 있는 추적 기능을 어떻게 수정 없이 넣을 수 있는가? 프록시를 쓰면 된다. 프록시는 대신 실행해주는거라고 보면 된다. 여기선 원본 코드와 똑같은데 기능이 조금 더 추가된 프록시를 실행하는 거다. 접근 제어가 목적이면 프록시 패턴으로, 새로운 기능 추가가 목적이면 데코레이터 패턴이라고 부르기로 했다. 이해를 위한 예제 코드를 작성하자. 그냥 프록시가 뭔지를 보여주기 위한 빈 프록시다. 만약 여러번 실행했을 때, 처음에 실행할 ..

    스프링 핵심 원리 - 고급편 - 섹션3. 템플릿 메서드 패턴과 콜백 패턴

    이 섹션에서 템플릿 메서드 패턴, 전략 패턴, 탬플릿 콜백 패턴을 알아볼거다. 전 섹션에서 본 로그추적기를 도입하려고 했는데, 막상 해놓고 보니 부가적으로 반복되는 코드가 너무 장황해졌다. 핵심기능은 단 한줄인데 단지 로그 추적을 위한 부가기능으로 뭔가 앞뒤로 덕지덕지 붙어서 너무 보기 흉하다. 이건 메소드가 2개라서 그나마 괜찮아 보이지 막 클래스와 메소드가 100개씩 넘어가면 더 힘들어진다. 하지만 반복되는 부분을 메서드로 따로 빼려고 해도 핵심 기능이 try catch로 감싸져 있어 이것도 쉽지 않다. 그래서 이 문제를 해결하는 디자인 패턴이 템플릿 메서드 패턴이다. 일단 이게 뭔지 알기 위해 테스트코드를 작성해본다. 주변은 같은데 안에만 다를 때 추상화 클래스 상속을 사용하면 된다. 이게 뭔지는 ..

    스프링 핵심 원리 - 고급편 - 섹션2. 쓰레드 로컬 - ThreadLocal

    이제 인터페이스를 만들어가며 본격적으로 해보자. @Slf4j public class FieldLogTrace implements LogTrace { private static final String START_PREFIX = "-->"; private static final String COMPLETE_PREFIX = ""; private static final String COMPLETE_PREFIX = "

    스프링 핵심 원리 - 고급편 - 섹션1. 예제 만들기

    프로젝트 기본 세팅 로그 추적기를 만들어볼거다. package hello.advanced.trace; import java.util.UUID; public class TraceId { private String id; private int level; public TraceId() { this.id = createdId(); this.level = 0; } private TraceId(String id, int level) { this.id = id; this.level = level; } private String createdId() { return UUID.randomUUID().toString().substring(0, 8); } public TraceId createNextId() { retur..

    스프링 부트 - 핵심 원리와 활용 - 섹션10. 모니터링 메트릭 활용

    전 섹션에 했던건 스프링 서버의 전체적인 환경 관리였고, 나만의 비즈니스를 모니터링 하려면 직접 정의해야 한다. 그래서 해보는거다. 프로젝트 세팅한다. AtomicInteger는 race 방지하려고 이제 이걸 본격적으로 메트릭에 넣어보자. 메트릭에 넣는것도 마이크로미터를 사용한다. 현재 카운터를 넣으니, 마이크로미터의 카운터를 가져와 넣어준다. 그럼 실제 메트릭에서도 저게 등록된다(단, 최소 한번은 실행해야 등록된다). 이 정보 또한 프로메테우스에 가게되고, 다른것들 처럼 그라파나에서도 사용 가능하게된다. 이 등록을 @Counter로 더 편하게 할 수 있다. 태그의 클래스와 메소드 등은 해당 클래스 이름과 함수 이름으로 알아서 적용한다. CountedAspect를 등록한 뒤 @Counted를 하면 된다...

    스프링 부트 - 핵심 원리와 활용 - 섹션9. 마이크로미터, 프로메테우스, 그라파나

    마이크로미터는 여러 모니터링 툴들을 하나로 통합시켜 추상화한거다. actuator에서 기본으로 제공하는 메트릭들을 보자. tag로 범위를 한정해서 볼 수도 있다. 이런 cpu 사용량같은 os뿐 아니라 사용자 요청, 톰캣 쓰레드 갯수, 로그 등도 확인 가능하다. 특히 유용한건 tomcat.threads.busy, tomcat.threads.config.max 그리고 직접 사용자가 만드는 메트릭임. 사용자가 만드는건 실제 서비스로 사용하는 비즈니스 로직을 만들어 넣어 테스트해볼 수 있기 때문. 메트릭의 한계점은 어디에 기록하는게 아니라 순간순간 보는거라 데이터베이스에 넣어서 기록하는게 필요함. 그걸 프로메테우스가 해주고, 보는거는 그라파나로 본다. 설치부터 실습한다. 프로메테우스는 포트 9090가 기본임. ..

    스프링 부트 - 핵심 원리와 활용 - 섹션8. 액츄에이터

    여기선 본격적인 강의 들어가기 전에 프로덕션 준비 기능 개념에 대해 먼저 설명해준다. 프로덕션 준비 기능은 코드로 작성한 서버 기술적 외에 배포할 때 고려해야 할 것들을 말함. 지표, 주적, 감사, 모니터링 등. 즉 모니터링 actuator라는걸 설치하면 이미 모니터링 기능으로써 제공된 /actuator url이 있다. 하지만 설치는 설치고 이걸 웹에 노출 시켜야지 나도 볼 수 있다. 어찌보면 당연한건데.. 예를들어 어떤게 bean에 등록되었는지 어쩌구 저쩌구 ~~. 기본은 물론이고 확인 가능하다던지. 좀 스프링에 특화된 모니터링이다. 숨겨져 있을 뿐 기본적으로 shutdown을 제외한 대부분의 기능들은 활성화 되어있다. 자주쓰는 것들 Production-ready Features (spring.io) ..

    스프링 부트 - 핵심 원리와 활용 - 섹션7. 외부설정과 프로필2

    이번엔 이 외부설정을 주로 어떻게 읽는지 알아볼거다. 새로운 프로젝트로 시작한다. 전에 나온 Environment로 가져와서 읽으면 된다. 근데 일일히 env.getProperty 하기 싫어서 @Value라는게 나옴 @Slf4j @Configuration public class MyDataSourceValueConfig { @Value("${my.datasource.url}") private String url; @Value("${my.datasource.username}") private String username; @Value("${my.datasource.password}") private String password; @Value("${my.datasource.etc.max-connection}..