Spring中的@Lookup注解和<lookup-method>标签

@Lookup 是xml配置标签look-up的注解实现。

一、<lookup-method/>标签

假设一个单例模式的bean A需要引用另外一个非单例模式的bean B,为了在我们每次引用的时候都能拿到最新的bean B,我们可以让bean A通过实现ApplicationContextWare来感知applicationContext(即可以获得容器上下文),从而能在运行时通过ApplicationContext.getBean(String beanName)的方法来获取最新的bean B。但是如果用ApplicationContextAware接口,就让我们与Spring代码耦合了,违背了反转控制原则(IoC,即bean完全由Spring容器管理,我们自己的代码只需要用bean就可以了)。
所以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();
}

spring配置:

<!-- 这是2个非单例模式的bean -->
<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="fruitPlate1" class="cn.com.willchen.test.di.FruitPlate">
    <lookup-method name="getFruit" bean="apple"/>
</bean>
<bean id="fruitPlate2" class="cn.com.willchen.test.di.FruitPlate">
    <lookup-method name="getFruit" bean="bananer"/>
</bean>

测试代码:

public static void main(String[] args) {
    ApplicationContext app = new ClassPathXmlApplicationContext("classpath:resource/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在初始化容器的时候对配置的bean做了特殊处理,Spring会对bean指定的class做动态代理,代理标签中name属性所指定的方法,返回bean属性指定的bean实例对象。每次我们调用fruitPlate1或者fruitPlate2这2个bean的getFruit()方法时,其实是调用了CGLIB生成的动态代理类的方法。关于CGLIB大家可自行在网上查阅。
lookup-method实现方式说明:

<bean class="beanClass">
	<lookup-method name="method" bean="non-singleton-bean"/>
</bean>
二、@Lookup注解

实例
有一个单例的Boy类:

@Component
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) //原型 也就是非单例
public class Boy {
    public void playToy() {
        Toy toy = getToy();
        System.out.println(toy);
    }

    @Lookup
    public Toy getToy() {
        return null;
    }
}

然后他每次要playToy()的时候,都会生成一个新的Toy对象,Toy是原型类型的,并且用@Lookup注解修饰playToy()方法,方法体里面返回空,Spring会自动生成一个代理对象:

@Component
@Scope(scopeName= ConfigurableBeanFactory.SCOPE_PROTOTYPE) //原型 也就是非单例
public class Toy {

    public Toy() {
        System.out.println("Buy a new toy...");
    }
}

THE END.

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值