Spring高级功能:Spring方法注入

程序汪丶 2019-06-23 22:14:09

Spring高级功能:Spring方法注入

 

无状态 Bean 的作用域一般可以配置为 singleton(单例模式),如果我们往 singleton 的 Boss 中注入 prototype 的 Car,并希望每次调用 boss Bean 的 getCar() 方法时都能够返回一个新的 car Bean,使用传统的注入方式将无法实现这样的要求。因为 singleton 的 Bean 注入关联 Bean 的动作仅有一次,虽然 car Bean 的作用范围是 prototype 类型,但 Boss 通过 getCar() 方法返回的对象还是最开始注入的那个 car Bean。

如果希望每次调用 getCar() 方法都返回一个新的 car Bean 的实例,一种可选的方法就是让 Boss 实现 BeanFactoryAware 接口,且能够访问容器的引用,这样 Boss 的 getCar() 方法就可以采取以下实现方式来达到目的:

public Car getCar(){
 //通过 getBean() 返回 prototype 的 Bean,每次都将返回新实例
 return (Car)factory.getBean("car");
}

但这种依赖 Spring 框架接口的设计将应用与 Spring 框架绑定在一起,部分开发者可能并不喜欢。针对前面提出的需求,是否有既不与 Spring 框架绑定,又可享受依赖注入好处的实现方案?Spring 没有让我们失望,可以通过方法注入的方案完美地解决这个问题。

1. lookup 方法注入

Spring loc 容器拥有复写 Bean 方法的能力,这项魔术般的功能归功于 CGLib 类包。CGLib 可以在运行期动态操作 Class 字节码,为 Bean 动态创建子类或实现类。关于 CGLib 的进一步介绍,将在以后的文章中介绍。

现在声明一个 MagicBoss 接口,并声明一个 getCar() 的接口方法。

public interface MagicBoss {
 Car getCar(); 
}

下面不编写任何实现类,仅通过配置为该接口提供动态的实现,让 getCar() 接口方法每次都返回新的 car Bean。

<!--①prototype类型的Bean-->
<bean id="car" class="com.smart.injectfun.Car"
 p:brand="红旗CA72" p:price="2000" scope="prototype"/>
<!--②实施方法注入-->
<bean id="magicBoss" class="com.smart.injectfun.MagicBoss" >
 <lookup-method name="getCar" bean="car"/>
</bean>

通过 lookup-method 元素标签为 MagicBoss 的 getCar() 提供动态实现,返回 prototype 类型的 car Bean,这样 Spring 将在运行期为 MagicBoss 接口提供动态实现,其效果等同于:

public class InjectFunTest {

 public ApplicationContext factory = null;
 private static String[] CONFIG_FILES = { "com/smart/injectfun/beans.xml" };

 @BeforeMethod
 public void setUp() throws Exception {
 factory = new ClassPathXmlApplicationContext(CONFIG_FILES);
 
 }

 @Test
 public void testLookup(){
 MagicBoss mboss = (MagicBoss) factory.getBean("magicBoss");
 assertNotSame(mboss.getCar(),mboss.getCar());
 }
}

因为每次调用 MagicBoss 的 getCar() 方法都会从容器中获取 car Bean,由于 car Bean 的作用域为 prototype,所以每次都返回新的 car 实例。

如果将 car Bean 的作用域设置为 singleton,虽然以上配置仍然可以运行,但这时 lookup 所提供的方法注入就没有什么意义了。因为我们可以容易地编写一个 MagicBoss 接口实现类,用属性注入的方式达到相同的目的。所以 lookup 方法注入是有一定使用范围的,一般在希望通过一个 singleton Bean 获取一个 prototype Bean 时使用。

提示:由于方法注入时 Spring 需要用到 CGLib 类包,所以需要将 CGLib 类包加入到类路径中,否则无法使用方法注入的功能。

2. 方法替换

在金庸笔下,“乾坤大挪移”是明教至高无上的神功,在《倚天屠龙记》里会九阳神功的张无忌最终修成了正果。在 Spring IOC 容器里,用户同样可以拥有这种“乾坤大挪移”的能力:可以使用某个 Bean 的方法去替换另一个 Bean 的方法。

在下面的例子中,Boss1的 getCar() 方法返回一辆宝马Z4。

public class Boss1 implements MagicBoss{
 public Car getCar() {
 Car car = new Car();
 car.setBrand("宝马Z4");
 return car;
 }
}

Boss2 实现了 Spring 的 org.springframework.beans.factory.support.MethodReplacer 接口,在接口方法 reimplement() 中,返回一辆美人豹。

package com.smart.injectfun;
import java.lang.reflect.Method;
import org.springframework.beans.factory.support.MethodReplacer;

public class Boss2 implements MethodReplacer {

 public Object reimplement(Object arg0, Method arg1, Object[] arg2) throws Throwable {

 Car car = new Car();
 car.setBrand("美人豹");
 return car;
 }
}

用于替换他人的 Bean 必须实现 MethodReplacer 接口,Spring 将利用该接口的方法去替换目标 Bean 的方法。下面通过 Spring loc 容器的“乾坤大挪移”术,用 Boss2 的方法去替换 Boss1 的 getCar() 方法。

<bean id="boss2" class="com.smart.injectfun.Boss2"/>
 
<bean id="boss1" class="com.smart.injectfun.Boss1">
  <replaced-method name="getCar" replacer="boss2"></replaced-method>
</bean>

当从容器中返回 boss1 Bean 并调用其 getCar() 方法时,将返回一辆“美人豹”的car,调包成功。

但这种高级功能就像《宋玉答楚王问》中所说的阳春白雪一样,在实际应用中很少使用,而属性注入、构造函数注入等“下里巴人”式的普通功能反而在实际项目中使用最多。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值