方法注入(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

目录
相关文章
|
存储 SQL 分布式计算
Spark中的数据加载与保存
Spark中的数据加载与保存
|
SQL 存储 弹性计算
阿里云EMR 2.0:重新定义新一代开源大数据平台
本次分享主要介绍了阿里云E-MapReduce的开发历程,EMR 2.0的新特性、产品架构,以及EMR 2.0在平台体验、数据开发、资源形态及分析场景等方面的全面突破与创新,重新定义新一代开源大数据平台。
3296 0
阿里云EMR 2.0:重新定义新一代开源大数据平台
|
9月前
|
数据采集 存储 数据库连接
Requests与BeautifulSoup:高效解析网页并下载资源
Requests与BeautifulSoup:高效解析网页并下载资源
|
12月前
|
弹性计算 运维 监控
EMR管控平台全面升级:智能化助力客户实现在离线混部和降本增效
本次介绍EMR开源大数据平台2.0的最新特性,基于微服务架构,提供更稳定高效的服务。平台升级主要体现在智能化和Serverless两个方面。智能化功能利用大语言模型提升运维效率,推出一键诊断和根因分析,缩短问题定位时间。全托管弹性伸缩根据业务动态自动调整资源,提高资源利用率。即将推出的EMR on ACS产品形态支持离在线业务混部,进一步优化资源使用,帮助用户实现降本增效。
|
负载均衡
Eureka服务注册流程
Eureka 是一款用于服务注册与发现的工具。服务提供者启动时向 Eureka 服务器注册自身信息,定期发送心跳保持活跃状态。服务消费者通过 Eureka 获取服务列表并调用。服务下线时主动通知 Eureka 移除实例信息。
230 0
|
人工智能 自然语言处理 搜索推荐
如何构建一套qwen-max智能体拥有媲美通义千问在线接口的能力
智能系统通过任务识别、决策引擎、工具选择和结果整合,自动选择合适的工具和方法,高效处理查询、生成、翻译、图像处理等任务,提供精准的解决方案。系统支持自然语言理解、任务分类、语义解析与意图识别,确保任务的准确执行和反馈。
356 3
【天梯赛】L1-095 分寝室
输出的方案对应女生都是 24/4=6 人间、男生都是 60/6=10 人间,人数差为 4。满足前三项要求的分配方案还有两种,即女生 6 间(都是 4 人间)、男生 4 间(都是 15 人间);同时,每间女寝人数必须都一样,每间男寝人数必须都一样,也就是女生总人数对女寝数取模为0,男生总人数对男寝数取模为0。输入在一行中给出 3 个正整数 n0​、n1​、n,分别对应女生人数、男生人数、寝室数。按题意模拟,因为知道总寝室数为n,所以可以从1~n-1暴力枚举女寝 i 的数量,那么男寝的数量则为 c-i。
351 6
|
开发框架 小程序 前端开发
Remax
Remax 是一款基于 Vue.js 的微信小程序开发框架,它提供了一套简洁、完整的 API,让开发者能够快速、高效地开发出功能丰富、性能优良的微信小程序。
527 1
|
Java Maven Spring
SpringBoot运行出现 Lookup method resolution failed; nested exception is java.lang.IllegalStateException
SpringBoot运行出现 Lookup method resolution failed; nested exception is java.lang.IllegalStateException
3552 0
|
开发工具 异构计算 内存技术
FPGA启动加载过程详解
FPGA启动加载过程详解
1641 0