스프링 딥러닝(1)

봄 IOC

의존성 주입

  1. 생성자 주입
  2. 세터 주입
  3. 인터페이스 주입

생성자 주입

public FXNewsProvider(IFXNewsListener newsListner,IFXNewsPersister newsPersister) {
    
     
 	this.newsListener = newsListner; 
	this.newPersistener = newsPersister; 
}

IoC 서비스 제공자는 주입된 객체의 구성 방법을 확인하고 필요한 종속 객체 목록을 얻은 다음 해당 객체를 주입합니다. 동일한 객체가 두 번 생성되는 것은 불가능하므로 주입된 객체의 생성 및 전체 수명 주기는 IoC 서비스 제공자가 관리해야 합니다.

세터 메소드 주입

JavaBean 객체의 경우 해당 속성은 일반적으로 setXXX() 및 getXXX() 메서드를 통해 액세스됩니다. 이러한 setXXX() 메서드를 총칭하여 setter 메서드라고 하며, getXXX()도 물론 getter 메서드라고 합니다. setter 방식을 통해 해당 객체의 속성을 변경할 수 있고, getter 방식을 통해 해당 속성의 상태를 얻을 수 있다. 따라서 현재 객체가 종속 객체에 해당하는 속성에 setter 메서드를 추가하기만 하면 해당 종속 객체를 setter 메서드를 통해 주입된 객체로 설정할 수 있습니다.

public class FXNewsProvider{
    
     
     private IFXNewsListener newsListener; 
     private IFXNewsPersister newPersistener; 

     public IFXNewsListener getNewsListener() {
    
     
    	 return newsListener; 
     } 
     public void setNewsListener(IFXNewsListener newsListener) {
    
     
     	this.newsListener = newsListener; 
     } 
     public IFXNewsPersister getNewPersistener() {
    
     
    	return newPersistener; 
     } 
     public void setNewPersistener(IFXNewsPersister newPersistener) {
    
     
    	this.newPersistener = newPersistener; 
     } 
}

이러한 방식으로 외부 세계는 setNewsListener 및 setNewPersistener 메서드를 호출하여 종속 개체를 FXNewsProvider 개체에 주입할 수 있습니다.

세터 메서드 주입은 생성이 완료된 후 객체를 사용할 수 있도록 하는 생성 메서드 주입과는 다르지만 상대적으로 느슨하며 객체 생성이 완료된 후에 주입할 수 있습니다.

인터페이스 주입

처음 두 주입 방법에 비해 인터페이스 주입이 그렇게 간단하고 명확하지 않습니다. 주입된 개체가 IoC 서비스 공급자가 종속 개체를 주입하기를 원하는 경우 인터페이스를 구현해야 합니다. 이 인터페이스는 종속 객체를 주입하는 방법을 제공합니다. IoC 서비스 공급자는 최종적으로 이러한 인터페이스를 사용하여 주입된 객체에 주입되어야 하는 종속 객체를 이해합니다. 아래 그림은 인터페이스 주입을 사용하여 FXNewsProvider에 종속 개체를 주입하는 방법을 보여줍니다.

IoC 서비스 공급자가 의존하는 IFXNewsListener를 주입하기 위해 FXNewsProvider는 먼저 IFXNewsListenerCallable 인터페이스를 구현해야 합니다. 종속 객체. 이와 같이 InjectionServiceContainer 객체, 즉 해당 IoC Service Provider는 이 인터페이스 방식을 통해 주입 객체 FXNewsProvider에 종속 객체를 주입할 수 있다.

세 가지 주입 방법 비교

  • 인터페이스 주입. 주입 방법의 사용 측면에서 인터페이스 주입은 현재 옹호되지 않는 방법이며 기본적으로 "폐기 상태"에 있습니다. 주입된 개체가 불필요한 인터페이스를 구현하도록 강제하기 때문에 방해가 됩니다. 생성자 주입 및 setter 메서드 주입에는 필요하지 않습니다.
  • 생성자 주입. 이 인젝션 방식의 장점은 객체가 생성된 후 바로 사용할 수 있는 준비 상태가 된다는 점입니다. 단점은 종속 객체가 많을 때 구성 방법의 매개변수 목록이 상대적으로 길어진다는 것입니다. 리플렉션을 통해 객체를 구성할 때 동일한 유형의 매개변수를 처리하기가 더 어렵고 유지 및 사용이 더 번거로울 것입니다. 그리고 Java에서는 생성자를 상속할 수 없으며 기본값을 설정할 수 없습니다. 필수적이지 않은 종속성 처리를 위해 여러 가지 구축 방법을 도입해야 할 수 있으며, 매개변수 개수 변경으로 인해 유지보수에 불편이 발생할 수 있습니다.
  • 세터 메소드 주입. 메서드에 이름을 지정할 수 있기 때문에 setter 메서드 주입이 생성자 메서드 주입보다 더 설명적입니다. 또한 setter 메서드를 상속할 수 있으므로 기본값을 설정할 수 있으며 IDE 지원이 우수합니다. 물론 단점은 개체가 생성 직후에 준비 상태로 들어갈 수 없다는 것입니다.

IoC의 이점

능동적으로 종속성을 획득하는 방식에서 IoC 방식으로 전환하는 것은 한 방향으로만 변경하는 것이 아니라 단순한 변환 뒤에는 실제로 더 많은 미스터리가 있습니다. IoC 모델이 우리에게 가져올 수 있는 이점을 말하자면 다양한 자료나 책에 많이 나열되어 있을 수 있습니다. 예를 들어 비즈니스 개체에 그다지 방해가 되지 않으며 IoC를 사용한 후 개체의 테스트 가능성, 재사용 가능성 및 확장성 등이 향상됩니다. 그러나 일반적으로 그것에 대해 이야기하는 것은 IoC 패턴이 가져오는 많은 이점에 대한 깊은 이해를 제공하지 않을 수 있으므로 구체적인 예부터 살펴보겠습니다.

IOC 공급자

비즈니스 개체가 IOC를 통해 해당 종속성을 선언할 수 있지만 이러한 상호 종속 개체를 함께 바인딩하려면 서비스가 여전히 필요하며 IoC 서비스 공급자가 이 작업을 수행합니다.

Ioc 서비스 공급자는 IoC 시나리오에서 비즈니스 개체를 함께 묶는 모든 구현을 참조할 수 있는 추상적인 개념입니다. 코드 조각, 관련 클래스 그룹 또는 보다 일반적인 IoC 프레임워크 또는 IoC 컨테이너 구현일 수 있습니다. Spring의 Ioc 컨테이너는 종속성 주입 서비스를 제공하는 Ioc 서비스 공급자입니다.

IoC 서비스 공급자의 책임

IoC 서비스 공급자의 책임은 상대적으로 간단합니다.비즈니스 객체의 구성 및 관리와 비즈니스 객체 간의 종속성 바인딩이라는 두 가지 주요 책임이 있습니다.

  • **비즈니스 개체 구성 관리:** IoC 시나리오에서 비즈니스 개체는 자신이 의존하는 개체를 구축하고 획득하는 방법에 대해 신경 쓸 필요가 없지만 이 작업 부분에는 항상 누군가가 이를 수행해야 합니다. 따라서 IoC 서비스 공급자는 클라이언트 개체에서 개체 구성 논리를 분리하여 논리의 이 부분이 비즈니스 개체의 구현을 오염시키지 않도록 해야 합니다.
  • **비즈니스 객체 간의 종속성 바인딩: **Ioc Service Provider에게 이 책임은 가장 어렵고 가장 중요합니다. 책임의 이 부분에 문제가 있는 경우 주입해야 하는 개체가 필요한 종속 개체를 찾지 못합니다. Ioc Service Provider는 이전에 구축되고 관리되었던 모든 비즈니스 객체와 각 비즈니스 객체 간의 식별 가능한 종속성을 결합하여 이러한 객체가 의존하는 객체를 주입하고 바인딩하여 각 비즈니스 객체가 준비될 수 있도록 합니다. 사용 상태.

IoC 서비스 공급자가 개체 간의 종속성을 관리하는 방법

주입된 객체는 IoC 서비스 공급자에게 다양한 방법으로 해당 종속성을 주입하도록 알릴 수 있습니다. 그러나 문제는 알림을 받는 IoC 서비스 공급자가 주입된 객체의 의도를 완전히 이해하고 적시에 효과적인 방식으로 원하는 종속성을 제공할 수 있는가입니다. 때로는 우리가 당연하게 여기는 것이 아닐 수도 있습니다. 주입된 개체에 대한 종속성 주입을 제공하는 IoC 서비스 공급자의 경우 주입된 개체와 자신이 관리하고 마스터하는 종속 개체 간의 해당 관계를 알아야 합니다.

IoC 서비스 공급자는 개체 간의 대응을 기록할 방법이 필요합니다. 예를 들어:

  • 주입된 개체와 종속 개체 간의 해당 관계는 기본 텍스트 파일을 통해 기록할 수 있습니다.
  • 이러한 해당 정보는 매우 설명적인 XML 파일 형식을 통해 등록할 수 있습니다.
  • 이러한 해당 메시지는 코드를 작성하여 등록할 수 있습니다.

따라서 실제 상황에서 다양한 특정 IoC 서비스 공급자 구현은 어떤 방식으로 "서비스 정보"를 기록합니까? 현재 널리 사용되는 IoC 서비스 공급자 제품은 다음과 같은 개체 관리 정보 등록 방법을 사용한다고 요약할 수 있습니다.

직접 인코딩

현재 대부분의 IoC 컨테이너는 PicoContainer, Spring, Avalon 등과 같은 직접 인코딩을 지원해야 합니다. 컨테이너가 시작되기 전에 프로그램 코딩을 통해 주입된 개체와 종속 개체를 컨테이너에 등록하고 이들 간의 종속성 주입 관계를 명확히 할 수 있습니다.

IoContainer container = ...; 
container.register(FXNewsProvider.class,new FXNewsProvider()); 
container.register(IFXNewsListener.class,new DowJonesNewsListener()); 
... 
FXNewsProvider newsProvider = (FXNewsProvider)container.get(FXNewsProvider.class); 
newProvider.getAndPersistNews();

해당 클래스에 해당하는 특정 인스턴스를 지정하면 이러한 유형의 개체 인스턴스를 원할 때 컨테이너에 등록된 해당 특정 인스턴스를 반환하도록 IoC 컨테이너에 알릴 수 있습니다.

인터페이스 주입이라면 의사 코드가 조금 더 보일 수 있습니다. 그러나 해당 개체를 등록하는 것 외에도 "주입 플래그 인터페이스"가 해당 종속 개체에 바인딩되어야 컨테이너가 최종적으로 어떤 종류의 해당 관계인지 알 수 있다는 점을 제외하면 원칙은 동일합니다.

다이렉트 코딩 형태의 인터페이스 주입 관리 기반 의존성 주입

IoContainer container = ...;
container.register(FXNewsProvider.class,new FxNewsProvider);
container.register(IFXNewsListener.class,new DowJonesNewsListener);
...
container.bind(IFXNewsListenerCallabe.class,container.get(IFXNewsListener.class));
...
FXNewsProvider newsProvider = (FXNewsProvider)contanier.get(IFXNewsProvider.class);
newProvider.getAndPersistNews();

바인딩 방법을 통해 "주입된 개체"가 의존하는 개체는 컨테이너에 등록된 IFXNewsListener 유형의 개체 인스턴스에 바인딩될 수 있습니다. 컨테이너가 FXNewsProvider 개체 인스턴스를 반환하기 전에 바인딩 정보에 따라 컨테이너의 IFXNewsListener에 등록된 개체 인스턴스를 "주입된 개체" FxNewsProvider에 주입하고 최종적으로 조립된 FXNewsProvider 개체를 반환합니다.

따라서 최종 IoC 서비스 공급자(즉, 각 IoC 프레임워크 또는 컨테이너 구현체)가 프로그램 코딩을 통해 서비스의 "난해한 의미"를 알 수 있도록 하는 것이 종속성 바인딩 관계를 관리하는 가장 기본적인 방법이어야 합니다.

구성 파일 방법

이것은 종속성 주입 관리의 보다 일반적인 방법입니다. 일반적인 텍스트 파일, 속성 파일, XML 파일 등은 모두 종속성 주입을 관리하기 위한 매개체가 될 수 있습니다. 그러나 가장 일반적인 방법은 XML 파일을 통해 개체 등록 및 개체 간의 종속성을 관리하는 것입니다.

<bean id="newsProvider" class=" ..FXNewsProvider">
	<property name= "newsListener" >
		<ref bean="djNewsListener"/>
    </property>
	<property name="newPersistener">
		<ref bean="djNewsPersister"/>
    </property>
</bean>
<bean id="djNewsListener" class=" ..impl.DowJonesNewsListener" ></bean>
<bean id="djNewsPersister" class=" ..impl.DowJonesNewsPersister"></bean>

메타데이터 방법

이 방법의 대표적인 구현은 java 5 annotations 및 Generic을 기반으로 Bob Lee가 개발한 일련의 IOC 프레임워크인 Google Guice입니다. 클래스의 메타데이터 정보를 직접 사용하여 개체 간의 종속성을 표시할 수 있으며 Guice 프레임워크는 이러한 주석에서 제공하는 정보에 따라 이러한 개체를 조합하고 사용을 위해 클라이언트 개체에 전달합니다.

종속성을 표시하기 위해 Guice 주석을 사용한 후의 FXNewsProvider 정의

public class FXNewsProvider {
    
    
 	private IFXNewsListenernewsListener;private IFXNewsPersister newPersistener ;
    @Inject
    public FXNewsProvider(IFXNewsListener listener,IFXNewsPersister persister) {
    
    
        this.newsListener= listener;
        this.newPersistener = persister ;
    }  
}

@Inject를 통해 우리는 IoC 서비스 공급자가 생성자 주입을 통해 FXNewsProvider에 의존하는 개체를 주입해야 함을 나타냅니다. 나머지 종속성 관련 정보는 Guice에서 해당 모듈에서 제공합니다.

FXNewsProvider에서 사용하는 모듈 구현

public class NewsBindingModule extends AbstractModule{
    
    
@Override
protected void configure() {
    
    
	bind (IFXNewsListener.class).to(DowJonesNewsListener.class).in(Scopes.SINGLETON);
    bind (FXNewsPersister.class).to(DowJonesNewsPersister.class).in (Scopes.SINGLETON)
}

모듈을 통해 추가 종속성 주입 관련 정보를 지정하면 최종 주입되고 Guice에서 직접 사용할 수 있는 개체를 직접 얻을 수 있습니다.

Injector injector = Guice.createInjector(new NewsBindingModule()) ;
FXNewsProvider newsProvider = injector.getInstance (FXNewsProvider.class)newsProvider.getAndPersistNews ( ) ;

물론 최종 주입 관계는 코드 처리를 통해 결정되어야 하며, 이러한 관점에서 주석 방식은 코딩 방식의 특수한 경우라고 볼 수 있습니다.

Spring의 IOC 컨테이너의 BeanFactory

앞서 Spring의 IoC 컨테이너가 IoC Service Provider라고 했지만 IoC라는 이름이 붙은 이유 중 일부에 불과하며 무시할 수 없는 것이 바로 "컨테이너"입니다. Spring의 IoC 컨테이너는 IoC를 지원하는 경량 컨테이너로 기본적인 IoC 지원 외에 경량 컨테이너로 IoC 이외의 지원도 제공한다. 예를 들어 Spring의 IoC 컨테이너 위에 Spring은 해당 AOP 프레임워크 지원 및 엔터프라이즈 수준 서비스 통합과 같은 서비스도 제공합니다. Spring의 IoC 컨테이너와 IoC Service Provider가 제공하는 서비스 사이에는 일정한 교집합이 존재하며 그 관계는 그림과 같다.

Spring의 IoC 컨테이너와 IoC 서비스 공급자 간의 관계

Spring은 두 가지 컨테이너 유형 BeanFactory와 ApplicationContext를 제공합니다.

  • BeanFactory의 기본 IOC 컨테이너 유형은 완전한 IOC 서비스 지원을 제공합니다. 지정하지 않으면 지연 초기화 전략(지연 로드)이 기본적으로 채택됩니다. 클라이언트 개체가 컨테이너의 관리 개체에 액세스해야 하는 경우에만 관리 개체가 초기화되고 종속성이 주입됩니다. 따라서 상대적으로 말해서 컨테이너 시작의 초기 속도는 상대적으로 빠르고 필요한 리소스는 제한적입니다. 리소스가 제한되고 기능적 요구 사항이 그다지 엄격하지 않은 시나리오의 경우 BeanFactory가 더 적합한 IOC 컨테이너 선택입니다.
  • ApplicationContext. ApplicationContext는 비교적 진보된 컨테이너 구현인 BeanFactory를 기반으로 구축되며, BeanFactory의 모든 지원 외에도 ApplicationContext는 이벤트 게시, 국제화 정보 지원 등과 같은 기타 고급 기능을 제공합니다. . ApplicationContext에 의해 관리되는 개체는 이 유형의 컨테이너가 시작된 후 기본적으로 모두 초기화되고 바인딩됩니다. 따라서 BeanFactory에 비해 ApplicationContext는 더 많은 시스템 리소스를 필요로 하며, 동시에 시작 시 모든 초기화가 완료되기 때문에 컨테이너 시작 시간도 BeanFactory보다 길다. 시스템 리소스가 충분하고 더 많은 기능이 필요한 경우 ApplicationContext 유형 컨테이너가 더 적합합니다.

ApplicationContext와 Beanfactory의 관계

이미지-20220606103921978

참고: ApplicationContext는 BeanFactory에서 간접적으로 상속하므로 BeanFactory 위에 구축된 IOC 컨테이너입니다.

BeanFactory는 자동차 공장과 같습니다. 다른 자동차 부품 회사나 자체 부품 생산 부서에서 자동차 부품을 가져와서 이 자동차 생산 공장으로 보내면 결국 생산 라인의 끝에서 완성차를 가져오기만 하면 됩니다. 마찬가지로 애플리케이션에 필요한 모든 비즈니스 객체를 BeanFactory에 전달한 후 남은 작업은 BeanFactory에서 직접 최종 조립되고 사용 가능한 객체를 얻는 것입니다. 최종 비즈니스 객체를 어셈블하는 방법에 대해서는 신경 쓸 필요가 없습니다. BeanFactory가 대신 처리합니다.

따라서 클라이언트 입장에서 BeanFactory를 다루는 것은 실제로 매우 간단하다. 가장 기본적인 수준에서 BeanFactory는 어셈블된 객체를 얻기 위한 메서드 인터페이스를 노출해야 합니다.

BeanFactory의 정의

public interface BeanFactory {
    
    
    String FACTORY_BEAN_PREFIX = "&";
    Object getBean(String name) throws BeansException;
    object getBean(String name,Class requiredType) throws BeansException;
    /**
	 *@since 2.5
	 */
    0bject getBean(String name,Object [] args) throws BeansException;boolean containsBean (string name) ;
    boolean issingleton(String name) throws NoSuchBeanDefinitionException;
    /**
	 *@since 2.0.3
	 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    /**
	 * @since 2.0.1
	 */
	boolean isTypeMatch(String name,Class targetType) throws NoSuchBeanDefinitionException;Class getType(String name) throws NoSuchBeanDefinitionException;
	string[] getAliases (string name) ;
}

위 코드의 메서드는 기본적으로 쿼리 관련 메서드로 객체를 획득하는 메서드(getBean), 컨테이너에 객체가 존재하는지 쿼리하는 메서드(containsBean), 빈의 상태를 획득하는 메서드, 방법의 종류 등 일반적으로 독립 실행형 애플리케이션의 경우 기본 항목 클래스만 컨테이너의 API와 직접 연결되기 때문입니다.

추천

출처blog.csdn.net/qq_45473439/article/details/125153679