方法注入 ‹lookup-method/›

Exisi 2022-06-28 07:44:38
Categories: Tags:
  • 用于注入方法返回结果,也就是说能通过配置方式替换方法返回结果。(在方法或者抽象方法上使用@Lookup注解,将会根据该方法的返回值,自动在BeanFactory中调用getBean()来注入该Bean)

语法

<bean class="beanClass">

<lookup-method name="method" bean="non-singleton-bean"/>

</bean>

 

参数

描述

name

methodbeanClass中的一个方法,可以不是抽象方法

bean

non-singleton-bean指的是lookup-methodbean属性指向的必须是一个非单例模式的bean

当然如果不是也不会报错,只是每次得到的都是相同引用的bean(同一个实例),这样用lookup-method就没有意义了

  • 另外对于method在代码中的签名有下面的标准:

 

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

 

参数

描述

public|protected

方法必须是可以被子类重写和调用的

abstract

可选,如果是抽象方法,CGLIB的动态代理类就会实现这个方法,如果不是抽象方法,就会覆盖这个方法

return-type

non-singleton-bean的类型,当然可以是它的父类或者接口。

no-arguments

不允许有参数。

 

  • 假设一个单例模式的 bean A 需要引用另外一个非单例模式的 bean B

 

  • 为了在每次引用的时候都能拿到最新的 bean B,可以让 bean A 通过实现 ApplicationContextWare 来感知 applicationContext(即可以获得容器上下文),从而能在运行时通过 ApplicationContext.getBean(String beanName) 的方法来获取最新的 bean B

 

  •  但是如果用 ApplicationContextAware 接口,就与 Spring 代码耦合了,违背了控制反转使用 bean 完全由 Spring 容器管理

 

  • 所以 Spring 提供了方法注入的方式来实现以上的场景。方法注入方式主要是通过 <lookup-method/> 标签。

 

  • 假设有一个果盘,果盘里放了一些水果,比如苹果,香蕉等,我们希望我们每次在果盘里拿到的都是最新鲜的水果。

实例

  • Java

// 定义一个水果类

public class Fruit {
   
public Fruit() {
        System.out.println("I got Fruit");
    }
}

 

 

// 苹果

public class Apple extends Fruit {
   
public Apple() {
        System.out.println("I got a fresh apple");
    }
}

 

 

// 香蕉

public class Bananer extends Fruit {
   
public Bananer () {
        System.out.println("I got a  fresh bananer");
    }
}

 

 

// 水果盘,可以拿到水果

public abstract class FruitPlate{
   
// 抽象方法获取新鲜水果

     protected abstract Fruit getFruit();
}

 

  • applicationCnotext.xml

<!-- 这是2个非单例模式的bean -->

<beans>

<bean id="apple" class="cn.com.willchen.test.di.Apple" scope="prototype" />

<bean id="bananer" class="cn.com.willchen.test.di.Bananer" scope="prototype" />

 

<!-- 拿苹果 -->

<bean id="fruitPlate" class="cn.com.willchen.test.di.FruitPlate">

    <lookup-method name="getFruit" bean="apple" />

</bean>

 

<!-- 拿香蕉 -->

<bean id="fruitPlate" class="cn.com.willchen.test.di.FruitPlate">

    <lookup-method name="getFruit" bean="bananer" />

</bean>

<beans>

 

  • Test.java

public static void main(String[] args) {

ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");

FruitPlate fp1= (FruitPlate) app.getBean("fruitPlate1");

FruitPlate fp2 = (FruitPlate) app.getBean("fruitPlate2");

fp1.getFruit();   

fp2.getFruit();

}

 

运行结果:

I got Fruit

I got a fresh apple

I got Fruit

I got a fresh bananer

 

解释

  • 从上面例子我们可以看到,在代码中,我们没有用到 Spring 的任何类和接口,实现了与 Spring 代码的耦合。

 

  • 其中,最为核心的部分就是 lookup-method 的配置和 FruitPlate.getFruit() 方法。

 

  • 上面代码中,我们可以看到 getFruit() 方法是个抽象方法,我们并没有实现它啊,那它是怎么拿到水果的呢。这里的 Srping 应用了 CGLIB(动态代理)类库。

 

  • Spring 在初始化容器的时候对配置 <lookup-method/> bean 做了特殊处理,Spring 会对 bean 指定的 class 做动态代理,代理 <lookup-method/> 标签中 name 属性所指定的方法,返回 bean 属性指定的 bean 实例对象。

 

  • 每次我们调用 fruitPlate1 或者 fruitPlate2 2 bean getFruit() 方法时,其实是调用了 CGLIB 生成的动态代理类的方法,自动实现抽象类中的方法

 

 

来自 <https://www.cnblogs.com/ViviChan/p/4981619.html>