方法注入(Method injection)

简介: 方法注入,重写方法,替换方法!@Lookup,lookup-method,replaced-method!Lookup method inject!Arbitrary method replacement!

方法注入(Method injection)

Spring提供两种机制去注入方法,分别是 Lookup method inject,Arbitrary method replacement。Lookup method inject只提供返回值注入,Arbitrary method replacement可以替换任意方法来达到注入。

Lookup method inject

​ 有时我们需要在一个bean A中调用另一个bean B的方法,通常我们会添加一个字段,然后使用依赖注入把bean B的实例注入到这个字段上。这种情况下在bean A 和 bean B都是singleton时没问题,但是在 bean A是singleton和bean B是非singleton时就可能出现问题。因为bean B为非singleton , 那么bean B是希望他的使用者在一些情况下创建一个新实例,而bean A使用字段把bean B的一个实例缓存了下来,每次都使用的是同一个实例。

​ 我们假设bean B是一个prototype

​ 一种解决办法是不使用字段依赖注入,每次使用bean B的时候都去bean容器中重新获取


/**
 * 这是一个命令执行类,提供一个process方法,执行用户的命令
 */
public class CommandManager{

    //使用依赖注入,把applicationContext注入进来
    @Autowire
    private ApplicationContext applicationContext;

    /**
     * 根据用户指定的参数,每次使用一个新的Command实例去执行命令
     * @param commandState 执行的参数
     * @return 执行后的返回值
     */
    public Object process(Map commandState) {
        // 每次使用都调用createCommand去获取一个新实例
        Command command = createCommand();
        command.setState(commandState);
        return command.execute();
    }

    //从applicationContext获取一个新的Command实例
    protected Command createCommand() {
        return this.applicationContext.getBean("command", Command.class);
    }
}

​ 上面的代码是每次都从applicationContext重新获取一个新实例来实现的。Spring提供了一个Lookup method inject机制,它可以改变方法的返回值,来达到方法注入的效果。对应的有annotation和xml两种使用方式。

annotation的使用方式@Lookup,把@Lookup加到你要改变方法返回值的方法上

public abstract class CommandManager{
    public Object process(Map commandState) {
        // 每次使用都调用createCommand去获取一个新实例
        Command command = createCommand();
        command.setState(commandState);
        return command.execute();
    }
    /**
     * Loopup的注释中的写明了需要返回的bean名字,如果没有写bean name,那么会根据createCommand的函数返回值类型去查找对应的bean
     * @return
     */
    @Lookup("command")
    protected abstract Command createCommand();
}

​ Spring的Lookup method inject实现原理的是使用CGLIB动态生成一个类去继承CommandManager,重写createCommand方法。然后根据@Lookup中指定的bean Name或者createCommand方法的返回类型判断需要返回的bean。createCommand可以是abstract和可以不是。因为使用的是继承,所以CommandManager类和createCommand方法都不能是final的。

createCommand方法的签名需要满足如下要求

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

对应实现的XML配置

<bean id="command" class="AsyncCommand" scope="prototype">
</bean>

<bean id="commandManager" class="CommandManager">
    <lookup-method name="createCommand" bean="command"/>
</bean>

​ 访问不同Scope的bean,可以使用ObjectFactory/ Provider 注入,详情查看Scoped beans as dependencies.

Arbitrary method replacement

​ Lookup method inject只是改变了方法的返回值,但是method replacement可以替换bean 容器里任意方法的实现,达到方法的完全注入,一般情况下不要这个使用特性!

此特性,只能基于XML配置实现。假如我们要替换如下类的computeValue方法

public class MyValueCalculator {
    public String computeValue(String input) {
       //...真实代码
    }
}

第一步,我们要现实org.springframework.beans.factory.support.MethodReplacer接口

public class ReplacementComputeValue implements MethodReplacer {
    /**
     * 当我们替换的方法被调用时,容器就会代理到这里,在这里执行我们要替换的执行逻辑
     * @param o   替换方法执行时对应的实例
     * @param m   替换方法
     * @param args 替换方法执行时传入的参数
     * @return
     * @throws Throwable
     */
    public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
        String input = (String) args[0];
        ...
        return ...;
    }
}

第二步,在XML中,使用replaced-method元素进行配置.

<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
    <!-- 需要替换的方法 -->
    <replaced-method name="computeValue" replacer="replacementComputeValue">
        <arg-type>String</arg-type>
    </replaced-method>
</bean>

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

在上面的xml中,在元素replaced-method中使用了arg-type。它的作用是在有多个方法重载时,根据arg-type中指定的参数class名字来确定具体替换哪一个方法。arg-type中的值可以是类全路径的一个子串,如下面所有的值都可以匹配java.lang.String

java.lang.String
String
Str

详情查看文档地址:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-method-injection

目录
相关文章
|
6月前
|
XML 安全 数据库
24、显错注入(updatexml和extractvalue)
24、显错注入(updatexml和extractvalue)
52 0
|
6月前
|
Java 开发者 Spring
Spring中获取Bean对象的三种注入方式和两种注入方法
Spring中获取Bean对象的三种注入方式和两种注入方法
|
24天前
|
SQL 安全 关系型数据库
beescms注入
通过 SQL 注入、弱口令爆破和文件上传三种方式对系统进行安全测试的过程。首先,通过手动注入和报错注入获取数据库信息,接着利用弱口令爆破工具尝试登录,最后通过修改 MIME 类型绕过文件上传限制,成功获取 shell。
beescms注入
|
4天前
|
SQL 关系型数据库 MySQL
注入
【11月更文挑战第17天】
13 4
|
6月前
|
Java Spring 容器
ServiceLocatorFactoryBean获取Bean方法
在上述示例中,`MyService`是要获取的具体Bean的类型。通过配置 `ServiceLocatorFactoryBean`,定义 `ServiceLocator`接口和实现类,然后通过获取 `MyServiceLocator`实例并调用方法,可以从Spring容器中获取特定类型的Bean。 买CN2云服务器,免备案服务器,高防服务器,就选蓝易云。百度搜索:蓝易云
83 0
|
6月前
|
XML 缓存 Java
Spring5源码(7)-lookup-method和replace-method注入
Spring5源码(7)-lookup-method和replace-method注入
111 0
|
设计模式 Java 测试技术
【注解使用】使用@Autowired注解警告Field injection is not recommended
【注解使用】使用@Autowired注解警告Field injection is not recommended
311 0
|
XML Java 数据格式
SpringXML实现注入
SpringXML实现注入
SpringXML实现注入
|
XML Java 数据格式
Spring的applicationContext.xml的配置和lookup-method,replaced-method的使用(三)
Spring的applicationContext.xml的配置和lookup-method,replaced-method的使用(三)
211 0
Spring的applicationContext.xml的配置和lookup-method,replaced-method的使用(三)
|
Java API Spring
@Resource,@Autowired,@Inject3种注入方式详解
JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。
182 0
@Resource,@Autowired,@Inject3种注入方式详解