[35일차] DI(의존성 주입, 컨테이너, 빈 ,@Configuration, @Bean)

유태형·2022년 6월 16일
0

코드스테이츠

목록 보기
35/77

오늘의 목표

  1. 의존성 주입
  2. 컨테이너
  3. @Configuration, @Bean



내용

의존성 주입

현재 클래스 100곳에서 CurrentDiscountInfo클래스의 객체를 쓰던중이었지만, 요구사항이 바뀌면서 RateDiscountInfo라는 새로운 클래스를 선언하여 기존의 CurrentDiscountInfo 대신 사용해야 한다면, 의존성을 고려하지 않았았으면 CurrentDiscountInfo를 사용하던 모든 100곳의 클래스에서 RateDiscountInfo로 변경해주어야 할 것입니다.

Class 클래스{
	// DiscountInfo discount = new CurrentDiscountInfo();
    // 클래스 100곳 모두 수정
    DiscountInfo discount = new RateDiscountInfo();
}

클래스 내부에서 의존하는 객체를 선언하는 것이 아닌, 외부에서 객체를 선언하여 해당 클래스로 의존 객체를 주입한다면 100 곳 모든 클래스가 아니라 주입시켜주는 부분 1곳만 수정하면 될 것입니다.

Class 클래스{
	DiscountInfo discount;
    
    //의존성 외부 주입
    public 생성자(DsicountInfo discount){
    	this.discount = discount;
    }
}
Class Config{ //의존성을 주입해주는 객체
	public DiscountInfo discountInfo(){
    	// return new CurrentDiscountInfo();
        //1곳만 수정 -> 100곳 클래스 수정x
    	return new RateDiscountInfo();
    }
}

의존도가 높으면 결합성이 높아지고 캡슐화가 낮아집니다. 객체지향은 낮은 결합성과 높은 캡슐화로 객체간 주는 영향을 줄여야 합니다. 따라서 의존 객체를 외부에서 주입해 줌으로써 의존도를 낮추는 것은 매우 유지보수, 테스트, 에러 수정에서 중요합니다.




컨테이너(Spring Container)

Collection Framework와 비슷하게 ApplicationContext 인터페이스를 구현한 구현체들이 만든 빈 메타 정보를 받는 곳을 스프링 컨테이너라고 부릅니다.

스프링 컨테이너IoC 개념을 이용하여 Bean객체로 만들고, 수정하고, 삭제하고, 의존 주입하고, 등등 여러가지 일을 개발자가 아닌 스스로 객체의 생명주기를 관리합니다.

예전에는 xml을 통하여 모두 설정 하였었지만, Spring Boot을 사용하면서 거의 사용하지 않고 애너테이션을 사용합니다.

스프링 컨테이너의 특징은 아래와 같습니다.

  1. 스프링 컨테이너는 Configuration Metadata를 사용합니다.
  2. 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 빈을 등록합니다.
  3. new AnnotaionConfigApplicationContext(Config클래스.class) 내에 존재하는 @Bean메서드 등록합니다.
  4. 에너테이션 기반 컨테이너 구성합니다.

스프링 컨테이너에게 빈 메타 정보를 전달해주는 객체 생성

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(컨테이너.class);

스프링 컨테이너도 컬렉션 프레임워크와 마찬가지로 인터페이스를 상속 받는 인터페이스가 존재하고 인터페이스를 구현한 구현체가 존재합니다.



Bean Factory

  • 스프링 컨테이너의 최상위 인터페이스 입니다.
  • BeanFactory는 빈을 등록하고 생성하고 조회하는 등 관리하는 역할을 수행합니다.
  • getBean()메서드를 통해 빈을 인스턴스화 시킵니다.
  • @Bean 애너테이션이 붙은 메서드를 통해 빈을 등록합니다.


ApplicationContext

  • BeanFactory의 기능을 상속받는 인터페이스입니다.
  • BeanFactory + @ 부가기능 제공합니다.

ApplicationContext는 인터페이스고 AnnotataionConfigApplicationContextApplicationContext를 구현한 구현체중 하나입니다.




빈(Bean)

스프링 컨테이너가 빈의 생성부터 소멸까지(다르게 설정 가능) 생명주기를 관리합니다.

Bean은 스프링 컨테이너에 인스턴스화 된 객체를 의미합니다.
@Configuration클래스에 @Bean메서드로 적힌 메서드를 호출해서 설정 메타디이터에 따라 스프링 컨테이너의 객체로 등록합니다.

//@Configuration의 @Bean메서드들 호출하여 객체를 만듭니다.
ApplicationContext ac = new AnnotationConfigApplicationContext(컨픽.class);
빈객체 b = ac.getBean("메서드명",빈클래스.class); //스프링 컨테이너의 빈객체를 반환합니다.


BeanDefinition

스프링은 다양한 설정 형식을 BeanDefinition이라는 추상화 덕북에 지원할 수 있습니다.

Bean은 BeanDefinition(빈 설정 메타정보)속성에 따라 생성되고 활용하는 방법이 달라지게 됩니다.

빈 1개당 1개의 메타 정보가 생성되며 스프링 컨테이너는 설정 형식이 XML, Java코드인지 모르고 BeanDefninition만 알면 됩니다.



빈 스코프(Bean Scope)

스코프(Scope)란 어느 범위까지 사용가능할지, 또 언제까지 사용 가능할지를 정의해둔 속성입니다. Bean Definition에 정의된 설정 메타 정보에 따라 Bean객체 각각의 스코프가 정의됩니다.

Bean의 은 여러 범위 중 하나에 배치되도록 정의할 수 있고, 사용자 정의 범위를 생성할 수 도 있습니다.

ScopeDescription
singleton(기본)각 Spring 컨테이너에 대한 단일 객체 인스턴스만 생성합니다.
prototype생성과 의존관계 주입까지만 관여하고 그 이상은 관리하지 않습니다.
request웹 요청이 들어오고 나갈 때 까지 유지는 스코프입니다.
session웹 세션이 생성되고 종료될 때 까지 유지되는 스코프입니다.
application웹 서블릿 컨텍스트(어플리케이션) 범위로 유지 되는 스코프입니다.
websocketWebSocket의 라이플 사이클까지 확장합니다. Spring ApplicationContext의 컨텍스트에서만 유효합니다.

싱글톤(Singleton)

클래스의 인스턴스가 1개 이고 추가 호출시 같은 인스턴스가 반환됩니다.

스프링 컨테이너의 시작과 함께 생성되어 스프링 컨테이너가 종료될때까지 유지되며 공유 인스턴스 하나만 관리하게 됩니다.(싱글톤 빈에 대한 모든 요청은 같은 빈 인스턴스를 반환합니다.)

싱글톤 방식은 여러 클라이언트가 하나의 객체 인스턴스를 공유하기 때문에 싱글톤 객체는 무상태로 설계해야 합니다.

  • 특정 클라이언트가 값을 변경할 수 있으면 안됩니다.
  • 읽기만 가능해야 합니다.
  • 스프링 빈의 공유 값을 설정하면 에러가 발생할 수도 있습니다.



@Configuration, @Bean

@Configuration
public class 컨텍스트{
	@Bean
    public 빈클래스 빈메서드(){
    	return new 빈클래스();
    }
}
  • @Configuration : 컨텍스트 클래스임을 명시합니다. 컨텍스트 클래스 내부에 있는 빈 메서드를 실행하여 스프링 컨테이너에서 관리하도록 객체를 생성합니다.
  • @Bean : 빈 메서드임을 알립니다. 해당 메서드 실행후 생성된 객체들은 스프링 컨테이너에서 관리됩니다.

ApplicationContext ac = new AnnotationConfigApplicationContext(컨텍스트.class);

입력시
1. 스프링 컨테이너를 인스턴스화 합니다.
2. @Configuration 클래스 자체가 Bean 정의로 등록되고 클래스 내에서 선언된 @Bean 메서드도 Bean정의로 등록됩니다.
3. @Component 클래스, JSR-330클래스 가 @Autowired, @Inject와 같이 DI메타데이터가 사용되는 것으로 가정합니다.

public interface 인터페이스{
	@Bean
    빈클래스 빈메서드(){
    	return new 빈클래스();
    }
}

@Configuration
public class 클래스 implements 인터페이스{

}

빈메서드가 존재하는 인터페이스를 구현하여 Configuration 클래스를 정의할 수 도 있습니다.

@Configuration
public class 컨텍스트{
	@Bean
    public BeanOne beanOne(){
    	return new BeanOne(beanTwo());
    }
    
    @Bean
    public BeanTwo beanTwo(){
    	return new BeanTwo();
    }
}

빈이 서로 의존성을 가질 때, 의존성을 표현하는 것은 다른 Bean 메서드를 호출하는 것 입니다.

@Configuration
public class ServiceConfig {

    @Bean
    public TransferService transferService(AccountRepository accountRepository) {
        return new TransferServiceImpl(accountRepository);
    }
}

@Configuration
public class RepositoryConfig {

    @Bean
    public AccountRepository accountRepository(DataSource dataSource) {
        return new JdbcAccountRepository(dataSource);
    }
}

@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
	@Bean(name="ThisIsName")
    public DataSource dataSource(){
    	return new DataSource();
    }
}
public static void main(String[] args){
	ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.clas);
    TransferService transferService = ctx.getBean(TransferService.class);
    AccountRepository accountRepository = ctx.getBean(AccountRepository.class);
    DataSource dataSource = ctx.getBean("ThisIsName");
}

@Import 애너테이션을 사용하여 다른 컨텍스트들의 빈 객체들을 가져올 수 있습니다.

@Import(컨택스트.class)는 1개의 컨택스트를 참조할 수 있고, @Import({컨텍스트1.class, 컨텍스트2.class, ...})형식으로 여러개의 컨텍스트들을 동시에 참조할 수 있습니다.

@Import 애너테이션을 사용하여 여러개의 @Configuration 컨텍스트들을 기억하고 생성할 필요없이 하나의 컨텍스트만 처리하면 됩니다.

@Bean 애너테이션에 name속성을 지정할 수 있습니다. getBean()등 빈 메서드를 구분할때 메서드명을 입력할 수도 있는데 이 때 name속성을 지정하여 메서드명을 다른 이름으로 지정이 가능합니다.
(name속성 == 빈메서드명 일때 에러발생 할 수 있으니 다른 이름 지정)




후기

Spring은 유지보수와 확장을 중요시하는 프레임워크입니다. 따라서 DI개념은 Spring에서 많은 중요한 부분을 차지합니다. 오늘은 그중에서도 중요한 컨테이너, 컨텍스트, 빈에 대하여 공부하였습니다. 정말 정말 중요한 부분인것 같습니다.




GitHub

https://github.com/ds02168/CodeStates_Spring/tree/main/cmarket

profile
오늘도 내일도 화이팅!

0개의 댓글