【Spring源码系列- IOC】
本文目录
一句话:这个注解是在单例中引用原型使用的
详细点说:Spring中默认的对象都是单例的(而且Spring会在一级缓存中保存该对象以便下次直接获取),如果是原型作用域,每次会创建一个新的对象。如果在单例模式的bean下引用一个原型模式的bean,此时就需要引用lookup-method标签来解决此类问题。 个人理解:由于当调用getBean()方法时,Spring会先在容器中查找有没有这个类,或者这个类的子类,通常情况下,Spring在查找的时候,如果没有匹配或者匹配到多个类都会报错,然而我们又想在一个程序中实现如下两个功能:
分别获取这个父类的两个不同的子类的实例
每次获取到的都是同一个类的不同实例
而lookup-method这个标签就是解决这些问题的
本文就是这两种情况的栗子🌰,感兴趣的同学可以跟着一步一步操作,绝对保姆级教程(不愧是俺(˶‾᷄ ⁻̫ ‾᷅˵))
获取同一父类的不同子类
这个示例一共需要新建6个文件

有4个实体类(一个父类+两个子类+一个操作类)
Animal.java(父类)

- package com.aqin.custom.MethodOverride.lookup;
-
- /**
- * @Description
- * @Author aqin1012 AQin.
- * @Date 2022/8/22 9:28 AM
- * @Version 1.0
- */
- public class Animal {
- public Animal() {
- System.out.println("吃点啥嘞?");
- }
- }
Cat.java

- package com.aqin.custom.MethodOverride.lookup;
-
- /**
- * @Description
- * @Author aqin1012 AQin.
- * @Date 2022/8/22 10:01 AM
- * @Version 1.0
- */
- public class Cat extends Animal{
- public Cat() {
- System.out.println("吃(_ _).。oO……猫粮");
- }
- }
Dog.java

- package com.aqin.custom.MethodOverride.lookup;
-
- /**
- * @Description
- * @Author aqin1012 AQin.
- * @Date 2022/8/22 9:29 AM
- * @Version 1.0
- */
- public class Dog extends Animal{
- public Dog() {
- System.out.println("吃(*≧ω≦)……狗粮");
- }
- }
AnimalAction.java

- package com.aqin.custom.MethodOverride.lookup;
-
- /**
- * @Description
- * @Author aqin1012 AQin.
- * @Date 2022/8/22 10:25 AM
- * @Version 1.0
- */
- public abstract class AnimalAction {
- /**
- * 获取执行该动作的动物
- *
- * @return
- */
- public abstract Animal getAnimal();
- }


添加如下bean定义:
"dog" class="com.aqin.custom.MethodOverride.lookup.Dog"> "cat" class="com.aqin.custom.MethodOverride.lookup.Cat"> -
"animalAction_A" class="com.aqin.custom.MethodOverride.lookup.AnimalAction"> -
"getAnimal" bean="dog"> -
"animalAction_B" class="com.aqin.custom.MethodOverride.lookup.AnimalAction"> -
"getAnimal" bean="cat">

- package com.aqin.custom.MethodOverride.test;
-
- import com.aqin.custom.MethodOverride.lookup.AnimalAction;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- /**
- * @Description
- * @Author aqin1012 AQin.
- * @Date 2022/8/22 10:29 AM
- * @Version 1.0
- */
- public class TestMethodOverride {
- public static void main(String[] args) {
- ApplicationContext applicationContext = new ClassPathXmlApplicationContext("MethodOverride.xml");
- AnimalAction animalActionA = (AnimalAction) applicationContext.getBean("animalAction_A");
- animalActionA.getAnimal();
- AnimalAction animalActionB = (AnimalAction) applicationContext.getBean("animalAction_B");
- animalActionB.getAnimal();
- }
- }

先在下图位置打个断点

选择debug方式执行

不断下一步,直到我们在配置类中配置的4个Bean都能在this对象中的singletonObjects中找到的时候,我们来查看使用了lookup-method标签的那两个Bean,可以看到这两个对象都是cglib的代理对象

当调用到getAnimal()方法时,会跳转到CglibSubclassingInstantiationStrategy中的intercept()方法中

这里的lo是animalAction_A,可以看到lo中的beanName跟xml配置文件中animalAction_A的

文件就用上面的结构就可以了,需要修改下测试类和xml配置文件
测试类做如下修改

- public class TestMethodOverride {
- public static void main(String[] args) {
- ApplicationContext applicationContext = new ClassPathXmlApplicationContext("MethodOverride.xml");
- AnimalAction animalActionB = (AnimalAction) applicationContext.getBean("animalAction_B");
- animalActionB.getAnimal();
- AnimalAction animalActionB_2 = (AnimalAction) applicationContext.getBean("animalAction_B");
- animalActionB_2.getAnimal();
- }
- }

- <bean id="dog" class="com.aqin.custom.MethodOverride.lookup.Dog" scope="prototype">bean>
- <bean id="cat" class="com.aqin.custom.MethodOverride.lookup.Cat" scope="prototype">bean>

此时this对象中的singletonObjects中就只有animalAction_A和animalAction_B两个了(因为Cat和Dog都的scope设置成了prototype(原型))

可以看到,两次获取的Cat一个是Cat@1730,一个是Cat@1790,并不是同一个对象,实现了在单例中引用原型(单例的bean会被Spring放在一级缓存中保存,以便下次直接获取,所以每次获取到的都是同一个实例)


返回的实际上是一个动态代理生成的对象

撒花(。・ω・。)ノ🎉🎉🎉