전체 글

전체 글

    1335. Minimum Difficulty of a Job Schedule 풀이 python

    https://leetcode.com/problems/minimum-difficulty-of-a-job-schedule/ Minimum Difficulty of a Job Schedule - LeetCode Can you solve this real interview question? Minimum Difficulty of a Job Schedule - You want to schedule a list of jobs in d days. Jobs are dependent (i.e To work on the ith job, you have to finish all the jobs j where 0 int: N = len(jobDifficulty) if d > N: return -1 dp = [[-1] * (..

    스프링 핵심 원리 - 고급편 - 섹션13. 스프링 AOP - 실무 주의사항

    실제로 사용하다가 겪을 수 있는 경우의 수들 일단 프록시 클래스를 내부 호출 했을 때 프록시 적용 안되는 문제 프록시를 하고 있는 클래스인데 이 클래스 안에서 자신의 내부 함수를 직접 호출하고 있다면 여기엔 프록시가 적용되지 않는다. 외부에서 하면 프록시의 함수를 실행하므로 당연히 된다. 참고로 이건 AspectJ 프레임워크를 쓴다면 이렇게 스프링 AOP처럼 프록시 클래스를 만드는게 아닌 저 클래스 함수 안에 코드를 직접 쓰기 때문에 이런일이 없다. 하지만 설정이 너무 복잡하고 이걸 스프링 AOP로 해결할 수 있는 방법도 많아 거의 쓰지 않는다. 그래서 클래스 내부에서도 자기 함수를 직접 불러오는게 아닌 자신도 프록시 클래스의 함수를 사용하도록 바꿔보자. 생성자로 받으면 아직 빈에 생성되지도 않은 걸 받..

    스프링 핵심 원리 - 고급편 - 섹션12. 스프링 AOP - 실전 예제

    앞에서 배웠던 거 실제로 쓰기 실패할 시 자동으로 재시작 하는 로직을 어노테이션으로 해보자. 요새 이러는게 추세라고 함. 일단 여기에 로그용 어노테이션 @Trace를 만들어서 적용해보자. 어노테이션 @Trace가 붙어있다면 이 프록시를 만들어 적용해라. 를 원하는 함수에 붙여준다. 잘 된다. 이제 @Trace말고 재시작 하는걸 해보자. 잘 된다. 이제 어느 함수가 시간이 오래걸릴 때 경고 뜨게 한다던지 하는 식으로 창의적으로 활용하면 된다. 좋은건 한번 잘 만들어두면 어느 메소드나 클래스에서든 재활용할 수 있다.

    스프링 핵심 원리 - 고급편 - 섹션11. 스프링 AOP - 포인트컷

    은근슬적 포인트컷 지시 문법들 그냥 넘어갔었는데 이번에 다룬다. execution을 가장 많이 사용하고 나머지는 자주 사용하지는 않아 execution 위주로 볼거다. 기반 및 테스트코드 작성 MemberService 클래스 인스턴스를 만들어 거기에 hello라는 함수를 가져온 모습이다. 이걸 기반으로 포인트컷 문법들을 본다. @Slf4j public class ExecutionTest { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); Method helloMethod; @BeforeEach public void init() throws NoSuchMethodException { helloMethod = MemberServic..

    스프링 핵심 원리 - 고급편 - 섹션9,10. 스프링 AOP 개념,구현

    지금 문제가 뭐냐면 실제로 비즈니스 기능을 수행하는 핵심 기능과 로그를 남기는 부가 기능으로 나누는데, 이런 부가 기능은 대체로 여러 클래스에서 쓰일 확률이 높다. 그래서 여러 클래스에 거쳐 사용되기 때문에 횡단 관심사라고 하고, 때문에 사용하려면 각각의 클래스마다 복붙을 해야 한다. 현실적으론 복잡해지는데, 원하는 클래스마다 함수를 써서 넣어야 하고 이걸 유틸같은 함수로 정의해서 사용해도 결국은 안의 코드를 수정해야 한다. 왜냐하면 핵심 기능을 감싸는 코드여야 하기 때문 이 문제를 해결하기 위해 스프링에서 AOP를 지원한다. 이런 고민은 특정 앱을 만든 한명이 아닌 보통 만들때 고민하는 문제들이라 아얘 지원하는걸 만들었다. @Aspect인데, 지금까지는 클래스 각각 하나를 보면서 앱을 만들었다면, 횡단..

    스프링 핵심 원리 - 고급편 - 섹션8. @Aspect AOP

    스프링은 @Aspect 애노테이션으로 매우 편리하게 포인트컷과 어드바이스로 구성되어 있는 어드바이 생성 기능을 지원한다. 별 설정없이 @Aspect만 했는데도 된 이유가 위의 @Around가 포인트컷의 역할을 하고, 그 밑의 함수가 어드바이스의 역할을 하기 때문. 처음에 컴포넌트 스캔할 때 @Aspect가 붙어있으면 이걸 기반으로 어드바이저 빌더가 어드바이저를 생성해서 프록시를 만든다. 이 방식이 매우 편리해서 실무에선 대부분 @Aspect를 사용한다. 근데 사실 만든 로그 찍는 기능이 하나의 클래스에서만 관심있는게 아니라 여러 클래스에서 관심있어 지정한라 이를 횡단 관심사라고 하다. 다음 섹션부턴 이런 횡단 관심사를 전문으로 해결하는 스프링 AOP에 대해 알아볼거다.

    스프링 핵심 원리 - 고급편 - 섹션7. 빈 후처리기

    빈 후처리기는 @Bean으로 정의한 걸 스프링이 컴포넌트 스캔해서 가져가는데, 빈 저장소에 넣기 직전에 뭔가를 더 해줄 수 있도록 정의하는 것. 이 빈 후처리기에서 바꿔주면 된다. 테스트 코드를 작성해보자. public class BasicTest { @Test void basicConfig() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BasicConfig.class); // A는 빈으로 등록된다. A a = applicationContext.getBean("beanA", A.class); a.helloA(); // B는 빈으로 등록되지 않는다. Assertions.asse..

    elastic beanstalk의 기본 nginx 설정들

    빡쳐서 임시로 만들어 ec2 접속 후 들여다봤다. nginx.conf #Elastic Beanstalk Nginx Configuration File user nginx; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; worker_processes auto; worker_rlimit_nofile 200000; events { worker_connections 1024; } http { server_tokens off; include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_lo..

    스프링 핵심 원리 - 고급편 - 섹션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..