天天看點

1.4.6.1. Lookup Method Injection(查找方法注入)  Spring Framework Documentation (5.3.10)

  Spring Framework Documentation (5.3.10)

Core IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP.

   Core Technologies

1. The IoC Container

1.1. Introduction to the Spring IoC Container and Beans(Spring IoC容器和bean簡介)

1.2. Container Overview (容器概覽)

1.3. Bean Overview (Bean概覽)

1.4. Dependencies(依賴)

1.4.1. Dependency Injection(依賴注入)

1.4.2. Dependencies and Configuration in Detail(依賴與配置詳細介紹)

1.4.3. Using depends-on(使用depends-on)

1.4.4. Lazy-initialized Beans(延遲初始化Bean)

1.4.5. Autowiring Collaborators(自動裝配協作者)

1.4.6. Method Injection(方法注入)

1.4.6.1. Lookup Method Injection(查找方法注入)

1.4.6.2. Arbitrary Method Replacement(任意方法替換)

1.5. Bean Scopes(Bean作用域)

關于Spring Framework Documentation (5.3.10)  核心技術的更多内容,請點選:

  Core Technologies

1.4.6.1. Lookup Method Injection(查找方法注入)

Lookup method injection is the ability of the container to override methods on container-managed beans and return the lookup result for another named bean in the container. The lookup typically involves a prototype bean, as in the scenario described in the preceding section. The Spring Framework implements this method injection by using bytecode generation from the CGLIB library to dynamically generate a subclass that overrides the method.

查找方法注入是容器重寫容器托管bean(container-managed bean)上的方法并傳回容器中另一個命名bean的查找結果的能力。查找通常涉及一個原型(prototype)bean,如前一節所述(the preceding section)。Spring架構通過使用CGLIB庫中的位元組碼生成特性來動态生成重寫該方法的子類,進而實作這種方法注入。

1.4.6.1. Lookup Method Injection(查找方法注入)  Spring Framework Documentation (5.3.10)
  • For this dynamic subclassing to work, the class that the Spring bean container subclasses cannot be 

    final

    , and the method to be overridden cannot be 

    final

    , either.
  • Unit-testing a class that has an 

    abstract

     method requires you to subclass the class yourself and to supply a stub implementation of the 

    abstract

     method.
  • Concrete methods are also necessary for component scanning, which requires concrete classes to pick up.
  • A further key limitation is that lookup methods do not work with factory methods and in particular not with 

    @Bean

     methods in configuration classes, since, in that case, the container is not in charge of creating the instance and therefore cannot create a runtime-generated subclass on the fly.
1.4.6.1. Lookup Method Injection(查找方法注入)  Spring Framework Documentation (5.3.10)
  • 對于這個動态子類來說,Spring bean容器從中生成子類的類不能(即父類)是final,要重寫的方法也不能是final。
  • 對具有

    abstract

     方法的類進行單元測試時,需要您自己對該類進行子類化,并提供

    abstract

     方法的存根實作(stub implementation)。
  • 元件掃描(component scanning)也需要具體的方法,這需要選擇具體的類(class)。
  • 另一個關鍵限制是,查找方法不适用于工廠方法,也不适用于配置類中的@Bean方法,因為在這種情況下,容器不負責建立執行個體,是以無法動态建立運作時生成的子類(runtime-generated subclass)。

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:

對于前面代碼段中的

CommandManager

 類,Spring容器動态重寫 

createCommand()

方法的實作。CommandManager類沒有任何Spring依賴項,如修改後的示例所示:

Java

package fiona.apple;

// 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() ;
}
           

Kotlin

package fiona.apple

// no more Spring imports!

abstract class CommandManager {

    fun process(commandState: Any): Any {
        // grab a new instance of the appropriate Command interface
        val command = createCommand() 
        // set the state on the (hopefully brand new) Command instance
        command.state = commandState
        return command.execute() 
    }

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

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:

在包含要注入的方法的用戶端類(本例中為CommandManager)中,要注入的方法需要以下形式的簽名:

<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:

如果方法是

abstract

,則動态生成的子類(dynamically-generated subclass)将實作該方法。否則,動态生成的子類将重寫在原始類中定義的具體方法。考慮下面的例子:

<!-- 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:

當需要myCommand bean的新執行個體時,辨別為commandManager的bean就會調用自己的createCommand

()

方法。如果需要的話,您必須小心地将

myCommand

 bean部署為prototype。如果是單例,則每次都傳回myCommand bean的相同執行個體。

或者,在基于注解的元件模型中,可以通過@lookup注解聲明查找方法,如下例所示:

Java

public abstract class CommandManager {

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

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

Kotlin

abstract class CommandManager {

    fun process(commandState: Any): Any {
        val command = createCommand() 
        command.state = commandState
        return command.execute() 
    }

    @Lookup("myCommand")
    protected abstract fun createCommand() : Command
}
           

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

或者,更習慣地說,您可以依靠目标bean(target bean)解析查找方法的聲明傳回類型:

Java

public abstract class CommandManager {

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

    @Lookup
    protected abstract MyCommand createCommand() ;
}
           

Kotlin

abstract class CommandManager {

    fun process(commandState: Any): Any {
        val command = createCommand() 
        command.state = commandState
        return command.execute() 
    }

    @Lookup
    protected abstract fun createCommand() : Command
}
           

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.

請注意,您通常應該使用具體的存根實作(concrete stub implementation)聲明此類帶注解的查找方法(annotated lookup method),以便它們與Spring的元件掃描規則相容,預設情況下抽象類會被忽略。此限制不适用于顯式注冊或顯式導入的bean類。

1.4.6.1. Lookup Method Injection(查找方法注入)  Spring Framework Documentation (5.3.10)
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.
1.4.6.1. Lookup Method Injection(查找方法注入)  Spring Framework Documentation (5.3.10)
另一種通路不同作用域的目标bean(differently scoped target bean)的方法是

ObjectFactory

Provider

注入點。參考Scoped Beans as Dependencies。

您還可能發現

ServiceLocatorFactoryBean

 (在org.springframework.beans.factory.config包中)很有用。