월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결스프링 핵심 원리 - 기본편
MyLogger 를 Interceptor 로 구현 시 질문
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]안녕하세요? 강의를 듣다가 requesURL 같은 경우 Interceptor 에서 멤버 변수로 저장하는 것이 좋다고 해서 구현을 해보려고 했는데 문제가 생겨서 질문 드립니다.## 앞으로 강좌를 계속 듣긴 할 거라서 혹시 뒤의 강좌를 듣고 나면 해결될 수 있는 문제라면 어느 강좌인지 알려주셔도 될 것 같습니다. MyLogger.javapackage hello.core.common; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.UUID; @Component @Scope(value = "request") public class MyLogger { private String uuid; private String requestURL; public void setRequestURL(String requestURL) { this.requestURL = requestURL; } public void log(String message) { System.out.println("[" + uuid + "]" + "[" + requestURL + "] " + message); } @PostConstruct public void init() { uuid = UUID.randomUUID().toString(); System.out.println("[" + uuid + "] request scope bean create: " + this); } @PreDestroy public void close() { System.out.println("[" + uuid + "] request scope bean close: " + this); } } CoreInterceptor.javapackage hello.core.common; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.ObjectProvider; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component @RequiredArgsConstructor public class CoreInterceptor implements HandlerInterceptor { private final ObjectProvider<MyLogger> myLoggerProvider; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("CoreInterceptor.preHandle"); String requestURL = request.getRequestURL().toString(); MyLogger myLogger = myLoggerProvider.getObject(); myLogger.setRequestURL(requestURL); return HandlerInterceptor.super.preHandle(request, response, handler); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } } WebMvcConfig.javapackage hello.core.common; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @RequiredArgsConstructor public class WebMvcConfig implements WebMvcConfigurer { private final ObjectProvider<MyLogger> myLoggerProvider; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new CoreInterceptor(myLoggerProvider)).excludePathPatterns("/css/**", "/images/**", "/js/**"); } } LogDemoController.javapackage hello.core.web; import hello.core.common.MyLogger; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.ObjectProvider; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; @Controller @RequiredArgsConstructor public class LogDemoController { private final LogDemoService logDemoService; private final ObjectProvider<MyLogger> myLoggerProvider; @RequestMapping("log-demo") @ResponseBody public String logDemo(HttpServletRequest request) { String requestURL = request.getRequestURL().toString(); MyLogger myLogger = myLoggerProvider.getObject(); myLogger.log("controller test"); logDemoService.logic("testId"); return "OK"; } } LogDemoService.javapackage hello.core.web; import hello.core.common.MyLogger; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.ObjectProvider; import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class LogDemoService { private final ObjectProvider<MyLogger> myLoggerProvider; public void logic(String id) { MyLogger myLogger = myLoggerProvider.getObject(); myLogger.log("service id = " + id); } } 위와 같이 이렇게 구현을 해보니 문제가 생기는데...일단, 인터셉터를 스프링 빈으로 등록하면서 MyLogger 를 활용하려면 알려주신 ObjectProvider 를 사용해야 할 것 같은데... WebMvcConfig 에서 인터셉터를 등록하는 경우, 위의 경우처럼 처음 서버 구동 시에 처리되어야 하는데 이 때는 reqeust 를 사용할 수 없는 문제입니다. 앞서 이 문제를 ObjectProvider 로 해결했는데 Interceptor 의 경우, 나중에 등록이 안 될 것 같은데 이런 경우 어떻게 해결해야 될까요?저렇게 인터셉터를 null 로 호출하니 실행해 보면 WebMvcConfig.java -> registry.addInterceptor(new CoreInterceptor(null))...java.lang.NullPointerException: Cannot invoke "org.springframework.beans.factory.ObjectProvider.getObject()" because "this.myLoggerProvider" is null위와 같은 에러가 발생합니다.관련된 소스 첨부하였습니다.도움 부탁 드립니다. 위의 소스는 제대로 된 걸로 다시 첨부하였습니다.registry.addInterceptor(new CoreInterceptor(null))...->private final ObjectProvider<MyLogger> myLoggerProvider; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new CoreInterceptor(myLoggerProvider)).excludePathPatterns("/css/**", "/images/**", "/js/**"); } 위와 같이 수정하였습니다. 이런 저런 버그들과 강의에서 가르쳐 주신 ObjectProvider 를 사용해서 설정파일에서 request 가 들어오는 시점에 로그를 주입해서 처리되도록 수정하였습니다.Interceptor 에서는 왜 ObjectProvider 를 사용하지 못할 거라고 생각했는지 모르겠네요. 답변 글 보고 질문을 수정하다가 생각이 나서 소스를 수정해 보니 잘 되는 것 같네요.감사합니다.
- 해결됨스프링 핵심 원리 - 기본편
애플리케이션 빈 출력하기
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]이렇게 위에 다 뜨는데 맞게 뜬건가요??
- 미해결스프링 핵심 원리 - 기본편
Mac OS 기반 인텔리제이 Spring boot 프로젝트 생성 시 발생한 오류
Mac OS 기반 인텔리제이를 설치하고 처음 Spring boot(gradle) 프로젝트 생성 시인텔리제이에서 build하는 과정에서 다음과 같은 오류가 발생합니다.구글링을 해봐도 어떤게 원인인지 해결 방안을 모르겠어서 질문 남겨요! * Exception is: org.gradle.api.UncheckedIOException: java.io.StreamCorruptedException: invalid type code: 00 at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:62) at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:41) at org.gradle.tooling.internal.provider.serialization.PayloadSerializer.deserialize(PayloadSerializer.java:78) at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner.run(ClientProvidedPhasedActionRunner.java:51) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:49) at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:65) at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:140) at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:41) at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:40) at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:122) at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:40) at org.gradle.internal.buildtree.InitDeprecationLoggingActionExecutor.execute(InitDeprecationLoggingActionExecutor.java:58) at org.gradle.internal.buildtree.DefaultBuildTreeContext.execute(DefaultBuildTreeContext.java:40) at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.lambda$execute$0(BuildTreeLifecycleBuildActionExecutor.java:65) at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:53) at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.execute(BuildTreeLifecycleBuildActionExecutor.java:65) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:61) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:57) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor.execute(RunAsBuildOperationBuildActionExecutor.java:57) at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.lambda$execute$0(RunAsWorkerThreadBuildActionExecutor.java:36) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:249) at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:109) at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.execute(RunAsWorkerThreadBuildActionExecutor.java:36) at org.gradle.tooling.internal.provider.continuous.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:110) at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64) at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46) at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:100) at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:88) at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:69) at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:62) at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:41) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:64) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:32) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:50) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:38) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31) at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75) at org.gradle.util.internal.Swapper.swap(Swapper.java:38) at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:64) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52) at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:49)
- 미해결스프링 핵심 원리 - 기본편
파라미터가 있는 빈을 필드주입 할 때
@Slf4j @SpringBootTest public class InternalCallV2Test { ##1## @Autowired CallService callService; @Test void internalCallV2(){ callService.external(); } @TestConfiguration static class InternalCallV1TestConfig{ @Bean CallService callService(){ return new CallService(internalService()); } @Bean InternalService internalService(){return new InternalService();} } @RequiredArgsConstructor static class CallService{ ##2## private final InternalService internalService; public void external(){ internalService.internal(); } } static class InternalService{ public void internal(){ } } }위와 같은 코드가 있을 때(1) 필드 주입@Autowired CallService callService;에서 callService이름의 빈을 찾아 객체를 주입 받습니다.(2) 생성자 주입@RequiredArgsConstructor static class CallService{ private final InternalService internalService;}에서 CallService의 생성자에 @Autowired를 통해 의존관계를 자동으로 주입받습니다.제가 궁금한건 빈을 등록할 때@Bean CallService callService(){ return new CallService(internalService());}CallService는 파라미터가 있는객체로 등록되는데 필드주입을 하게되면 그냥 CallService객체를 주입 받는 건가요????(파라미터가 있는 지 무시하고)생성자 주입은 파라미터가 있으니까 어떤게 주입되는지 보이는 데 필드주입은 잘 모르겠습니다... 답변주시면 정말 감사하겠습니다.
- 미해결스프링 핵심 원리 - 기본편
프로토타입 빈 관련 질문있습니다.
@Test void singletonClientUsePrototype() { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class); PrototypeBean bean = ac.getBean(PrototypeBean.class); String[] beanDefinitionNames = ac.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName); if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) System.out.println("beanDefinitionName = " + beanDefinitionName); } } @Scope("prototype") static class PrototypeBean { private int count = 0; public void addCount() { count++; } public int getCount() { return count; } @PostConstruct public void init() { System.out.println("PrototypeBean.init " + this); } @PreDestroy public void destroy() { System.out.println("PrototypeBean.destroy " +this); } } 프로토타입 빈을 ac.getBean 을 통해 요청하고 그 이후에 스프링 컨테이너를 조회했을때 프로토타입 빈이 존재하는지 확인해볼려고 위와 같이 코드를 작성하였습니다.그 결과로이와 같이 프로토타입 빈이 스프링 컨테이너에 있는걸 확인했습니다. 여기서 궁금한 점이 1. 스프링 컨테이너가 프로토타입 빈을 관리하지 않는 시점이란게 ac.getBean(PrototypBean.class) 을 실행한 바로 이후가 맞을까요? 2. ac.getBean(PrototypBean.class) 를 통해 빈을 반환하였고 그 뒤로는 스프링 컨테이너에서 해당 빈을 관리하지 않는다면 왜 프로토타입 빈이 여전히 스프링 컨테이너에서 조회가 되는지 궁금합니다. 제가 생각해본 바로는 ac.getBean(PrototypBean.class) 이후에는 스프링 컨테이너에 해당 프로토타입빈이 존재하지 않지만, 해당 프로토타입 빈의 beanDefintion은 여전히 존재하여 위와 같은 결과가 나왔다라고 생각이 들었는데 이게 맞을까요? 3. 해당 PrototypeBean 클래스에는 @PostConstruct 어노테이션을 통해 프로토타입 스프링빈이 의존관계 주입을 마칠떄 beanDefinitionName = ... 메세지가 뜨도록 설정하였습니다. 그런데 위 예제에서는AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);코드로 한번PrototypeBean bean = ac.getBean(PrototypeBean.class);코드로 두번 프로토타입 빈을 요청하였으므로 해당 메세지가 2번이 떠야하는게 아닌가요? 왜 한번만 발생하는지 궁금합니다. 이것도 제가 생각해본 바로는 스프링컨테이너를 생성하는 시점에 싱글톤타입과 다르게 프로토타입은 beanDefinition 만 생성이되고 스프링빈이 생성되지는 않기 때문에 위와 같은 결과가 나왔다라고 생각이 들었는데 이게 맞는 내용인지 궁금합니다.
- 미해결스프링 핵심 원리 - 기본편
XmlAppContext 관련 문의
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]XmlAppContext 테스트 실행시키니까 강의에서 나온것처럼 않뜨고 이런식으로 뜨는데 이게 원래 그런건가요?00:56:47.686 [main] WARN org.springframework.core.LocalVariableTableParameterNameDiscoverer -- Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: helllo.core.Member.MemberServiceImpl00:56:47.698 [main] WARN org.springframework.core.LocalVariableTableParameterNameDiscoverer -- Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: helllo.core.Order.OrderServiceImpl
- 해결됨스프링 핵심 원리 - 기본편
AppConfig 작성시 인스턴스 일치 문제관련
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]AppConfig 작성시 사진과 같이 코드를 작성하면 OrderServiceImple 에 들어가는 MemoryMeberRepository랑 Memberservice에 들어가는 MemoryMeberRepository 각 각 new 로 생성하여 할당했으므로 둘이 동기화가 안돼는 거 아닌가요??
- 미해결스프링 핵심 원리 - 기본편
@Configuration
안녕하세요! 싱글톤 강의 듣다가 궁금한 점이 있어서 질문 남깁니다.우선 제가 이해한 내용이 맞는지 확인 부탁드립니다.@Configuration을 붙이지 않고, @Bean만 붙인 객체들은 생성하면 빈에 등록되며, 빈 컨테이너에 의해 관리는 되지만 @Configuration를 붙이지 않았기 때문에 스프링이 AppConfig CGLIB라는 라이브러리를 사용하지 않아서 동일한 객체를 가지고 오지 않아 싱글톤이 보장되지 않는다. 맞나요? 그래서 @Configuration을 쓰지 않았을 때 memberRepository가 3번 출력이 되는 것 까지는 이해했습니다..제가 이해가 안 가는 부분은 MemberServiceImpl에 들어있는 memberRepository가 왜 new MemoryMemberRepository()를 넣어준 것과 같나요? 왜 스프링 컨테이너가 관리하지 않나요...? AppConfig에서 memberRepository()에서 new MemoryMemberRepository() 해줬는데 여기에 싱글톤 적용이 되지 않아서 계속 new 해준 것과 같다는 의미인가요?
- 미해결스프링 핵심 원리 - 기본편
AllBeanTest시, NoUniqueBeanDefinitionException 오류
AllBeanTest에서,강사님하고는 다른 오류가 뜹니다 ㅠ < 강사님 오류 > < 저의 오류 >org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderServiceImpl' defined in file [C:\study2\core\out\production\classes\hello\core\order\OrderServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core.discount.DiscountPolicy' available: expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy 라고 뜨는데, 왜 강사님과 다르게 저는 빈이 2개가 있다는 오류가 뜰까요?? ㅠㅠ orderServiceImplpackage hello.core.order; import hello.core.annotation.MainDiscountPolicy; import hello.core.discount.DiscountPolicy; import hello.core.member.Member; import hello.core.member.MemberRepository; import hello.core.member.MemoryMemberRepository; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.AutoConfigurationPackage; import org.springframework.stereotype.Component; @Component public class OrderServiceImpl implements OrderService{ private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy; // final이 붙으면 필수값이 됨.@RequiredArgsConstructor는 필수값을 가지고 생성자를 만들어준다. @Autowired private DiscountPolicy rateDiscountPolicy; @Autowired public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) { this.memberRepository = memberRepository; this.discountPolicy = discountPolicy; } @Override public Order createOder(Long memberId, String itemName, int itemPrice) { Member member = memberRepository.findById(memberId); int discountPrice = discountPolicy.discount(member, itemPrice); return new Order(memberId, itemName, itemPrice, discountPrice); } public MemberRepository getMemberRepository(){ return memberRepository; } } RateDiscountPolicypackage hello.core.discount; import hello.core.annotation.MainDiscountPolicy; import hello.core.member.Grade; import hello.core.member.Member; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; @Component public class RateDiscountPolicy implements DiscountPolicy{ private int discountPercent = 10; @Override public int discount(Member member, int price) { if(member.getGrade() == Grade.VIP){ return price * discountPercent / 100; } else { return 0; } } } FixDiscountPolicypackage hello.core.order; import hello.core.annotation.MainDiscountPolicy; import hello.core.discount.DiscountPolicy; import hello.core.member.Member; import hello.core.member.MemberRepository; import hello.core.member.MemoryMemberRepository; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.AutoConfigurationPackage; import org.springframework.stereotype.Component; @Component public class OrderServiceImpl implements OrderService{ private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy; // final이 붙으면 필수값이 됨.@RequiredArgsConstructor는 필수값을 가지고 생성자를 만들어준다. @Autowired private DiscountPolicy rateDiscountPolicy; @Autowired public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) { this.memberRepository = memberRepository; this.discountPolicy = discountPolicy; } @Override public Order createOder(Long memberId, String itemName, int itemPrice) { Member member = memberRepository.findById(memberId); int discountPrice = discountPolicy.discount(member, itemPrice); return new Order(memberId, itemName, itemPrice, discountPrice); } public MemberRepository getMemberRepository(){ return memberRepository; } } AppConfigpackage hello.core; import hello.core.discount.DiscountPolicy; import hello.core.discount.FixDiscountPolicy; import hello.core.discount.RateDiscountPolicy; import hello.core.member.MemberService; import hello.core.member.MemberServiceImpl; import hello.core.member.MemoryMemberRepository; import hello.core.order.OrderService; import hello.core.order.OrderServiceImpl; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; // @Bean memberService -> new MemoryMemberRepository() // @Bean orderService -> new MemoryMemberRepository() // call AppConfig.memberService // call AppConfig.memberRepository // call AppConfig.memberRepository // call AppConfig.orderService // call AppConfig.memberRepository // 예상은 위와 같지만, 실제 실행된 것은 // call AppConfig.memberService // call AppConfig.memberRepository // call AppConfig.orderService @Configuration public class AppConfig { @Bean public MemberService memberService() { System.out.println("call AppConfig.memberService"); return new MemberServiceImpl(memberRepository()); } @Bean public MemoryMemberRepository memberRepository() { System.out.println("call AppConfig.memberRepository"); return new MemoryMemberRepository(); } @Bean public OrderService orderService() { System.out.println("call AppConfig.orderService"); return new OrderServiceImpl(memberRepository(), discountPolicy()); // return null; } @Bean public DiscountPolicy discountPolicy() { //return new FixDiscountPolicy(); return new RateDiscountPolicy(); } } AllbeanTestpackage hello.core.Autowired; import hello.core.AutoAppConfig; import hello.core.discount.DiscountPolicy; import hello.core.member.Grade; import hello.core.member.Member; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import java.util.List; import java.util.Map; import static org.assertj.core.api.Assertions.*; public class AllBeanTest { @Test void findAllBean(){ ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class); DiscountService discountService = ac.getBean(DiscountService.class); Member member = new Member(1L, "userA", Grade.VIP); int discountPrice = discountService.discount(member, 10000, "fixDiscountPolicy"); // discount가 얼마나 되는지 보는 서비스 assertThat(discountService).isInstanceOf(DiscountService.class); assertThat(discountPrice).isEqualTo(1000); } static class DiscountService { private final Map<String, DiscountPolicy> policyMap; private final List<DiscountPolicy> policies; @Autowired public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) { this.policyMap = policyMap; this.policies = policies; System.out.println("policyMap = " + policyMap); System.out.println("policies = " + policies); } public int discount(Member member, int i, String fixDiscountPolicy) { return 0; } } }
- 해결됨스프링 핵심 원리 - 기본편
빌드가 안됩니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]project에 강의 영상과 달리 Gradle 이 두개가 있길래 첫번째 선택후 영상과 동일한 방법으로 파일을 열었는데 이런 에러가 뜹니다. 뭐가 문제 일까요??
- 해결됨스프링 핵심 원리 - 기본편
초기 설정 sync 에러
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 네2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 아니요3. 질문 잘하기 메뉴얼을 읽어보셨나요? 넵[질문 내용] No matching variant of org.springframework.boot:spring-boot-gradle-plugin:3.1.1 was foundsync에서 이 문구가 계속 뜹니다ㅠㅠ- Incompatible because this component declares a component, compatible with Java 17 and the consumer needed a component, compatible with Java 11이거랑 같이 여러개가 뜨는데 뭐가 문제일까요? 17 설치해놨었는데 11 사용한다고 하셔서 11 다시 설치하고 환경변수까지 바꿔놨는데 계속 뜨네요...
- 미해결스프링 핵심 원리 - 기본편
생성자 주입 문의
[질문 내용]안녕하세요. 생성자 주입을 권장한다는 말씀을 듣고 의문이 생겨 문의드립니다.만약 개발 도중 생성자 필드가 추가가 된다면 해당 생성자 부분 코드를 건드리게 될텐데, 그에 따라 해당 생성자를 사용했던 코드들이 전부 오류가 날 것이고 변경이 필요할 것 같습니다.해당 사항이 발생하더라도 생성자 주입 방식을 제일 권장하시는 걸까요?
- 미해결스프링 핵심 원리 - 기본편
8분20초 쯤에 return 값에서 빨간줄이 쳐집니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.여기에 질문 내용을 남겨주세요.제가 어디 놓친 부분이 있을까요??ㅠㅠ 되돌려봤는데도 다시 써봐도 해결이 안되네요ㅠㅠ
- 미해결스프링 핵심 원리 - 기본편
이클립스 프로젝트 오류
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]start.spring.io에서 저대로 설정하고 이클립스에서 바로 불러오기하면 두번째사진처럼 에러가 납니다. 뭐가 문제인지 모르겠어요ㅠㅠ
- 미해결스프링 핵심 원리 - 기본편
Bean annotation 위치 질문
AppConfig.java에서 memberRepository와 discountPolicy에도 @Bean annotation을 붙이는 이유가 궁금합니다. 외부적으론 Service만 사용되고 Bean 로드 시에도 없어도 문제없이 실행되는것으로 보이는데, 특별한 이유가 있을까요?
- 미해결스프링 핵심 원리 - 기본편
스프링 웹 애플리케이션 실행 시 main 스레드 및 내장 톰캣
처음에 SpringApplication.run(UploadApplication.class, args); 실행하면main스레드에 의해서 스프링 컨테이너 및 웹서버 생성 등 작업을 완료하고 나면main 스레드는 listening 작업을 하나요? 어떤 상태가 되나요내장 톰캣이란 게 결국 스프링이 톰캣 라이브러리를 jar파일로 가지고 있다고 인지하면 될까요소켓 여는 라이브러리부터service로직 호출하는 org.apache.coyote.http11;필터를 호출하는 org.apache.catalina.core; 등이 WAS인가요?
- 미해결스프링 핵심 원리 - 기본편
생성자 주입
여기서 setter메서드 상관없이 생성자가 1개 이니깐 자동 주입 되는 줄 알았는데 왜 주입이 안되나요??
- 미해결스프링 핵심 원리 - 기본편
getBean 반환값
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]스프링 컨테이너에있는 스프링 빈 저장소에는 AppConfig에 있던 메소드 이름을 빈 이름으로 사용하고 빈 객체에는 return에 적혀있는 객체를 저장하는 걸로 이해했습니다. 강의 당시 AppConfig에 DiscountPolicy에는 RateDiscountPolicy의 객체가 return되게 되어있는데 상속에 관한 spring bean조회를 할 때ac.getBean("fixDiscountPolicy, DiscountPolicy.class)를 하면 FixDiscountPolicy 타입의 객체가 반환이 됩니다. 스프링 빈에 올라가는 것들은 AppConfig에 있는 정보로 올라가는 것 외에도 다른 방식으로도 올라가는 것처럼 보이는데 이 부분에 대해 설명해주시면 감사하겠습니다.
- 미해결스프링 핵심 원리 - 기본편
@Configuration 에 대한 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.[질문 내용]@Configuration을 사용하면 우측에 있는 빈들끼리의 의존관계를 스프링 컨테이너가 설정해주어 빈 이름이 같은 경우 같은 빈 객체를 호출하지만 @Configuration을 사용하지 않으면 스프링 컨테이너가 의존관계를 직접적으로 설정해주진 않아 memberServiceImpl 로 호출하는 memoryMemberRe~와 memberRepo~로 호출하는 memoryMemberRe~가 다른걸까요??
- 미해결스프링 핵심 원리 - 기본편
인터페이스와 구현체 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.강의를 듣다가 갑자기 의문점이 들어서 질문올립니다.public interface DiscountPolicy { int discount(Member member, int price); } 이 코드는 인터페이스이고public class FixDiscountPolicy implements DiscountPolicy{ private int discountFixAmount = 1000; //1000원 할인 @Override public int discount(Member member, int price) { if(member.getGrade() == Grade.VIP) { return discountFixAmount; } else { return 0; } } } 이 코드는 구현체입니다.그런데 궁금한 점은private final DiscountPolicy discountPolicy = new FixDiscountPolicy();에서 discountFixAmount 변수를 사용할 수 있는 이유가 무엇인가요? 타입이 DiscountPolicy이기 때문에 인터페이스에는 없고 구현체에만 있는 메서드나 변수는 사용 할 수 없는거 아닌가요?