当前位置: 首页 > news >正文

Spring基础——方法注入(Method Injection)

目录

  • 查找方法注入(Lookup Method)
    • 查找方法注入
      • 基于XML的方法注入
      • 基于注解的方法注入
  • Arbitrary Method Replacement(任意方法替换)

文章所用项目源码参考:java_spring_learn_repo

查找方法注入(Lookup Method)

  • 通常我们项目开发中大多都使用单例模式的Bean,因此Bean之间的依赖大多都是单例与单例之间的,而如果我们想将prototype模式的Bean被注入到单例模式的Bean中,因为单例Bean只会在创建时注入Bean的引用,所以prototype模式的Bean会一直是最开始创建的实例(换句话说就是prototype间接失效了,已经是单例模式了)。如果想要每次调用prototype模式Bean都获取一个新的实例,可以通过方法注入来实现。
  • 在Spring官方给的文档中提供了一种能在每次调用都获取新实例对象的方案,可以通过实现ApplicationContextAware接口,给Bean注入容器,然后再让Bean需要调用新实例时让容器创建一个新的实例。

ApplicationContextAware是Spring框架中的一个接口,用于让Bean实现类获取对Spring应用上下文(ApplicationContext)的引用。通过实现ApplicationContextAware接口,Bean可以在被实例化后,由Spring容器注入应用上下文的引用,从而获取容器中的其他Bean或执行一些与容器相关的操作。

  • 首先创建一个prototype的Bean
public class Command {private String state;public void setState(String state) {this.state = state;}public String execute() {return this + "对象被执行";}
}
  • XML配置Scope为prototype
<bean id="command" class="com.nobugnolife.method_injection.Command" scope="prototype"/>
  • 这里通过实现ApplicationContextAware来获取ApplicationContext,然后在对象每次调用process方法时都会让容器获取一个新的Command实例
public class MyApplicationContextAwareBean implements ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}// 通过applicationContext创建新的Commmad实例化Beanprotected Command createCommand() {return this.applicationContext.getBean("command", Command.class);}// 每次调用process时都从容器中获取新的bean实例public String process(String state) {Command command = createCommand();command.setState(state);return command.execute();}
}
  • 测试process调用是否为新实例
@Test
public void testMethodInjection(){ApplicationContext ctx = new ClassPathXmlApplicationContext("methodInjection.xml");MyApplicationContextAwareBean mcb = ctx.getBean(MyApplicationContextAwareBean.class);System.out.println(mcb.process("发送信息"));System.out.println(mcb.process("激活"));System.out.println(mcb.process("添加"));
}

test_applicationcontextaware

  • 这种方法会将Spring的代码框架耦合进项目工程中,因此官方并不推荐通过这种方法解决非单例模式Bean的调用问题,Spring也给出了通过方法注入的解决方案(有其他很多解决方案,本篇文章重点是讲方法注入)。

查找方法注入

  • 查找方法是通过在单例Bean中声明一个抽象方法,该抽象方法会在Spring容器运行时动态生成(通过CGLIB库直接生成字节码)一个子类来实现这个抽象方法,以提供prototypeBean实例。
  • 因为Spring在运行的时候是自动创建子类实现,因此要被子类实现的抽象类不能有final
  • 如果是通过工厂模式实例化Bean的话,查找方法注入是不起作用的,特别是通过@Bean注解的方式,因为此时容器不负责创建实例,所以不能动态创建运行时子类。

基于XML的方法注入

  • 首先需要定义一个查找方法的抽象类,并提供实例化Bean的抽象方法
public abstract class CommandManager {public String process(String commandState) {// 通过调用createCommand来获取新的实例BeanCommand command = createCommand();command.setState(commandState);return command.execute();}protected abstract Command createCommand();
}
  • 在bean配置中设置lookup-method标签
<!-- 查找方法注入 -->
<bean id="commandManager" class="com.nobugnolife.method_injection.CommandManager"><lookup-method name="createCommand" bean="command"/>
</bean>

基于注解的方法注入

  • 注解通过Lookup注解对抽象方法进行标记即可
@Component
public abstract class CommandManager {public String process(String commandState) {// 通过调用createCommand来获取新的实例BeanCommand command = createCommand();command.setState(commandState);return command.execute();}@Lookupprotected abstract Command createCommand();
}

Arbitrary Method Replacement(任意方法替换)

  • 任意方法是指Spring框架中一种高级的AOP(面向切面编程)功能。通过这种方式,你可以在运行时替换类中的方法,并提供自定义的实现逻辑。
  • 要想实现任意方法替换,首先要实现org.springframework.beans.factory.support.MethodReplacer提供的方法
public class ReplacementCompute implements MethodReplacer {public Object reimplement(Object o, Method method, Object[] objects) throws Throwable {// 获取原方法传入参数String input = (String) objects[0];// 执行新的指令方法return "Compute方法重构:" + input;}
}
  • 之后部署初始类,然后指定对应实现方法覆盖的Bean
<!-- 定义原方法Bean-->
<bean id="compute" class="com.nobugnolife.method_injection.Compute"><!-- 使用replaced-method关联需要覆盖的方法 name为方法名 replacer为指定覆盖方法的bean --><replaced-method name="ComputeValue" replacer="replacementCompute"><!-- 重载方法参数的签名,只有当方法重载时有多个变体时才是必要的 --><arg-type>String</arg-type></replaced-method>
</bean><bean id="replacementCompute" class="com.nobugnolife.method_injection.ReplacementCompute"/>
  • 任意方法替换的功能很灵活而且十分强大,但因为过于接近底层,而且会重构代码逻辑,容易造成非常危险的后果,因此尽量不要在开发中运用。

相关文章:

  • Qt如何将视频获取单帧
  • java实现pdf转word
  • Java基础知识点
  • MySQL 备份方案
  • EasyRecovery16电脑硬盘数据恢复软件功能详解
  • umi4 项目使用 keepalive 缓存页面(umi-plugin-keep-alive、react-activation)
  • 力扣hot100:560.和为K的子数组(前缀和+哈希表)
  • 基于Mindspore,通过Resnet50迁移学习实现猫十二分类
  • 【C++】类的默认成员函数(上)
  • 【S32DS报错】-8-调用初始化函数Port_Init后,S32DS断开与调试器PEmicro/J-Link的连接,无法调试Debug(基于MCAL)
  • 【conda】实现conda环境迁移的4种方式
  • 数字孪生10个技术栈:数据采集的八种方式
  • CL/opencl.h: No such file or directory(CentOS8 QT5.12.12)
  • Spring容器的启动流程
  • 如何在Word里一次性给全部汉字加拼音?
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • 【前端学习】-粗谈选择器
  • const let
  • CSS 专业技巧
  • Laravel 中的一个后期静态绑定
  • learning koa2.x
  • MaxCompute访问TableStore(OTS) 数据
  • MySQL QA
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • PHP 7 修改了什么呢 -- 2
  • TCP拥塞控制
  • vagrant 添加本地 box 安装 laravel homestead
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 构建二叉树进行数值数组的去重及优化
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 说说动画卡顿的解决方案
  • 通过来模仿稀土掘金个人页面的布局来学习使用CoordinatorLayout
  • 说说我为什么看好Spring Cloud Alibaba
  • 整理一些计算机基础知识!
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • ​低代码平台的核心价值与优势
  • ​力扣解法汇总946-验证栈序列
  • #define用法
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (4)(4.6) Triducer
  • (9)STL算法之逆转旋转
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (C语言)strcpy与strcpy详解,与模拟实现
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (Note)C++中的继承方式
  • (WSI分类)WSI分类文献小综述 2024
  • (过滤器)Filter和(监听器)listener
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (一)kafka实战——kafka源码编译启动
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • *p++,*(p++),*++p,(*p)++区别?
  • .axf 转化 .bin文件 的方法
  • .cfg\.dat\.mak(持续补充)
  • .net 使用ajax控件后如何调用前端脚本