인프런 커뮤니티 질문&답변

승현 이님의 프로필 이미지
승현 이

작성한 질문수

스프링 핵심 원리 - 기본편

코드가 완전히 같은데 한쪽은 오류가 발생하고 다른쪽은 오류가 발생하지 않습니다.(git push하고 git clone한 코드결과가 다릅니다)

작성

·

373

·

수정됨

0

왼쪽과 오른쪽은 완전히 동일한 코드입니다. 오른쪽 컴파일러 코드를 깃 push해서 올리고 다른폴더에 git clone해서 실행한게 왼쪽 컴파일러 입니다. (추가적으로 인텔리제이로도 프로젝트를 비교해 봤는데 소스코드에 관해선 동일합니다) 그런데 도대체 왜 오른쪽은 오류가 뜨고 왼쪽은 오류가 뜨지 않는지 궁금합니다. 오류 내용은 맨 아래에 있고 test core에 contextLoads에서 발생한 내용입니다. 오류 내용으로 보건데 memberImple에서 memberRepository의 의존성을 주입하는데 memberRepository랑 MemoryMemberRepository두개의 빈이 존재해서 둘 중 어떤걸 써야 할 지 모르겠다 라는 것 같습니다. 코드는 아래랑 같은데 이게 원래 저 오류가 뜨는게 맞는건지 아닌지도 잘 모르겠습니다. 혹시 이게 롬복관련 강의진행하고 컴퓨터를 다른 컴퓨터로 다시 옮겨서 진행해서 롬복때문인가 싶어서 셋팅도 하고 컴파일러도 껐다가 켜봤습니다.

appconfig에서 MemberRepository가 등록이 되고 AutoAppConfig에서 MemoryMemberRepository가 등록이 되는것 같은데 이름이 다르니까 싱글톤이 적용이 안되는것 같고 이게 MemberServiceImpl 에서 @Autowired로 DI되면 둘 중 어떤걸 해야하는지 모르니까 오류를 내뱉는것 같은데 제가 생각한게 맞는지 궁금합니다.

  1. 제가 생각한게 맞다면 왜 왼쪽은 성공했는지

  2. 틀렸다면 어디가 어떻게 틀렸는지 중간에 싱글톤 개념같이 언급한 부분은 맞는 생각인지

  3. 왜 왼쪽은 성공하고 오른쪽은 틀렸는지

이렇게가 궁금합니다.


추가로 오른쪽 컴파일러에서 원래 실습에서 진행한 테스트 코드에서는 오류가 안뜨고 core에서만 오류가 떴는데 오류가 왜 뜨는지 시험해 보다가 test()테스트케이스를 만들어서 한개의 스프링 컨테이너에 appconfig랑 autoappconfig랑 둘 다 불러오니 거기서 core랑 똑같은 오류가 나서 위에 말한대로 생각한것 입니다.

 

package hello.core;

import hello.core.member.Member;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(
       // basePackages = "hello.core.member", default는 1번째 줄에 있는 패키지 경로
        excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)

)
public class AutoAppConfig {

//    @Bean(name ="memoryMemberRepository")
//    MemberRepository memberRepository(){
//        return new MemoryMemberRepository();
//    }
}
package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberRepository;
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.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
    @Bean
    public MemberRepository memberRepository() {
        System.out.println("call AppConfig.memberRepository");
        return new MemoryMemberRepository();
    }
    @Bean
    public DiscountPolicy discountPolicy() {
        //return new FixDiscountPolicy();
        return new RateDiscountPolicy();
    }
    @Bean
    public MemberService memberService(){
        System.out.println("call AppConfig.memberService");
        return new MemberServiceImpl(memberRepository());
     }
    @Bean
    public OrderService orderService(){
        System.out.println("call AppConfig.orderService");
        return new OrderServiceImpl(memberRepository(), discountPolicy());
     }


}
package hello.core.member;

import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Getter
@Component
public class MemberServiceImpl implements MemberService{
    //Test용도
    private final MemberRepository memberRepository;
    @Autowired
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }

}
package hello.core.member;

import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Component;

@Component
public class MemoryMemberRepository implements MemberRepository{

    private static Map<Long, Member> store = new HashMap<>();//실무에선 컨커뤈트 해쉬맵? 사용함 동시성 이슈
    @Override
    public void save(Member member) {
        store.put(member.getId(),member);
    }

    @Override
    public Member findById(Long memberId) {
        return store.get(memberId);

    }
}

답변 2

0

안녕하세요. 승현 이님, 공식 서포터즈 y2gcoder입니다.

코드가 같은데 해당 에러가 발생하는 것이라면 IDE 쪽을 의심해볼 수 있을 것 같습니다. 아마도 build tool 쪽 문제 같고, 자주하는 질문(클릭)의 해결방안3을 참고해서 확인해보시겠습니까?

감사합니다.

승현 이님의 프로필 이미지
승현 이
질문자

감사합니다 문제는 해결됐습니다. 그런데 그럼 저 코드가 제대로 동작하는 이유가 memoryMemberRepository는 자동등록이고 memberRepository는 수동등록이기 때문에 의존성 주입할 때도 수동등록이 우선으로 등록이 되어 정상적으로 동작하는것 인가요?

스프링 부트 3.2버전으로 올라가면서 매개변수 추론 기능이 빠졌고, 이로 인해 발생한 문제라고 합니다 자세한 내용은 다음 링크(클릭)을 참고해주십쇼!

0

승현 이님의 프로필 이미지
승현 이
질문자

본문에 글자수 제한 때문에 여기에 오류 올립니다


java.lang.IllegalStateException: Failed to load ApplicationContext for [MergedContextConfiguration@69228e85 testClass = hello.core.CoreApplicationTests, locations = [], classes = [hello.core.CoreApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@5bd73d1a, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@70d2e40b, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@7c18432b, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@1a15b789, org.springframework.boot.test.context.SpringBootTestAnnotation@4a6b257f], contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null]

	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:180)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:130)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:141)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:97)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260)
	at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:163)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310)
	at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
	at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberServiceImpl' defined in file [C:\Users\zzan9\Desktop\GithubProject\helloSpring\core\core\out\production\classes\hello\core\member\MemberServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'hello.core.member.MemberRepository' available: expected single matching bean but found 2: memoryMemberRepository,memberRepository
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:802)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:241)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1191)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:960)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:762)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:464)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:334)
	at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137)
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58)
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46)
	at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1458)
	at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:552)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:225)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:152)
	... 17 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core.member.MemberRepository' available: expected single matching bean but found 2: memoryMemberRepository,memberRepository
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:218)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1420)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911)
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789)
	... 41 more

승현 이님의 프로필 이미지
승현 이

작성한 질문수

질문하기