7.4.6 Lookup method injection

Lookup method injection is the ability of the container to override methods on container managed beans, to 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 generate dynamically a subclass that overrides the method.

查询方法注入是容器的能力,它可以重写被容器管理的beans的方法,然后为在容器中另一个被命名的bean返回查询结果.像之前这一章中被描述的场景,这个查询通常包含一个原型bean.Spring框架实现这个方法注入通过使用CGLIB库生成的字节码去生成一个动态的子类去重写这个方法.

  • For this dynamic subclassing to work, the class that the Spring bean container will subclass cannot be final, and the method to be overridden cannot be final either.
  • 为了让这个动态的子类能够运作,在Spring bean容器中有子类的类不能为 final,被重写的方法也不能为 final .
  • Unit-testing a class that has an abstract method requires you to subclass the class yourself and to supply a stub implementation of the abstractmethod.
  • 单元测试一个带有抽象方法的类需要你有这个类的子类并且有这个抽象方法的存根实现.
  • Concrete methods are also necessary for component scanning which requires concrete classes to pick up.
  • 具体的方法也是组件扫描必须的,它需要去挑选具体的类.
  • A further key limitation is that lookup methods won’t work with factory methods and in particular not with @Bean methods in configuration classes, since the container is not in charge of creating the instance in that case and therefore cannot create a runtime-generated subclass on the fly.
  • 一个更关键的限制是查询方法不会通过工厂方法运作,特别是在配置类中没有@Bean注解的方法,自从容器不负责创建实例的情况下,因此不能够创建一个运行时生成的子类在忙碌的时候.

Looking at the CommandManager class in the previous code snippet, you see that the Spring container will dynamically override the implementation of the createCommand() method. Your CommandManager class will not have any Spring dependencies, as can be seen in the reworked example:

在之前的代码片段中看一下CommandManager这个类,你可以看到Spring容器将会动态的重写createCommand()这个方法实现.你的CommandManager类将不会有任何的Spring依赖,也可以看一下这个重做的例子:

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

In the client class containing 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); [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. For 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 method createCommand() 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 as a singleton, the same instance of the myCommand bean is returned each time.

这个被叫做commandManager的bean调用它本身的方法createCommand()每当它需要一个myCommand的新实例时.你必须仔细的将myCommand这个bean部署为一个原型,如果这是实际需要的.如果作为一个单例,每时每刻都会返回myCommand的相同实例.

Alternatively, within the annotation-based component model, you may declare a lookup method through the @Lookup annotation:

反之,通过基于注解的组件模型,你可以声明一个查询方法通过@Lookup注解:

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 may rely on the target bean getting resolved against the declared return type of the lookup method:

或者,更常用的,你可以依靠目标bean获取到被解析的相对这个查询方法的被声明的返回类型:

public abstract class CommandManager {

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

    @Lookup
    protected abstract MyCommand createCommand();
}

Note that you will 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 in case of explicitly registered or explicitly imported bean classes.

注意你通常会声明这种查询方法的注解通过一个具体的存根实现,为了它们能够兼容在Spring的组件扫描规则,抽象类默认会被忽视.这种限制不会应用在明确注册或明确导入bean类的情况下.

Another way of accessing differently scoped target beans is an ObjectFactoryProvider injection point. Check out the section called “Scoped beans as dependencies”.

另一种方式是访问不同域对象beans是一个 ObjectFactoryProvider 注入点.请看the section called “Scoped beans as dependencies”.

The interested reader may also find the ServiceLocatorFactoryBean (in the org.springframework.beans.factory.config package) to be of use.

感兴趣的读者可能会找ServiceLocatorFactoryBean (in the org.springframework.beans.factory.config package)去使用.

猜你喜欢

转载自blog.csdn.net/weixin_41648566/article/details/80984779