본문 바로가기

Web/spring

[Spring Framework core] 1.4. Dependencies (3)

728x90

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-dependson

 

Core Technologies

In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do

docs.spring.io

 

 

틀린 해석이 있다면 알려주세요 🍉

 


1.4.3. Using depends-on

빈이 다른 빈의 종속성일 경우에는 하나의 빈이 다른 빈의 속성으로 설정된다. 

일반적으로 <ref/> element 를 사용하여 수행한다. 빈 간의 종속성이 덜 직접적인 경우에는 명시적으로 강제할 수 있다.

depends-on 속성을 강제할 수 있다.

<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />

 

여러 bean에 대한 종속성을 표현하려면 bean 이름 목록을 속성 값으로 제공해준다. depends-on(쉼표, 공백 및 세미콜론 가능)

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
    <property name="manager" ref="manager" />
</bean>

<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />



depends-on 속성은 초기환 시간의 의존성과 해당 파괴 시간 의존성(SingleTon일 때)을 지정할 수 있다

주어진 bean과의 종속관계를 정의하는 종속 bean은 주어진 bean자체가 파괴되기 전에 먼저 파괴된다

쉽게 말해 종료 순서도 제어할 수 있다. 

 

 

 

 

 

 

1.4.4. Lazy-initialized Beans

기본적으로 ApplicationContext는 구현 시에 초기화 process의 일부를 만들어 구성한다

일반적으로 사전 인스턴스화는 구성 또는 환경을 즉시 발견되기 때문이다.

하지만 이런 동작을 지연시키고 싶을 때가 있을 것이다. 그럴 경우는 Lazy-initialized 하여 사전 인스턴스화를 방지할 수 있다

이는 IoC컨테이너 시작이 아니라, 처음 요청 시에 bean instance를 생성하도록 하게한다

 

In XML, this behavior is controlled by the lazy-init attribute on the <bean/> element, as the following example shows:

<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>
 

When the preceding configuration is consumed by an ApplicationContext, the lazy bean is not eagerly pre-instantiated when the ApplicationContext starts, whereas the not.lazy bean is eagerly pre-instantiated.

However, when a lazy-initialized bean is a dependency of a singleton bean that is not lazy-initialized, the ApplicationContext creates the lazy-initialized bean at startup, because it must satisfy the singleton’s dependencies. The lazy-initialized bean is injected into a singleton bean elsewhere that is not lazy-initialized.

You can also control lazy-initialization at the container level by using the default-lazy-init attribute on the <beans/> element, as the following example shows:

<beans default-lazy-init="true">
    <!-- no beans will be pre-instantiated... -->
</beans>
 
 
 
 
 

1.4.5. Autowiring Collaborators

Spring container는 Collaborator bean간의 관계를 자동으로 연결할 수 있다

이렇게 하면 두가지 이점이 있다

1. Autowiring 을 하면 속성, 생성자 arguments 지정 필요성을 줄일 수 있다

2. Autowiring 을 하면 개체가 발전함에 따라 구성을 업데이트할 수 있다. 클래스에 종속성을 추가 시 구성을 수정하지않고 종속성을 자동으로 충족할 수 있다. 

 

 

When using XML-based configuration metadata (see Dependency Injection), you can specify the autowire mode for a bean definition with the autowire attribute of the <bean/> element. The autowiring functionality has four modes. You specify autowiring per bean and can thus choose which ones to autowire. The following table describes the four autowiring modes:

Table 2. Autowiring modesModeExplanation
no (Default) No autowiring. Bean references must be defined by ref elements. Changing the default setting is not recommended for larger deployments, because specifying collaborators explicitly gives greater control and clarity. To some extent, it documents the structure of a system.
byName Autowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master and uses it to set the property.
byType Lets a property be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens (the property is not set).
constructor Analogous to byType but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised.

With byType or constructor autowiring mode, you can wire arrays and typed collections. In such cases, all autowire candidates within the container that match the expected type are provided to satisfy the dependency. You can autowire strongly-typed Map instances if the expected key type is String. An autowired Map instance’s values consist of all bean instances that match the expected type, and the Map instance’s keys contain the corresponding bean names.

 
 
Limitations and Disadvantages of Autowiring
전체 프로젝트에서 일관되게 사용할 때 Autowiring 은 잘 작동하지만, 그렇지않은 경우에는 단점이 생긴다
 
- property and constructor-arg settings 의 명시적 종속성은 항상 autowiring을 재정의한다. primitive, Strings, Classes(및 이러한 단순 배열)와 같은 단순 속성을 자동연결 할 수는 없다. (의도적인 설계)
- autowiring은 명시적인 연결보다 덜 정확하다. Spring은 예기치않은 결과가 발생할 수 있는 모호한 경우의 추측을 피하려고 한다. Spring 관리 객체 간의 관계는 더이상 명시적으로 문서화 되지 않는다
- Spring Container에서 문서를 생성할 수 있는 도구에 연결 정보가 제공되지 않을 수 있다
- container 내의 여러 정의는 autowired 될 setter method 또는 constructor-args 에 의해 지정된 유형과 일치할 수 있다. array, collection, map 인스턴스의 경우 반드시 문제가 되는 것은 아니지만, 단일 값을 예상하는 종속성의 경우 이 모호성이 임의로 해결되지않는다. 고유한 bean 정의를 사용할 수 없어 예외가 발생한다
이러한 단점을 해결하기 위해선 이러한 옵션이 있다.
  • Abandon autowiring in favor of explicit wiring. //autowiring 포기
  • Avoid autowiring for a bean definition by setting its autowire-candidate attributes to false, as described in the next section. // autowire-candidate attribute를 false로 설정
  • Designate a single bean definition as the primary candidate by setting the primary attribute of its <bean/> element to true. // primary attribute 의 속성을 true로 설정하여 기본 후보로 지정
  • Implement the more fine-grained control available with annotation-based configuration, as described in Annotation-based Container Configuration. // 세분화 된 제어 구현
 

Core Technologies

In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do

docs.spring.io

 

Excluding a Bean from Autowiring

빈 단위로 autowiring에서 빈을 제외할 수 있다.

In Spring’s XML format, set the autowire-candidate attribute of the <bean/> element to false. The container makes that specific bean definition unavailable to the autowiring infrastructure (including annotation style configurations such as @Autowired).

The autowire-candidate attribute is designed to only affect type-based autowiring. It does not affect explicit references by name, which get resolved even if the specified bean is not marked as an autowire candidate. As a consequence, autowiring by name nevertheless injects a bean if the name matches.

You can also limit autowire candidates based on pattern-matching against bean names. The top-level <beans/> element accepts one or more patterns within its default-autowire-candidates attribute. For example, to limit autowire candidate status to any bean whose name ends with Repository, provide a value of *Repository. To provide multiple patterns, define them in a comma-separated list. An explicit value of true or false for a bean definition’s autowire-candidate attribute always takes precedence. For such beans, the pattern matching rules do not apply.

These techniques are useful for beans that you never want to be injected into other beans by autowiring. It does not mean that an excluded bean cannot itself be configured by using autowiring. Rather, the bean itself is not a candidate for autowiring other beans.

 
 
 

1.4.6. Method Injection

대부분의 Application 시나리오에서 container의 대부분은 싱글톤이다. 싱글톤 bean이 다른 싱글톤 bean과 collaboration 해야하거나 싱글톤이 아닌 bean이 다른 싱글톤과 collaboration 을 해야하는 경우에 한 bean을 다른 bean 속성으로 정의해서 종속성을 처리한하는데, 그 이유는 bean lifecycle이 다를 때 문제가 생기기 때문이다.

만약 싱글톤인 A bean과 싱글톤이 아닌 프로토타입의 B bean을 사용한다고 하면, 아마도 A에 대한 각 메소드 호출에서 컨테이너는 싱글톤 A bean을 생성하는 기회가 한번 밖에 없기에 속성 설정도 한번만 가능한 것이다. 그러면 필요할때 Bean B의 새 인스턴스를 A에게 줄 수 없게된다.

 

이런 상황에서는 inversion of control 를 포기하는 것이 방법이다.

ApplicationContextAware 인터페이스를 구현 후 Bean A가 필요할 때마다 (일반적으로 새롭게) BeanB 인스턴스를요청할 수 있도록 getBean("B")하면 된다.

 

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-aware

 

Core Technologies

In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do

docs.spring.io

// Spring-API imports

public class CommandManager implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    public Object process(Map commandState) {
        // grab a new instance of the appropriate Command
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();
    }

    protected Command createCommand() {
        // notice the Spring API dependency!
        return this.applicationContext.getBean("command", Command.class);
    }

    public void setApplicationContext(
            ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

The preceding is not desirable, because the business code is aware of and coupled to the Spring Framework. Method Injection, a somewhat advanced feature of the Spring IoC container, lets you handle this use case cleanly.

https://spring.io/blog/2004/08/06/method-injection

 

Spring | Home

Cloud Your code, any cloud—we’ve got you covered. Connect and scale your services, whatever your platform.

spring.io

 

 

 

Lookup Method Injection

Lookup Method injection은 container 관리 빈의 메서드를 정의하고 container의 다른 명명된 빈에 대한 검색 결과를 반환하는 기능이다.

Look up에는 일반적으로 프로토타입의 빈이 포함된다. Spring Framework는 메서드를 재정의 하는 하위 클래스를 동적으로 생성하기 위해 CGLIB 라이브러리 바이트 코드 생성을 사용하여 이 메소드 주입을 구현한다.

 

이 dynamic subclassing 작동을 하려면 SpringBean container 하위 클래스가 final 이 될 수 없으며, 재정의 되는 메서드도 마찬가지이다

abstract 메소드가 있는 클래스를 단위 테스트하려면 class를 직접 하위 클래스로 만들고 abstract method stub구현을 제공해야한다

구체적인 클래스를 선택해야하는 component scanning에도 구체적인 method가 필요하다

 

추가로 주요제한 사항은 Look up method가 factory method 특히 구성 클래스의 @Bean 메소드와 함께 작동하지않는다는 것이다. 이 경우에는 container가 인스턴스 생성을 하지않으므로 runtime 생성에서 이를 사용할 수 없기 때문이다.

 

 

In the case of the CommandManager class in the previous code snippet, the Spring container dynamically overrides the implementation of the createCommand() method. The CommandManager class does not have any Spring dependencies, as the reworked example shows:

CommandMannger 컨테이너는 method 구현을 dynamic하게 재정의한다 -> createCommand()

// no more Spring imports!

public abstract class CommandManager {

    public Object process(Object commandState) {
        // grab a new instance of the appropriate Command interface
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();
    }

    // okay... but where is the implementation of this method?
    protected abstract Command createCommand();
}
 

In the client class that contains the method to be injected (the CommandManager in this case), the method to be injected requires a signature of the following form:

<public|protected> [abstract] <return-type> theMethodName(no-arguments);
 

If the method is abstract, the dynamically-generated subclass implements the method. Otherwise, the dynamically-generated subclass overrides the concrete method defined in the original class. Consider the following example:

<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
    <!-- inject dependencies here as required -->
</bean>

<!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
    <lookup-method name="createCommand" bean="myCommand"/>
</bean>
 

The bean identified as commandManager calls its own createCommand() method whenever it needs a new instance of the myCommand bean. You must be careful to deploy the myCommand bean as a prototype if that is actually what is needed. If it is a singleton, the same instance of the myCommand bean is returned each time.

Alternatively, within the annotation-based component model, you can declare a lookup method through the @Lookup annotation, as the following example shows:

@Lookup annotation을 사용하여 선언할 수 있다
public abstract class CommandManager {

    public Object process(Object commandState) {
        Command command = createCommand();
        command.setState(commandState);
        return command.execute();
    }

    @Lookup("myCommand")
    protected abstract Command createCommand();
}
 

Or, more idiomatically, you can rely on the target bean getting resolved against the declared return type of the lookup method:

Java
Kotlin
public abstract class CommandManager {

    public Object process(Object commandState) {
        Command command = createCommand();
        command.setState(commandState);
        return command.execute();
    }

    @Lookup
    protected abstract Command createCommand();
}
 

Note that you should typically declare such annotated lookup methods with a concrete stub implementation, in order for them to be compatible with Spring’s component scanning rules where abstract classes get ignored by default. This limitation does not apply to explicitly registered or explicitly imported bean classes.

 
Another way of accessing differently scoped target beans is an ObjectFactory/ Provider injection point. See Scoped Beans as Dependencies.
You may also find the ServiceLocatorFactoryBean (in the org.springframework.beans.factory.config package) to be useful.
 

Core Technologies

In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do

docs.spring.io

 

 

Arbitrary Method Replacement

Look up method 주입 보다 덜 유용한 주입 형식은 관리하는 bean의 임의 메서드를 다른 메서드로 구현하여 대체하는 기능이 있다

실제로 이 기능이 필요할 때 까지 이 섹션의 나머지부분을 안전하게 건너 띌 수 가 있다.

With XML-based configuration metadata, you can use the replaced-method element to replace an existing method implementation with another, for a deployed bean. Consider the following class, which has a method called computeValue that we want to override:

public class MyValueCalculator {

    public String computeValue(String input) {
        // some real code...
    }

    // some other methods...
}
 

 

 

인터페이스를 구현하는 MethodReplacer로 새 메서드 정의를 제공한다

A class that implements the org.springframework.beans.factory.support.MethodReplacer interface provides the new method definition, as the following example shows:

/**
 * meant to be used to override the existing computeValue(String)
 * implementation in MyValueCalculator
 */
public class ReplacementComputeValue implements MethodReplacer {

    public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
        // get the input value, work with it, and return a computed result
        String input = (String) args[0];
        ...
        return ...;
    }
}
 

The bean definition to deploy the original class and specify the method override would resemble the following example:

<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
    <!-- arbitrary method replacement -->
    <replaced-method name="computeValue" replacer="replacementComputeValue">
        <arg-type>String</arg-type>
    </replaced-method>
</bean>

<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>
 

You can use one or more <arg-type/> elements within the <replaced-method/> element to indicate the method signature of the method being overridden. The signature for the arguments is necessary only if the method is overloaded and multiple variants exist within the class. For convenience, the type string for an argument may be a substring of the fully qualified type name. For example, the following all match java.lang.String:

java.lang.String
String
Str
 

Because the number of arguments is often enough to distinguish between each possible choice, this shortcut can save a lot of typing, by letting you type only the shortest string that matches an argument type.

args의 수는 가능한 각 선택 항목을 구별하기에 충분하기 때문에 입력 시간을 절약할 수 있다

 

 

 

728x90