spring学习(五)——spring官方文档阅读(5.0.7)——方法注入

方法注入

使用场景:假设单例bean A中有一个方法每次调用都需要一个新的非单例bean B,由于IOC只会在创建bean A的时候进行依赖注入,所以将bean B作为A的属性不能解决问题,此时可以使用方法注入,一种方法是让A实现接口ApplicationContextAware接口,这个接口定义如下:

public interface ApplicationContextAware {

    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

这个接口可以获得IOC容器,接着调用getBean方法即可获得一个B,如下:

// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;

// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

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

这种方式不是很推荐,因为我们在自己的代码中嵌入了spring框架的代码,这意味着当我们换个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();
}

一般用来方法注入的方法组织形式如下:

<public|protected> [abstract] <return-type> theMethodName(no-arguments);
<!-- 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>

将CommandManager为抽象类,为什么我们可以创建CommandManager的bean?因为spring 会通过CGLIB(动态代理)生成CommandManager的子类,会自动实现抽象方法createCommand(),返回myCommand对象,当然我们也可以将方法注入组织成非抽象类:

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

此时spring动态生成的子类会覆盖这个方法,不论如何,一定要让方法注入可以被继承

使用方法注入后,每次我们执行process方法时,spring就会返回一个myCommand对象,如果myCommand配置成单例,则每次都会返回同一个myCommand对象

我们也可以使用注解方式实现方法注入:

public abstract class CommandManager {

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

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

上述方法是通过名字寻找匹配的bean,我们也可以忽略名字,此时会根据类型查找匹配的bean:

public abstract class CommandManager {

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

    @Lookup
    protected abstract MyCommand createCommand();
}

除了可以替换抽象方法外,方法注入几乎可替换任意方法,举个例子:
 

public class MyValueCalculator {

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

    // some other methods...
}

为了替换computerValue方法,我们需要两个步骤:

1、继承org.springframework.beans.factory.support.MethodReplacer接口,并实现其中的reimplement方法:

/**
 * 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 ...;
    }
}

2、配置xml:
 

<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"/>

replace-method指出被替换的方法,replacer指出替换的方法,当被替换的方法被多次重载时,才需要使用<arg-type/>来消除歧义

猜你喜欢

转载自blog.csdn.net/dhaiuda/article/details/81866760