【Spring源码系列- IOC】
1 | 【Spring源码】0.安装Gradle环境 | |
2 | 【Spring源码】1.下载与编译_pom relocation to an other version number is not f | |
3 | 【Spring源码】2.试个水先~Debug找到传说中的三级缓存(图解向,堆图预警) | |
4 | 【Spring源码】3. xml文件如何转换成BeanDefinition(主要涉及prepareRefresh()+ obtainFreshBeanFactory()两个函数,图解向,堆图预警)_spring xml转bean | |
5 | 【Spring源码】4. 自己搞个标签?~自定义标签保姆级全过程(图解向,堆图预警) | |
6 | 【Spring源码】5.spring的bean工厂准备工作(prepareBeanFactory(beanFactory) | |
7 | 【Spring源码】6. Spring扩展自定义属性编辑器保姆级教程 | |
8 | 【Spring源码】7. 如何添加自定义的BeanFactoryPostProcessor | |
9 | 【Spring源码】8. 捋下invokeBeanFactoryPostProcessors()主要处理流程 | |
10 | 【Spring源码】9. 超级重要的ConfigurationClassPostProcessor | |
11 | 【Spring源码】10. 递归调用的processConfigurationClass()方法 | |
12 | 【Spring源码】11. 我是注解类不?checkConfigurationClassCandidate()注解类判断方法详解 | |
13 | 【Spring源码】12. 注册bean处理器registerBeanPostProcessors() | |
14 | 【Spring源码】13. 国际化处理initMessageSource()源码解析 | 【补充内容】【保姆级】SpringBoot项目中的i18n国际化 |
15 | 【Spring源码】14. 消息多播器(观察者模式) | 【补充内容】【保姆级示例向】观察者模式 |
16 | 【Spring源码】15. Bean的创建过程(1.概述篇) | |
17 | 【Spring源码】16. Bean的创建过程(2) | |
18 | 【Spring源码】17.创建Bean这篇认真的@(・●・)@ | 【补充内容】 【保姆级·创建对象】如何通过Supplier创建对象 【保姆级·创建对象】如何通过factory-method创建对象 【保姆级·创建对象】如何利用resolveBeforeInstantiation()在预处理阶段返回一个Bean的实例对象 |
19 | 【Spring源码】18. factory-method创建对象关键函数详解:instantiateUsingFactoryMethod() | |
20 | 【Spring源码】19. 没合适的构造器?找determineCandidateConstructors()! | |
21 | 【Spring源码】20. MergedBeanDefinitionPostProcessor修改/合并bean定义 | 【补充内容】 【保姆级】@PostConstruct & @PreDestroy使用示例 【Spring源码】AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition()详解 【Spring源码】CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition()详解 |
22 | 【Spring源码】21. 初探循环依赖 | 【补充内容】 【保姆级】手把手Debug循环依赖的整体流程 【实践向】当移除了三级缓存…… 【分析向】没有三级缓存会导致什么? 【Spring源码】插播一个创建代理对象的wrapIfNecessary()方法 |
23 | 【Spring源码】22. 属性填充populateBean()详解 | 【补充内容】 【Spring源码】自动注入·名称:autowireByName()详解 【Spring源码】自动注入·类型:autowireByType()详解 【Spring源码】属性值的解析与赋值:populateBean().applyPropertyValues() 【保姆级】超超超简单的自定义注解实现@Autowired同款功能 |
24 | 【Spring源码】23. 执行初始化逻辑:initializeBean() |
本文目录
🌰
文件结构
创建实体类
创建配置文件
新建Spring配置文件
创建测试类
测试结果
测试分析
获取一个类的不同实例
xml配置文件
测试结果
测试分析
一句话:这个注解是在单例中引用原型使用的
详细点说: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();
}
创建配置文件
新建Spring配置文件
添加如下bean定义:
<bean id="dog" class="com.aqin.custom.MethodOverride.lookup.Dog"></bean>
<bean id="cat" class="com.aqin.custom.MethodOverride.lookup.Cat"></bean><bean id="animalAction_A" class="com.aqin.custom.MethodOverride.lookup.AnimalAction"><lookup-method name="getAnimal" bean="dog"></lookup-method>
</bean><bean id="animalAction_B" class="com.aqin.custom.MethodOverride.lookup.AnimalAction"><lookup-method name="getAnimal" bean="cat"></lookup-method>
</bean>
创建测试类
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的<lookup-method name="getAnimal" bean="dog"></lookup-method>标签中的bean="dog"是相对应的(animalAction_B类似)
获取一个类的不同实例
文件就用上面的结构就可以了,需要修改下测试类和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();}
}
xml配置文件
<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放在一级缓存中保存,以便下次直接获取,所以每次获取到的都是同一个实例)
返回的实际上是一个动态代理生成的对象
撒花(。・ω・。)ノ🎉🎉🎉