공부해요/Spring

2.용어정리(2)-IoC,DI,Bean

예쁜꽃이피었으면 2021. 12. 8. 13:32

 

의존성
1) 의존은 변경에 의해 영향을 받는 관계를 의미한다.
2) 한 클래스가 다른 클래스의 메서드를 실행할 때 이를 '의존한다'라고 한다.(= 한 객체가 다른 객체를 사용할 때)
3) A가 B를 사용해야만 A의 역할을 수행할 수 있는 경우 
4) '변경에 의해 영향을 받는 관계', 의존한다는 것은 변경에 유연하지 못함을 의미한다.
IoC
프로그램이 개발자에게 틀을 강요해서 그 형식으로 만들게 하는것
IoC = DI + DL

DI
강요하는 내용들 ex) 박스를 만들때 높이는 4cm, 너비는 10cm로 해라 등등
장점 : 모양이 정형화 됨으로 유지및 관리가 쉽다.

IoC(Inversion of Control, 제어의 역전)

- 메소드나 객체의 호출작업을 개발자가 결정하는 것이 아니라, 외부에서 결정되는 것을 의미한다.

- 제어의 역전 : 제어의 흐름을 바꾼다.

  => 의존성을 역전시켜 객체 간의 결합도를 줄이고 유연한 코드를 작성할 수 있게하여 가독성 및 코드 중복, 유지 보수를 편하게 할 수 있게 한다.

- 프레임워크 기반의 개발에서는 프레임워크 자신이 흐름을 제어하는 주체가 되어, 필요할때 마다 어플리케이션 코드를 호출하여 사용한다. 프레임워크에서 제어권을 갖는 것은 컨테이너(Container)이다. 객체에 대한 제어권이 개발자로부터 컨테이너에게 넘어가면서 객체의 생성부터 생성주기관리까지의 모든 것을 컨테이너가 도맡아 하게 되었다. 이를 일반적인 제어권의 흐름이 바뀌었다고 하여 IoC(제어의 역전)라고 부른다.

   => 컨테이너가 코드 대신 오브젝트의 제어권을 갖고 있어 IoC(제어의 역전)이라 한다.

- IoC = DI + DL

기존의 객체 생성 및 실행 스프링의 객체 생성 및 실행
1. 객체 생성
2. 의존성 객체 생성
- 내부 클래스에서 생성
3. 의존성 객체 메소드 호출
1. 객체 생성
2. 의존성 객체 주입
- 스스로가 만드는 것이 아니라 제어권을 스프링에게 위임하여 스프링이 만들어 놓은 객체를 주입한다.
3. 의존성 객체 메소드 호출
=> 스프링이 모든 의존성 객체를 스프링이 실행될 때 다 만들어주고 필요한 곳에 주입시켜 줌으로써 Bean들은 싱글톤 패턴의 특징을 가지며, 제어의 흐름을 사용자가 컨트롤 하는 것이 아니라 스프링에게 맡겨 작업을 처리하게 된다.

 

더보기

 


DL(Dependency Lookup , 의존성 검색)

- 컨테이너에서는 객체들을 관리하기 위해 별도의 저장소에 Bean을 저장하는데 저장소에 저장되어 있는 컨테이너에서 제공하는 API를 이용하여 사용하고자 하는 Bean을 검색하는 방법


DI(dependency Injection, 의존성 주입)

- 객체의 의존성을 외부에서 주입하는 개념

  = 필요한게 있으면 내가 직접 만드는 것이 아니라 선언을 통해 외부에서 알아서 제공해주겠다고 하는 것

- 외부에서 두 객체간의 관계를 결정해주는 디자인패턴

- 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 다이나믹하게 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.

- DI는 클래스 사이의 의존관계를 빈 설정정보를 바탕으로 컨테이너가 자동적으로 연결해주는 것을 말한다.

- IoC가 공장으로 인스턴스를 만들었다면 그걸 실제로 우리가 사용을 해야하는데 그걸 도와주는게 DI의 기능이다. 그 인스턴스를 객체화시켜서 객체를 주입시키는 기능이다.

 

- 의존성 주입 방법(3) - https://martinfowler.com/articles/injection.html

1) setter메소드를 이용한 의존성 삽입(Setter Injection : type 2 IoC)

: 의존성을 입력받는 setter메소드를 만들고 이를 통해 의존성을 주입한다.

더보기

setter()메소드는 외부에서 오브젝트 내부의 attribute값을 변경하려는 용도로 주로 사용된다.

핵심기능은 파라미터로 전달되는 값을 내부의 인스턴스 변수에 저장하는 것이다.

스프링에서 지지하는 DI방식으로, 외부에서 제공받은 오브젝트 레퍼런스를 저장해뒀다가 내부의 메소드에서 사용하게 하는 DI방식에서 활용하기에 적당하다.

Setter Injection with Spring

The Spring framework is a wide ranging framework for enterprise Java development. It includes abstraction layers for transactions, persistence frameworks, web application development and JDBC. Like PicoContainer it supports both constructor and setter injection, but its developers tend to prefer setter injection - which makes it an appropriate choice for this example.

To get my movie lister to accept the injection I define a setting method for that service

class MovieLister...

  private MovieFinder finder;
public void setFinder(MovieFinder finder) {
  this.finder = finder;
}

Similarly I define a setter for the filename.

class ColonMovieFinder...

  public void setFilename(String filename) {
      this.filename = filename;
  }

The third step is to set up the configuration for the files. Spring supports configuration through XML files and also through code, but XML is the expected way to do it.

<beans>
    <bean id="MovieLister" class="spring.MovieLister">
        <property name="finder">
            <ref local="MovieFinder"/>
        </property>
    </bean>
    <bean id="MovieFinder" class="spring.ColonMovieFinder">
        <property name="filename">
            <value>movies1.txt</value>
        </property>
    </bean>
</beans>

The test then looks like this.

public void testWithSpring() throws Exception {
    ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");
    MovieLister lister = (MovieLister) ctx.getBean("MovieLister");
    Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
    assertEquals("Once Upon a Time in the West", movies[0].getTitle());
}

2) 생성자를 이용한 의존성 삽입(Constructor Injection : type 1 IoC)

: 필요한 의존성을 모두 포함하는 클래스의 생성자를 만들고 그 생성자를 통해 의존성을 주입한다.

즉, 생성자에 파라미터를 만들어두고 이를 통해 DI컨테이너가 의존할 오브젝트 레퍼런스를 넘겨주는 방식

더보기

 

class MovieLister...

  public MovieLister(MovieFinder finder) {
      this.finder = finder;       
  }

The finder itself will also be managed by the pico container, and as such will have the filename of the text file injected into it by the container.

class ColonMovieFinder...

  public ColonMovieFinder(String filename) {
      this.filename = filename;
  }

The pico container then needs to be told which implementation class to associate with each interface, and which string to inject into the finder.

private MutablePicoContainer configureContainer() {
    MutablePicoContainer pico = new DefaultPicoContainer();
    Parameter[] finderParams =  {new ConstantParameter("movies1.txt")};
    pico.registerComponentImplementation(MovieFinder.class, ColonMovieFinder.class, finderParams);
    pico.registerComponentImplementation(MovieLister.class);
    return pico;
}

This configuration code is typically set up in a different class. For our example, each friend who uses my lister might write the appropriate configuration code in some setup class of their own. Of course it's common to hold this kind of configuration information in separate config files. You can write a class to read a config file and set up the container appropriately. Although PicoContainer doesn't contain this functionality itself, there is a closely related project called NanoContainer that provides the appropriate wrappers to allow you to have XML configuration files. Such a nano container will parse the XML and then configure an underlying pico container. The philosophy of the project is to separate the config file format from the underlying mechanism.

To use the container you write code something like this.

public void testWithPico() {
    MutablePicoContainer pico = configureContainer();
    MovieLister lister = (MovieLister) pico.getComponentInstance(MovieLister.class);
    Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
    assertEquals("Once Upon a Time in the West", movies[0].getTitle());
}

Although in this example I've used constructor injection, PicoContainer also supports setter injection, although its developers do prefer constructor injection.


3) 초기화 인터페이스를 이용한 의존성 삽입(Interface Injection : type 3 IoC)

: 의존성을 주입하는 함수를 포함한 인터페이스를 작성하고 이 인터페이스를 구현하도록 함으로써 실행시에 이를 통하여 의존성을 주입한다.

더보기

가장 먼저 Injection을 하기 위한 인터페이스를 정의한 후, 구현하면 DI가 이루어지도록 한다.

이건 스프링이 지원하지 않는 DI방식이다. 


 

 


Bean / Bean Factory

- 스프링 IoC컨테이너가 관리하는 객체

- 스프링에서는 이 Bean들을 관리한다는 의미로 컨테이너를 빈 팩토리(Bean Factory)하고 부른다.(= 팩토리 디자인 패턴 구현)

- 컨테이너(Container) = 빈 팩토리(Bean Factory) : 오브젝트의 생성과 오브젝트 사이의 런타임관계를 설정하는 DI관점에서 볼 때

- 애플리케이션 컨텍스트(Application Context) = DI기능 + 여러 컨테이너 기능(엔터프라이즈 어플리케이션을 개발 할 때 필요한..)

 


Spring에서 제공하는 IoC/DI컨테이너

- BeanFactory : IoC/DI에 대한 기본 기능을 가지고 있다.

- ApplicationContext : BeanFactory의 모든 기능을 포함하며, 일반적으로 BeanFactory보다 추천된다.

  트랜잭션처리, AOP 등 에대한 처리를 할 수 있다.

  BeanPostProcessor, BeanFactoryPostProcessor등을 자동으로 등록하고, 국제화처리,

  어플리케이션 이벤트 등을 처리할 수 있다.

- BeanPostProcessor : 컨테이너의 기본로직을 오버라이딩하여 인스턴스화와 의존성 처리 로직 등을

  개발자가 원하는대로 구현할 수 있도록 한다.

- BeanFactoryPostProcessor : 설정된 메타 데이터를 커스터 마이징 할 수 있다.

 


Bean class

- 예전에는 비쥬얼한 컴포넌트를 Bean이라고 불렀지만, 요즘에는 일반적인 JAVA클래스를 Bean라고 말한다.

- Bean class의 특징(3)

  1) 기본 생성자를 가지고 있다.

  2) 필드는 private하게 선언한다.

  3) getter, setter메소드를 가진다. -> getName(), setName()메소드를 name property라고 한다.

 

 


[참조]

https://greatlaboratory.dev/spring/spring-01/

https://velog.io/@suwon-city-boy/%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%B4%EB%9E%80

 

 

반응형