[Spring] 정리(1)

박찬영·2024년 6월 28일

Spring

목록 보기
39/42

1. ApplicationContext

ApplicationContext applicationContext = 
	new AnnotationConfigApplicationContext(AppConfig.class);

MemberService memberService = 
	applicationContext.getBean("memberService", MemberService.class);
    
OrderService orderService = 
	applicationContext.getBean("orderService", OrderService.class);
  • ApplicationContext를 스프링 컨테이너라 한다.
  • ApplicationContext는 인터페이스이다.
  • 스프링 컨테이너는 XML을 기반으로 만들 수 있고, 애노테이션 기반의 자바 설정 클래스로 만들 수 있다.
    • ex) AnnotationConfigApplicationContext (애노테이션 기반)
  • 기존에는 개발자가 AppConfig를 사용해서 직접 객체를 생성하고 DI를 했지만, 이제부터는 스프링 컨테이너를 통해서 사용한다.
  • 스프링 컨테이너는 @Configuration이 붙은 AppConfig를 설정(구성) 정보로 사용한다. 여기서 @Bean이라 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다. 이렇게 스프링 컨테이너에 등록된 객체를 스프링 빈이라 한다.
  • 스프링 빈은 @Bean이 붙은 메서드의 명을 스프링 빈의 이름으로 사용한다.
  • 이전에는 개발자가 필요한 객체를 AppConfig를 사용해서 직접 조회했지만, 이제부터는 스프링 컨테이너를 통해서 스프링 빈(객체)를 찾아야 한다.

2. @Configuration, @Bean

@Configuration
public class AppConfig {
    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }
    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
}

3. @ComponentScan & @Component, @Autowired

@Configuration
@ComponentScan
public class AutoAppConfig {

}
  • 컴포넌트 스캔을 사용하려면 먼저 @ComponentScan을 설정 정보에 붙여주면 된다.
  • 컴포넌트 스캔을 사용하면 @Configuration이 붙은 설정 정보를 자동으로 등록한다.
  • @Bean으로 등록한 클래스가 하나도 없다.
//MemoryMemberRepository @Component 추가
@Component
public class MemoryMemberRepository implements MemberRepository {}
//OrderServiceImpl @Component, @Autowired 추가
@Component
public class OrderServiceImpl implements OrderService {

 	private final MemberRepository memberRepository;
 	private final DiscountPolicy discountPolicy;
 
 	@Autowired
 	public OrderServiceImpl(MemberRepository memberRepository, 
    							DiscountPolicy discountPolicy) {
        
 		this.memberRepository = memberRepository;
 		this.discountPolicy = discountPolicy;
 	}
}
  • @Autowired를 사용하면 생성자에서 여러 의존관계도 한번에 주입받을 수 있다.
  • 생성자가 딱 1개만 있으면 @Autowired를 생략해도 자동 주입이 된다!
//@RequiredArgsConstructor
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
 	private final MemberRepository memberRepository;
 	private final DiscountPolicy discountPolicy;
}
  • @RequiredArgsConstructor 기능을 사용하여 final이 붙은 필드를 모아서 생성자를 자동으로 만든 코드이다.

3.1 @Primary

ac.getBean(DiscountPolicy.class)
  • @Autowired는 타입으로 조회하기 때문에, 마치 위의 코드와 유사하다
  • 타입으로 조회하면 선택된 빈이 2개 이상일 때 문제가 발생한다.
    • ex) DiscountPolicy의 FixDiscountPolicy , RateDiscountPolicy
  • @Primary로 해결
//@Primary 사용

@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}

@Component
public class FixDiscountPolicy implements DiscountPolicy {}
  • @Primary는 우선순위를 정하는 방법이다.
  • @Autowired 시에 여러 빈이 매칭되면 @Primary가 우선권을 가진다.

3.2 ComponetScan 관련 함수

3.2.1 basePackages & basePackageClasses
@ComponentScan(
	basePackages = {"hello.core"}
}
  • basePackages : 탐색할 패키지의 시작 위치 지정
  • basePackageClasses : 지정한 클래스의 패키지를 탐색 시작 위치로 지정
3.2.2 Filter
    @Configuration
    @ComponentScan(
            includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, 
            	classes = MyIncludeComponent.class),
            excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, 
            	classes = MyExcludeComponent.class)
    )
    static class ComponentFilterAppConfig {
    }
  • includeFilters에 MyIncludeComponent 애노테이션을 추가해서 BeanA가 스프링 빈에 등록된다.
  • excludeFilters에 MyExcludeComponent 애노테이션을 추가해서 BeanB는 스프링 빈에 등록되지 않는다.

4. initMethod & destroyMethod, @PostConstruct & @PreDestroy

빈 생명주기 콜백

//initMethod & destroyMethod
public void init() {
 	System.out.println("NetworkClient.init");
 	connect();
 	call("초기화 연결 메시지");
 }
 
 public void close() {
 	System.out.println("NetworkClient.close");
 	disConnect();
 }
 
@Configuration
static class LifeCycleConfig {

 	@Bean(initMethod = "init", destroyMethod = "close")
 	public NetworkClient networkClient() {
 		NetworkClient networkClient = new NetworkClient();
 		networkClient.setUrl("http://hello-spring.dev");
 		return networkClient;
 	}
}
  • 스프링 빈이 스프링 코드에 의존하지 않는다.
  • 코드를 고칠 수 없는 외부 라이브러리를 초기화, 종료해야 할 때 사용
//@PostConstruct & @PreDestroy
 @PostConstruct
 public void init() {
 	System.out.println("NetworkClient.init");
 	connect();
 	call("초기화 연결 메시지");
 }
 
 @PreDestroy
 public void close() {
 	System.out.println("NetworkClient.close");
 	disConnect();
 }
 
 @Configuration
static class LifeCycleConfig {

 	@Bean
 	public NetworkClient networkClient() {
 		NetworkClient networkClient = new NetworkClient();
 		networkClient.setUrl("http://hello-spring.dev");
 		return networkClient;
 	}
}
  • 평상시에는 @PostConstruct, @PreDestroy 애노테이션을 사용

5. @Scope

  • 스코프는 번역 그대로 빈이 존재할 수 있는 범위를 뜻한다.
  • 스프링 빈이 기본적으로 싱글톤 스코프로 생성된다.

@Scope("prototype")

  • 프로토타입 : 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여하고 더는 관리하지 않는 매우 짧은 범위의 스코프이다.
//@Scope("prototype") & ObjectProvider
@Scope("prototype")
static class PrototypeBean {
 
 	private int count = 0;
 	
    public void addCount() {
 		count++;
	}
 
 	public int getCount() {
 		return count;
 	}
}
 
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;

public int logic() {
 	PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
 	prototypeBean.addCount();
 	int count = prototypeBean.getCount();
 	return count;
}
  • 싱글톤 빈과 프로토타입 빈을 함께 사용하기 위해선 ObjectProvider 사용

웹 스코프

  • request : HTTP 요청 하나가 들어오고 나갈 때 까지 유지되는 스코프, 각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고, 관리된다.
  • session : HTTP Session과 동일한 생명주기를 가지는 스코프
  • application : 서블릿 컨텍스트( ServletContext )와 동일한 생명주기를 가지는 스코프
  • websocket : 웹 소켓과 동일한 생명주기를 가지는 스코프
profile
블로그 이전했습니다 -> https://young-code.tistory.com

0개의 댓글