게시글
질문&답변
안녕하세요.
아마 아래 질문과 같은 상황이신 것 같네요.https://inf.run/U9fwJ now()를 기본 system clock에서 실행을 하면 매번 새로운 시간이 돌아오는 것으로 기대를 합니다. 그래서 제가 사용하는 맥에서는 아주 작은 시간이라도 now()를 호출 할 때마다 시간이 바뀝니다.그런데 윈도우의 자바 내부 구현에서는 now()가 돌려주는 시간 최소 단위가 달라서 그런지, 이렇게 연속으로 now()를 실행하는 코드라면 정말 작은 시간차만 있어서 같은 시간이 돌아오기도 합니다. 위의 글을 읽어보시면 윈도우에서 now()를 30번 실행했더니 계속 같은 값이 나오다가 뒷 부분에서 시간이 바뀐다고 합니다. 그래서 이 테스트가 실패하네요. 테스트 중간에 Thread.sleep(100) 정도라도 넣어서 잠깐 대기했다가 now()가 다시 실행되도록 만들면 테스트가 성공할 겁니다.OS마다 자바 언어 구현의 차이가 있기 때문에 발생하는 문제입니다. 한번 확인해보시고 그래도 궁금하신 점이 있으시면 알려주세요.
- 0
- 2
- 21
질문&답변
Payment 엔티티에 exRateProvider 주입
말씀하신 내용은 AspectJ를 이용해서 Payment 오브젝트가 생성되는 생성자 호출 시점을 가로채서 부가적인 빈을 주입하는 기법입니다.그런데 여기선 그 방식을 사용할 필요는 없습니다.PaymentService에서 Payment 오브젝트를 생성할 때 ExRateProvider 타입 빈을 파라미터로 넣어주면 되죠. 생성자 또는 정적 팩토리 메소드에 사용할 수 있습니다. 그냥 코드를 이용해서 직접 주입을 해주는 것이면 충분합니다.왜냐하면 ExRateProvider가 사용이 되는 시점은 Payment가 처음 만들어지고 초기화되는 때로 명확하고 이후엔 필요하지 않습니다. 따라서 굳이 복잡한 난이도의 AOP 주입 방법을 사용할 필요는 없습니다.ExRateProvider는 Payment 생성 시점에 환율을 한번 계산하면 이후에 사용할 필요가 없기 때문에 다른 DI처럼 내부에 저장해둘 이유도 없습니다. 이런 경우 환율 계산이 필요한 메소드 또는 생성자에 파라미터로 주입하는 메소드 호출 주입 방법을 사용하면 충분합니다.환율을 적용해서 계산된 금액을 넣는 대신, 환율 제공자 오브젝트를 넘겨서 Payment 생성 시점에 내부에서 계산하도록 만들어보세요.
- 0
- 1
- 33
질문&답변
@Transactional private 사용유무
말씀하신 대로 private 메소드에는 스프링의 프록시 기반 AOP를 적용할 수 없습니다. 기본적으로 인터페이스 구현 또는 상속을 통한 오버라이딩 기법을 써서 프록시 역할을 하는 코드를 최종 클래스의 메소드를 실행하기 전후에 넣어야 하는데, 그런 코드가 나올 수가 없기 때문이죠.그러면 TransactionTemplate을 써서 트랜잭션을 만드는 방법 뿐인가라고 생각할 수도 있겠네요. 하지만 좀 더 근본적으로 생각해볼 필요가 있겠네요.모든 클래스의 private 메소드는 결국 어떤 public 또는 그에 준하는 접근이 가능한 메소드를 타고 실행이 됩니다. 그런다고 하면 트랜잭션의 경계를 굳이 특정 private으로 제한할 필요는 없을 겁니다. 보통 public으로 외부에 공개한 메소드가 결국 이 오브젝트가 제공하는 중요한 기능일테고, 트랜잭션은 그런 기능 단위로 시작하고 종료하는 게 자연스럽습니다. private 메소드는 시간이 지나면서 자주 바뀌거나 변경됩니다. 내부의 디테일한 구현은 리팩터링이나 여러 다른 이유로 변경을 해도 오브젝트를 사용하는 쪽에 영향을 주지 않기 때문에 변경에서 자유롭습니다. 그런데 그 메소드에 트랜잭션을 선언한다는 것은 매우 불안정한 코드와 트랜잭션 기능 적용이 되겠죠. 모든 DB 기능이 사용되는 메소드에서 다시 트랜잭션을 시작할 필요는 없습니다. 진입점에 해당하는 public 메소드에서 트랜잭션을 시작해두면 이후에 호출되는 모든 메소드, 심지어 다른 빈의 메소드까지 트랜잭션에 포함됩니다. 따라서 private 메소드에 트랜잭션을 지정하는 것은 결코 좋은 설계가 아닙니다. 아주 복잡한 AOP 기술을 쓰면 불가능한 것도 아니지만, 그럴만큼 필요할리가 없을 듯하네요. 트랜잭션을 시작해두는 것 때문에 특별히 성능에 영향이 있거나 하지 않습니다. 그래서 public 메소드나 인터페이스의 공개된 메소드에 트랜잭션을 지정하는 것이 좋습니다. 위의 코드라면 createOrder() 메소드에 트랜잭션 설정을 적용하세요.
- 0
- 1
- 33
질문&답변
JdbcClient 생성 질문
날카로운 질문을 주셨네요.특별한 이유가 있어서 JdbcClient를 직접 만든 것은 아닙니다. JdbcClient가 만들어지는 과정을 보여드리려고 그렇게 코드를 만들었을 뿐입니다. 말씀하신 대로 싱글톤 빈으로 정의해서 가져와서 사용해도 됩니다. 오래 전에 많이 쓰이던 JdbcTemplate도 비슷한 스타일로 생성자에서 DataSource를 받아서 만들어 저장해두고 쓰기도 했거든요. JdbcTemplate, JdbcClient 등은 복잡하지 않은 가벼운 템플릿이고, 특별한 의존성 없이 간단히 만들어서, 심지어 스프링 밖에서도 쓸 수 있다는 것을 강조하기 위해서 그렇게 쓰기도 했습니다. 테스트나 main 메소드에서도 바로 사용할 수 있으니까요. 물론 처음에 그런식으로 시작했다가 리포지토리가 많아지면서 계속 중복이 보이면 리팩터링을 통해서 빈으로 추출하는 작업을 하게 될 겁니다. 그 외에 다른 이유로 직접 생성한 것은 아니니, 사용법과 의존 관계를 잘 파악하셨다면 빈으로 등록해두고 편하게 사용하시면 됩니다.
- 0
- 2
- 38
질문&답변
안녕하세요 PaymentConfig 질문드립니다.
안녕하세요.질문에 넣어주신 코드 두 개가 제가 보기에는 똑같아 보입니다. 다시 확인해보시고 알려주시면 답변 드리겠습니다.
- 0
- 2
- 51
질문&답변
[공유] 윈도우 사용자를 위한 http 명령어 오류 해결 방법
제가 알려드린 방법으로는 httpie 설치에 문제가 있으셨군요. 좋은 팁을 알려주셔서 감사합니다. 윈도우 환경을 준비해서 좀 더 세심하게 설치 방법 등을 연구해보겠습니다.
- 0
- 2
- 121
질문&답변
섹션7. 자동구성 정보파일분리 강의 질문(@MyAutoConfiguration 붙힌 이유)
@MyAutoConfiguration은 @Configuration을 메타 애노테이션으로 가지고 있으니 구성정보를 작성하는 클래스라는 것을 스프링에게 알려줄 수 있죠. 그래서 @Bean이나 @Import 등을 사용할 수 있습니다. 동시에 스프링부트의 자동 구성에서 사용하는 구성 정보를 담은 클래스라는 것을 명확하게 하기 위해서 애노테이션을 새로 만든 것입니다. 실제로는 스프링 부트는 @AutoConfiguration이라는 애노테이션을 가지고 있죠. 이걸 흉내내서 만든 것이 @MyAutoConfiguration입니다.proxyBeanMethods = false은 스프링이 최근에 추가한 방식입니다. @Configuration에서 @Bean이 붙은 메소드를 다른 여러 빈에서 중복해서 호출해서 의존관계 주입(DI)을 하고 있지 않다면 결과적으로 차이는 없습니다. 말씀하신 클래스에 이걸 붙여도 상관없습니다. 스프링이 최근에 proxyBeanMethods = false를 적극적으로 사용하고 있기 때문에 이에 대한 설명을 해봤습니다. 스프링 부트를 이용해서 개발하면서 가질 수 있는 질문과 동작 원리를 모르기 때문에 오해할 수 있는 지점, 그리고 사용하는 기술의 동작 방식에 대한 이해를 돕고자 만든 강의입니다. 단순하게 내용을 외우는 것은 별 도움이 안 될 것입니다. 일단 자동 구성이 어떻게 동작하는지, 지금 적굥된 자동 구성이 어떤 일을 하고 있는지 등이 궁금할 때, 다시 강의 내용을 확인해보시고, 알려드린 방법으로 스프링 부트의 기술을 살펴보시는 경험이 필요합니다. 그래도 제가 중요하다고 강조드린 내용은 기억해두시면 좋겠습니다. 더 궁금하신 내용이 있으면 다시 알려주세요.
- 0
- 2
- 96
질문&답변
WebApplicationContext를 DispatcherServlet에 this로 넘기는 것
어느 수업의 어느 시점에 나오는 예제인지를 알려주시면 좀 더 정확하게 답을 드릴 수 있을 것 같습니다. ApplicationContext 인터페이스로 대표되는 스프링 컨테이너는 사실 굉장히 복잡하고 깊은 여러 인터페이스와 클래스 상속 구조를 가지고 있습니다. 어떤 방식으로 스프링의 구성 정보를 전달하는가에 따라서 실제 사용되는 클래스가 달라지죠. 그런데 예제와 같이 스프링의 기능을 살펴볼 때는 필요한 기능을 가진 가장 최상위 인터페이스 또는 클래스를 사용해서 코드를 만듭니다. 일반적인 스프링 개발에선 사실 이 ApplicationContext를 구현한 스프링 컨테이너를 직접 액세스할 경우는 거의 없습니다. 다만 강의에서는 동작원리를 살펴보기 위해서 적절한 타입으로 만들어진 스프링 컨테이너를 받아서 사용하고 있죠.ApplicationContext로 대표되는 스프링 컨테이너 오브젝트가 웹과 관련된 컨텍스트에서 사용될 때는 꼭 Web이 들어간 ApplicationContext를 사용해야 합니다. DispatcherServlet 등에서 사용하는 메소드를 가지고 있어야 하거든요. 그래서 GenericWebApplicationContext 타입을 썼을텐데, 결국 이것도 상위는 GenericApplicationContext 혹은 가장 최상위 ApplicationContext를 구현한 것이기 때문에, 만약 코드에서 사용하는 기능이 getBean()과 같이 가장 단순한 거라면 ApplicationContext로, registerBean() 처럼 코드로 빈을 등록하는 작업이 필요한 경우라면 이 메소드를 가진 상위 타입인 GenericApplicationContext로 받아서 사용할 뿐입니다.일단 강의에서는 스프링 컨테이너가 이런 작업을 하고 있구나 정도만 이해하시면 충분합니다. 그때마다 쓰이는 클래스나 인터페이스 타입이 다르긴 하지만 결국 이게 우리가 개발할 때 만들어지는 스프링 컨테이너가 구현하거나 상속한 인터페이스나 클래스 중의 하나일 것이라고 생각하시면 충분할 것 같습니다.내부 구조가 더 궁금하시다면 스프링 소스 코드에서 ApplicationContext 인터페이스로부터 출발해서 이를 확장한 여러 인터페이스, 그리고 이를 구현한 각종 클래스를 살펴보시면 됩니다. 흥미롭긴하지만 사실 스프링을 더 깊이 이해하는데 크게 도움이 될 것은 아니라서, 그 부분을 자세히 보여드리면서 설명드리진 못했네요. 말씀하신 것처럼 예제 코드에서 필요로 하는 메소드를 가지고 있는 타입이라면, 그 타입으로 받아서 사용해보세요. 좀 특별한 케이스를 제외하면 잘 변환이 될 겁니다. 코드를 변경하고 컴파일과 동작이 잘 되면 아무 문제가 없는 것입니다. 혹시 더 궁금하신 게 있으시면 보고 계신 코드를 포함해서 다시 질문을 해주세요. 감사합니다.
- 0
- 2
- 175
질문&답변
생성자 파라미터성자 파라미터
스프링은 컴포넌트스캔이든 명시적인 빈 팩토리 메소드 선언이든 상관없이 등록 가능한 모든 빈 정보를 먼저 수집하고 이 사이의 의존관계를 확인합니다. 그래서 그에 따라 각 빈의 생성 순서를 조정합니다.위와 같은 @Bean 팩토리 메소드를 이용하는 경우 아래 transactionManager()를 실행해서 빈을 만들려면 DataSource 타입의 빈이 필요하다는 것을 알 수 있고, 위 dataSource()를 이용해서 빈을 먼저 만든 뒤에 그 오브젝트를 아래 transactionManager()의 파라미터로 넘겨줍니다. 순환참조가 발생하지 않는다면 이와 같이 다른 빈을 파라미터로 주입 받아서 새로운 빈을 생성하는 방식을, 생성자 주입 또는 @Bean 메소드 파라미터 주입 등에 활용할 수 있습니다.
- 0
- 2
- 181
질문&답변
인프라 빈 구성 정보의 분리에서 EnableMyAutoConfiguration 질문드립니다.
@Configuration은 @Component를 메타 애노테이션으로 가지고 있어서 애노테이션이 붙은 클래스를 빈으로 등록되게 합니다. 그런데 @Configuration이 꼭 클래스에 바로 지정된 애노테이션, 여기서라면 MySpringApplication에 있어야하는 것은 아닙니다. 메타 애노테이션으로 따라가다 @Configuration이 나와도 적용이 되겠죠. 이후에 언제라도 @Bean을 넣어서 수동 빈 등록이 가능하도록 만들기도 하고, 해당 클래스가 전체 애플리케이션 컨텍스트가 등록되는 기반이 되는 클래스임을 나타내도록 하기 위해서라도 @Configuration이 바로 붙어있는게 좋은 것 같습니다. 스프링 부트의 @SpringBootApplication는 @SpringBootConfiguration 애노테이션을 가지고 있고, 이 안에 메타 애노테이션으로 @Configuration이 있습니다. 그래서 @SpringBootApplication이 붙은 클래스가 @Configuration 기능을 수행하는 것이죠.지금 예제에서는 @EnableMyAutoConfiguration 위에 @Configuration이 있어서 이게 적용이 되는 것으로 보이는데, 그래도 @MySpringBooApplication이 기본 @Configuration 클래스임을 쉽게 볼 수 있도록 그 위에 @Configuration이 있는 것이 적절해보입니다. Autoconfiguration은 구현 방법에 따라서 @Configuration이 붙은 config 클래스를 직접 참조하지 않을 수도 있거든요.
- 0
- 2
- 102