相信很多朋友对Spring已经很熟悉了,面试中也经常会被问到Spring里面相关的知识,比如IOC、DI、AOP等,下面通过手写IOC的方式来对IOC里面相关的内容,进行熟悉和理解


IOC分析

IOC是什么

Inversion of Control 控制反转,也称依赖倒置(反转)

如何理解这个控制反转呢?

反转:依赖对象的获得被反转了,由自己创建,反转为从IOC容器中获取(和自动注入);

也就是说,你不要来找我了,我去找你,传统的方式呢,是我在对象内部来去控制另外的对象,有了IOC,IOC是一个专门的容器,来创建和管理这些对象

比如,我们平时找女朋友或者男朋友,就会想方设法的去打听他们的联系方式啊,爱好啊等等,这些东西啊都是需要我们自己去做的。IOC呢就好比婚介所啊,聊天交友群啊之类的,然后我们可以向他们提出我们的要求,身高体重,长相身材啊等等,这些介绍的中间人就会按照我们的要求去提供一个对象,然后我们和提供的这个对象谈恋爱就行了

IOC能够带来什么好处

通过上述的简单描述可以知道,IOC有下面这些好处:

  1. 代码更加简洁,不需要自己去new使用的对象了,也做到了解耦
  2. 面向接口编程,使用者和具体者之间解耦,容易扩展和替换实现者
  3. 可以方便的进行AOP的增强

IOC容器是做什么工作的

IOC主要的工作就是创建、管理这些类的实例,然后可以向使用者提供这些实例

IOC容器是否是工厂模式的实例

是的,IOC负责来创建类的实例对象,需要的话就从IOC容器中get,那么也可以称IOC容器为Bean工厂,生产的就是Bean实例


IOC设计实现

设计IOC需要什么

通过上面短短的信息,可以知道IOC容器既然是一个Bean工厂,那么是不是需要一个Bean工厂的接口,负责创建和获取这些bean呢?

又怎么知道用户提供的bean是什么样的呢?是不是还需要一个接口来去定义这些Bean?

Bean工厂和Bean的定义接口都有了,那么Bean工厂又怎么知道该如何创建Bean,是不是需要把Bean定义的信息告诉Bean工厂啊,那么可以定义一个注册接口,来作为Bean工厂和Bean定义之间沟通的桥梁

总结,设计IOC需要下面三个元素:

1. Bean工厂接口

2. Bean定义接口

3. Bean定义的注册接口

定义接口

一:Bean工厂接口



主要用来创建和获取Bean实例

  1. /**
  2. * @ClassName BeanFactory
  3. * @Description: Bean工厂接口,负责创建和获取Bean
  4. * @Author TR
  5. * @Date 2021/3/25
  6. * @Version V1.0
  7. */
  8. public interface BeanFactory {
  9. /** 获取bean */
  10. Object getBean(String beanName) throws Exception;
  11. }

二:Bean定义的注册接口



Bean定义的注册接口中需要哪些方法呢?

是不是需要能够注册和获取Bean定义的信息,那么注册的这些Bean定义信息还需要去区分它,那是不是给每个Bean定义,让它有一个唯一的名字就行了啊

  1. /**
  2. * @ClassName BeanDefinitionRegistry
  3. * @Description: Bean定义的注册接口,作为Bean定义和Bean工厂之间的桥梁
  4. * @Author TR
  5. * @Date 2021/3/25
  6. * @Version V1.0
  7. */
  8. public interface BeanDefinitionRegistry {
  9. /** 注册Bean定义信息,beanName用来区分注册的Bean定义 */
  10. void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  11. throws BeanDefinitionRegisterException;
  12. /** 获取Bean信息 */
  13. BeanDefinition getBeanDefinition(String beanName);
  14. /** 是否已经注册过了Bean定义 */
  15. boolean containsBeanDefinition(String beanName);
  16. }

自定义的异常类:

  1. /**
  2. * @ClassName BeanDefinitionRegisterException
  3. * @Description: 自定义异常类
  4. * @Author TR
  5. * @Date 2021/3/25
  6. * @Version V1.0
  7. */
  8. public class BeanDefinitionRegisterException extends Exception {
  9. public BeanDefinitionRegisterException(String message) {
  10. super(message);
  11. }
  12. public BeanDefinitionRegisterException(String message, Throwable cause) {
  13. super(message, cause);
  14. }
  15. }

三:Bean定义接口



Bean定义它的用途是啥呢?就是告诉Bean工厂该如何去创建某个类的Bean

获取类的实例有下面几种方式:

1. new 构造方法

  1. User user = new User()

2. 工厂方法:静态工厂

  1. public class UserFactory {
  2. public static User getUser() {
  3. return new User();
  4. }
  5. }

3. 工厂方法:成员方法

  1. public class UserFactory {
  2. public User getUser() {
  3. return new User();
  4. }
  5. }

Bean工厂帮助我们创建Bean的时候需要知道哪些信息呢?

5. 通过new构造方法的话,需要知道类名

6. 通过静态工厂方法,需要知道工厂类名、工厂方法名

7. 通过成员工厂方法,需要知道工厂bean名、工厂方法名

那么每次从Bean工厂获取bean的实例时,是不是都需要创建一个新的bean呢?肯定不是啊,有的只需要单例的就行

Bean定义信息是需要告诉Bean工厂如何创建Bean的,那么Bean定义需要向Bean工厂提供一些方法:

  1. 获取Bean的类名:getBeanClass():Class
  2. 获取工厂方法名:getFactoryMethodName():String
  3. 获取工厂Bean名:getFactoryBeanName():String
  4. 是不是单例,作用范围等:getScope():String、isSingleton()、isPrototype()

提供上述的几种方法是不是就足够了呢?类对象的生命周期还会有什么呢?

  1. 创建对象后是不是还需要一些初始化:getInitMethodName():String
  2. 比如有些对象在销毁时还需要进行一些特定的销毁逻辑(如释放资源):getDestroyMethodName():String

那么提供上面的初始化方法和销毁方法,供用户使用,对Bean工厂呢,就是要获取这些初始化和销毁的方法

  1. /**
  2. * @ClassName Beandefinition
  3. * @Description: Bean定义接口
  4. * @Author TR
  5. * @Date 2021/3/25
  6. * @Version V1.0
  7. */
  8. public interface BeanDefinition {
  9. /** 单例 */
  10. String SCOPE_SINGLETON = "singleton";
  11. /** 多例 */
  12. String SCOPE_PROTOTYPE = "prototype";
  13. /** 通过构造方法获取Bean */
  14. Class<?> getBeanClass();
  15. /** 设置beanClass */
  16. void setBeanClass(Class<?> beanClass);
  17. /** 通过静态工厂获取Bean */
  18. String getFactoryMethodName();
  19. /** 设置工厂方法名称 */
  20. void setFactoryMethodName(String factoryMethodName);
  21. /** 通过成员工厂获取Bean */
  22. String getFactoryBeanName();
  23. /** 设置工厂Bean名称 */
  24. void setFactoryBeanName(String factoryBeanName);
  25. /** 获取范围 */
  26. String getScope();
  27. /** 设置范围 */
  28. void setScope(String scope);
  29. /** 是不是单例的 */
  30. boolean isSingleton();
  31. /** 是不是多例的 */
  32. boolean isPrototype();
  33. /** 获取初始化方法 */
  34. String getInitMethodName();
  35. /** 设置初始化方法 */
  36. void setInitMethodName(String initMethodName);
  37. /** 获取销毁方法 */
  38. String getDestroyMethodName();
  39. /** 设置销毁方法 */
  40. void setDestroyMethodName(String destroyMethodName);
  41. /**
  42. * 验证方法:
  43. * 用来在注册Bean定义的时候验证是否可以注册
  44. */
  45. default boolean validate() {
  46. //没有定义BeanClass,或者没有指定工厂方法或工厂bean,则不合法,
  47. //这就是在玩我啊,啥都没有就像要个对象
  48. if (getBeanClass() == null) {
  49. if (StringUtils.isBlank(this.getFactoryMethodName())
  50. || StringUtils.isBlank(this.getFactoryBeanName())) {
  51. return false;
  52. }
  53. }
  54. //定义了类,又定义了工厂bean,则不合法,不知道使用哪一个
  55. if (getBeanClass() != null && StringUtils.isNoneBlank(this.getFactoryBeanName())) {
  56. return false;
  57. }
  58. return true;
  59. };
  60. }

实现接口

接口有了,接下来是不是要去实现它们了,要去做点有意思的事情了呢?

首先呢。来实现一个通用的Bean定义的GenericBeanDefinition类

一:Bean定义的实现GenericBeanDefinition

Bean定义的实现类,相对来说比较简单,主要做的事情就是获取和设置Bean定义信息

  1. /**
  2. * @ClassName GenericBeanDefinition
  3. * @Description: Bean定义的实现类
  4. * @Author TR
  5. * @Date 2021/3/25
  6. * @Version V1.0
  7. */
  8. public class GenericBeanDefinition implements BeanDefinition {
  9. private Class<?> beanClass;
  10. private String factoryMethodName;
  11. private String factoryBeanName;
  12. private String initMethodName;
  13. private String destroyMethodName;
  14. private String scope = BeanDefinition.SCOPE_SINGLETON;
  15. @Override
  16. public Class<?> getBeanClass() {
  17. return beanClass;
  18. }
  19. @Override
  20. public void setBeanClass(Class<?> beanClass) {
  21. this.beanClass = beanClass;
  22. }
  23. @Override
  24. public String getFactoryMethodName() {
  25. return factoryMethodName;
  26. }
  27. @Override
  28. public void setFactoryMethodName(String factoryMethodName) {
  29. this.factoryMethodName = factoryMethodName;
  30. }
  31. @Override
  32. public String getFactoryBeanName() {
  33. return factoryBeanName;
  34. }
  35. @Override
  36. public void setFactoryBeanName(String factoryBeanName) {
  37. this.factoryBeanName = factoryBeanName;
  38. }
  39. @Override
  40. public String getScope() {
  41. return scope;
  42. }
  43. @Override
  44. public void setScope(String scope) {
  45. this.scope = scope;
  46. }
  47. @Override
  48. public boolean isSingleton() {
  49. return scope.equals(BeanDefinition.SCOPE_SINGLETON);
  50. }
  51. @Override
  52. public boolean isPrototype() {
  53. return scope.equals(BeanDefinition.SCOPE_PROTOTYPE);
  54. }
  55. @Override
  56. public String getInitMethodName() {
  57. return initMethodName;
  58. }
  59. @Override
  60. public void setInitMethodName(String initMethodName) {
  61. this.initMethodName = initMethodName;
  62. }
  63. @Override
  64. public String getDestroyMethodName() {
  65. return destroyMethodName;
  66. }
  67. @Override
  68. public void setDestroyMethodName(String destroyMethodName) {
  69. this.destroyMethodName = destroyMethodName;
  70. }
  71. @Override
  72. public String toString() {
  73. return "GenericBeanDefinition{" +
  74. "beanClass=" + beanClass +
  75. ", factoryMethodName='" + factoryMethodName + '\'' +
  76. ", factoryBeanName='" + factoryBeanName + '\'' +
  77. ", initMethodName='" + initMethodName + '\'' +
  78. ", destroyMethodName='" + destroyMethodName + '\'' +
  79. ", scope='" + scope + '\'' +
  80. '}';
  81. }
  82. }

二:Bean工厂的实现DefaultBeanFactory

接下来需要实现Bean工厂,让它可以初步的工作起来

首先思考一下,创建的bean定义信息是不是需要存起来啊,那么定义一个Map来缓存Bean定义的信息

  1. /** Bean定义缓存 */
  2. private Map<String, BeanDefinition> beanDefinitionMap
  3. = new ConcurrentHashMap<>();

创建好的Bean也需要存放起来,方便下一次获取

  1. /** Bean缓存 */
  2. private Map<String, Object> beanMap = new ConcurrentHashMap<>();

在getBean中需要做一些事情,创建Bean实例,然后可以初始化

  1. public class DefaultBeanFactory
  2. implements BeanFactory, BeanDefinitionRegistry {
  3. @Override
  4. public Object getBean(String beanName) throws Exception {
  5. return doGetBean(beanName);
  6. }
  7. }

接下来实现doGetBean方法:

通过上面的叙述,可以知道创建一个Bean实例有三种方法:通过构造方法、通过静态工厂、通过成员工厂方法,代码如下:

  1. private Object doGetBean(String beanName) throws Exception {
  2. //先去缓存里面判断一下,对应的beanName的对象是不是已经创建好了
  3. Object bean = beanMap.get(beanName);
  4. if (bean != null) {
  5. return bean;
  6. }
  7. BeanDefinition bd = beanDefinitionMap.get(beanName);
  8. Objects.requireNonNull(bd, "招不到【"+beanName+"】的Bean定义信息");
  9. Class<?> beanClass = bd.getBeanClass();
  10. if (beanClass != null) {
  11. //通过构造方法构建对象
  12. if (StringUtils.isBlank(bd.getFactoryMethodName())) {
  13. bean = createBeanByConstructor(bd);
  14. } else { //通过静态工厂构建对象
  15. bean = createBeanByStaticFactory(bd);
  16. }
  17. } else { //通过成员工厂构建对象
  18. bean = createBeanByFactoryBean(bd);
  19. }
  20. //开始bean的生命周期
  21. if (StringUtils.isNotBlank(bd.getInitMethodName())) {
  22. doInitMethod(bean, bd);
  23. }
  24. //对单例bean的处理
  25. if (bd.isSingleton()) {
  26. beanMap.put(beanName, bean);
  27. }
  28. return bean;
  29. }

代码逻辑:首先去beanMap里面拿Bean,如果已经存在了就直接返回了;然后根据beanName获取bean定义信息,后面加了一个根据beanName如果获取不到bean定义的非空判断;然后就是获取beanClass,如果说beanClass不等于空,工厂方法名字为空,那么可以知道这个是根据构造方法来创建Bean的;如果工厂方法非空,即是根据静态工厂创建Bean;如果beanClass是空的,那么可以断定是根据成员方法来创建Bean的

1. 通过构造方法创建Bean

首先肯定是要获取到类名,然后根据newInstance实例化Bean,最后返回就可以了

  1. /** 通过构造方法构建对象 */
  2. private Object createBeanByConstructor(BeanDefinition bd) throws Exception {
  3. //获取类名
  4. Class<?> type = bd.getBeanClass();
  5. //实例化bean
  6. Object bean = type.newInstance();
  7. return bean;
  8. }

2. 通过静态工厂创建Bean

静态工厂创建Bean,是根据类.方法名来创建的,首先也是获取到类名,然后就是获取工厂方法名,根据getMethod获取到方法,然后调用方法进行实例化

  1. /** 通过静态工厂构建对象 */
  2. private Object createBeanByStaticFactory(BeanDefinition bd) throws Exception {
  3. //获取工厂类名
  4. Class<?> type = bd.getBeanClass();
  5. //获取工厂方法名称
  6. String factoryMethodName = bd.getFactoryMethodName();
  7. Method method = type.getMethod(factoryMethodName, null);
  8. Object object = method.invoke(type, null);
  9. return object;
  10. }

3. 通过成员工厂创建Bean

成员工厂创建Bean,首先要获取到的就是工厂Bean,然后再获取工厂方法,最后根据getMethod获取到方法,然后调用方法进行实例化

  1. /** 通过成员工厂构建对象 */
  2. private Object createBeanByFactoryBean(BeanDefinition bd) throws Exception {
  3. //获取工厂bean名称
  4. String factoryBeanName = bd.getFactoryBeanName();
  5. //获取工厂bean
  6. Object factoryBean = getBean(factoryBeanName);
  7. //获取工厂方法
  8. String factoryMethodName = bd.getFactoryMethodName();
  9. Method method = factoryBean.getClass().getMethod(factoryMethodName, null);
  10. Object object = method.invoke(factoryBean, null);
  11. return object;
  12. }

下面是Bean注册接口的实现:

  1. @Override
  2. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionRegisterException {
  3. Objects.requireNonNull(beanName, "注册bean需要指定beanName");
  4. Objects.requireNonNull(beanDefinition, "注册bean需要指定beanDefinition");
  5. if (!beanDefinition.validate()) {
  6. throw new BeanDefinitionRegisterException("名字为【"+beanName+"】的beanName不合法," + beanDefinition);
  7. }
  8. if (containsBeanDefinition(beanName)) {
  9. throw new BeanDefinitionRegisterException("名字为【"+beanName+"】的beanName已经注册过了," + beanName);
  10. }
  11. beanDefinitionMap.put(beanName, beanDefinition);
  12. }
  13. @Override
  14. public BeanDefinition getBeanDefinition(String beanName) {
  15. return beanDefinitionMap.get(beanName);
  16. }
  17. @Override
  18. public boolean containsBeanDefinition(String beanName) {
  19. return beanDefinitionMap.containsKey(beanName);
  20. }

代码逻辑:注册Bean定义信息,首先要有beanName,这个是用来区分Bean定义信息的,所以加了非空判断,bean定义信息也要判断是否为空,然后根据bean定义接口里面的验证方法,判断bean定义信息是不是合法的,然后再根据containsBeanDefinition方法判断一下是不是已经注册过了,最后把注册的Bean定义信息放到beanDefinitionMap里面就可以了

通过实现Closeable来实现销毁的逻辑:

  1. @Override
  2. public void close() throws IOException {
  3. // 针对单例Bean执行销毁方法
  4. for(Map.Entry<String, BeanDefinition> e : beanDefinitionMap.entrySet()) {
  5. //获取BeanName
  6. String beanName = e.getKey();
  7. //获取Bean定义
  8. BeanDefinition definition = e.getValue();
  9. //如果是单例Bean并且销毁方法非空,那么就执行销毁方法
  10. if(definition.isSingleton() && StringUtils.isNotBlank(definition.getDestroyMethodName())) {
  11. //得到Bean
  12. Object instance = beanMap.get(beanName);
  13. if(instance == null) {continue;}
  14. Method m = null;
  15. try {
  16. m = instance.getClass().getMethod(definition.getDestroyMethodName(), null);
  17. m.invoke(instance, null);
  18. } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
  19. ex.printStackTrace();
  20. }
  21. }
  22. }
  23. }

整个代码实现:

  1. /**
  2. * @ClassName DeafultBeanFactory
  3. * @Description: Bean工厂的实现类
  4. * @Author TR
  5. * @Date 2021/3/25
  6. * @Version V1.0
  7. */
  8. public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Closeable {
  9. /** Bean定义缓存 */
  10. private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
  11. /** Bean缓存 */
  12. private Map<String, Object> beanMap = new ConcurrentHashMap<>();
  13. @Override
  14. public Object getBean(String beanName) throws Exception {
  15. return doGetBean(beanName);
  16. }
  17. private Object doGetBean(String beanName) throws Exception {
  18. //先去缓存里面判断一下,对应的beanName的对象是不是已经创建好了
  19. Object bean = beanMap.get(beanName);
  20. if (bean != null) {
  21. return bean;
  22. }
  23. BeanDefinition bd = beanDefinitionMap.get(beanName);
  24. Objects.requireNonNull(bd, "招不到【"+beanName+"】的Bean定义信息");
  25. Class<?> beanClass = bd.getBeanClass();
  26. if (beanClass != null) {
  27. //通过构造函数构建对象
  28. if (StringUtils.isBlank(bd.getFactoryMethodName())) {
  29. bean = createBeanByConstructor(bd);
  30. } else { //通过静态工厂构建对象
  31. bean = createBeanByStaticFactory(bd);
  32. }
  33. } else { //通过成员工厂构建对象
  34. bean = createBeanByFactoryBean(bd);
  35. }
  36. //开始bean的生命周期
  37. if (StringUtils.isNotBlank(bd.getInitMethodName())) {
  38. doInitMethod(bean, bd);
  39. }
  40. //对单例bean的处理
  41. if (bd.isSingleton()) {
  42. beanMap.put(beanName, bean);
  43. }
  44. return bean;
  45. }
  46. /** bean */
  47. private void doInitMethod(Object bean, BeanDefinition bd) throws Exception {
  48. Method method = bean.getClass().getMethod(bd.getInitMethodName(), null);
  49. method.invoke(bean, null);
  50. }
  51. /** 通过成员工厂构建对象 */
  52. private Object createBeanByFactoryBean(BeanDefinition bd) throws Exception {
  53. //获取工厂bean名称
  54. String factoryBeanName = bd.getFactoryBeanName();
  55. //获取工厂bean
  56. Object factoryBean = getBean(factoryBeanName);
  57. //获取工厂方法
  58. String factoryMethodName = bd.getFactoryMethodName();
  59. Method method = factoryBean.getClass().getMethod(factoryMethodName, null);
  60. Object object = method.invoke(factoryBean, null);
  61. return object;
  62. }
  63. /** 通过静态工厂构建对象 */
  64. private Object createBeanByStaticFactory(BeanDefinition bd) throws Exception {
  65. //获取工厂类名
  66. Class<?> type = bd.getBeanClass();
  67. //获取工厂方法名称
  68. String factoryMethodName = bd.getFactoryMethodName();
  69. Method method = type.getMethod(factoryMethodName, null);
  70. Object object = method.invoke(type, null);
  71. return object;
  72. }
  73. /** 通过构造函数构建对象 */
  74. private Object createBeanByConstructor(BeanDefinition bd) throws Exception {
  75. //获取类名
  76. Class<?> type = bd.getBeanClass();
  77. //实例化bean
  78. Object bean = type.newInstance();
  79. return bean;
  80. }
  81. @Override
  82. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionRegisterException {
  83. Objects.requireNonNull(beanName, "注册bean需要指定beanName");
  84. Objects.requireNonNull(beanDefinition, "注册bean需要指定beanDefinition");
  85. if (!beanDefinition.validate()) {
  86. throw new BeanDefinitionRegisterException("名字为【"+beanName+"】的beanName不合法," + beanDefinition);
  87. }
  88. if (containsBeanDefinition(beanName)) {
  89. throw new BeanDefinitionRegisterException("名字为【"+beanName+"】的beanName已经注册过了," + beanName);
  90. }
  91. beanDefinitionMap.put(beanName, beanDefinition);
  92. }
  93. @Override
  94. public BeanDefinition getBeanDefinition(String beanName) {
  95. return beanDefinitionMap.get(beanName);
  96. }
  97. @Override
  98. public boolean containsBeanDefinition(String beanName) {
  99. return beanDefinitionMap.containsKey(beanName);
  100. }
  101. @Override
  102. public void close() throws IOException {
  103. // 针对单例Bean执行销毁方法
  104. for(Map.Entry<String, BeanDefinition> e : beanDefinitionMap.entrySet()) {
  105. String beanName = e.getKey();
  106. BeanDefinition definition = e.getValue();
  107. if(definition.isSingleton() && StringUtils.isNotBlank(definition.getDestroyMethodName())) {
  108. Object instance = beanMap.get(beanName);
  109. if(instance == null) {continue;}
  110. Method m = null;
  111. try {
  112. m = instance.getClass().getMethod(definition.getDestroyMethodName(), null);
  113. m.invoke(instance, null);
  114. } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
  115. ex.printStackTrace();
  116. }
  117. }
  118. }
  119. }
  120. }

测试一下

首先定义一个接口:

  1. public interface Boy {
  2. void sayLove();
  3. }

Lad实现类:主要是验证通过new的方式

  1. public class Lad implements Boy {
  2. @Override
  3. public void sayLove() {
  4. System.out.println("我爱你,亲爱的!"+ hashCode());
  5. }
  6. //初始化方法
  7. public void init() {
  8. System.out.println("老天赐予我一个对象吧!");
  9. }
  10. //销毁方法
  11. public void destroy() {
  12. System.out.println("自古多情空余恨,此恨绵绵无绝期!");
  13. }
  14. }

BoyFactory类:验证静态工厂方法

  1. public class BoyFactory {
  2. public static Boy getBean() {
  3. return new Lad();
  4. }
  5. }

BoyFactoryBean实现类:验证成员工厂方法

  1. public class BoyFactoryBean {
  2. public Boy buildBoy() {
  3. return new Boy() {
  4. @Override
  5. public void sayLove() {
  6. System.out.println("我爱你,大妹子!"+ hashCode());
  7. }
  8. };
  9. }
  10. }

测试类:

  1. /**
  2. * @ClassName Test
  3. * @Description: 测试类
  4. * @Author TR
  5. * @Date 2021/3/25
  6. * @Version V1.0
  7. */
  8. public class TestDemo {
  9. static DefaultBeanFactory factory = new DefaultBeanFactory();
  10. /** 测试构造方法注册Bean */
  11. @Test
  12. public void testRegister() throws Exception {
  13. GenericBeanDefinition definition = new GenericBeanDefinition();
  14. //设置beanClass
  15. definition.setBeanClass(Lad.class);
  16. //设置为单例
  17. definition.setScope(BeanDefinition.SCOPE_SINGLETON);
  18. //设置初始化方法
  19. definition.setInitMethodName("init");
  20. //设置销毁方法
  21. definition.setDestroyMethodName("destroy");
  22. //注册bean定义
  23. factory.registerBeanDefinition("lad", definition);
  24. }
  25. /** 测试静态工厂注册Bean */
  26. @Test
  27. public void testRegisterStaticFactoryMethod() throws Exception {
  28. GenericBeanDefinition definition = new GenericBeanDefinition();
  29. //设置beanClass
  30. definition.setBeanClass(BoyFactory.class);
  31. //设置工厂方法名称
  32. definition.setFactoryMethodName("getBean");
  33. //注册bean定义
  34. factory.registerBeanDefinition("staticFactoryBoy", definition);
  35. }
  36. /** 测试成员方法注册Bean */
  37. @Test
  38. public void testRegisterFactoryMethod() throws Exception {
  39. GenericBeanDefinition definition = new GenericBeanDefinition();
  40. //首先要获取工厂Bean
  41. definition.setBeanClass(BoyFactoryBean.class);
  42. //工厂Bean的名称
  43. String fBeanName = "boyFactoryBean";
  44. //注册工厂Bean定义
  45. factory.registerBeanDefinition(fBeanName, definition);
  46. //然后设置工厂方法
  47. definition = new GenericBeanDefinition();
  48. //设置工厂Bean的名称
  49. definition.setFactoryBeanName(fBeanName);
  50. //设置工厂方法
  51. definition.setFactoryMethodName("buildBoy");
  52. //设置为多例
  53. definition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
  54. //注册bean定义
  55. factory.registerBeanDefinition("factoryBoy", definition);
  56. }
  57. @AfterClass
  58. public static void testGetBean() throws Exception {
  59. System.out.println("构造方法方式------------");
  60. for (int i = 0; i < 3; i++) {
  61. Boy boy = (Boy) factory.getBean("lad");
  62. boy.sayLove();
  63. }
  64. System.out.println("静态工厂方法方式------------");
  65. for (int i = 0; i < 3; i++) {
  66. Boy ab = (Boy) factory.getBean("staticFactoryBoy");
  67. ab.sayLove();
  68. }
  69. System.out.println("工厂方法方式------------");
  70. for (int i = 0; i < 3; i++) {
  71. Boy ab = (Boy) factory.getBean("factoryBoy");
  72. ab.sayLove();
  73. }
  74. factory.close();
  75. }
  76. }

执行后输出结果:

可以看到构造方法获取的Bean它的hashCode是一样的,即是单例的;成员方法设置了多例,看到的是hashCode是不一样的

至此,手写IOC容器就结束了,希望通过本篇文章,能够让您对Spring的IOC有更深刻的理解,感谢阅读!

本文其他知识点链接:

女娲造人引发思考之Java设计模式:工厂模式

这个世界上只有一个你之Java设计模式:单例模式

我自横刀向天笑,手写Spring IOC容器,快来Look Look!的更多相关文章

  1. 手写Spring AOP,快来瞧一瞧看一看撒!

    目录 AOP分析 Advice实现 定义Advice接口 定义前置.后置.环绕和异常增强接口 Pointcut实现 定义PointCut接口 定义正则表达式的实现类:RegExpressionPoin ...

  2. 利用递归,反射,注解等,手写Spring Ioc和Di 底层(分分钟喷倒面试官)了解一下

    再我们现在项目中Spring框架是目前各大公司必不可少的技术,而大家都知道去怎么使用Spring ,但是有很多人都不知道SpringIoc底层是如何工作的,而一个开发人员知道他的源码,底层工作原理,对 ...

  3. 手写一个IOC容器

    链接:https://pan.baidu.com/s/1MhKJYamBY1ejjjhz3BKoWQ 提取码:e8on 明白什么是IOC容器: IOC(Inversion of Control,控制反 ...

  4. 从零开始手写 spring ioc 框架,深入学习 spring 源码

    IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过 ...

  5. Spring源码分析 手写简单IOC容器

    Spring的两大特性就是IOC和AOP. IOC Container,控制反转容器,通过读取配置文件或注解,将对象封装成Bean存入IOC容器待用,程序需要时再从容器中取,实现控制权由程序员向程序的 ...

  6. 手写Spring Config,最终一战,来瞅瞅撒!

    上一篇说到了手写Spring AOP,来进行功能的增强,下面本篇内容主要是手写Spring Config.通过配置的方式来使用Spring 前面内容链接: 我自横刀向天笑,手写Spring IOC容器 ...

  7. 手写Spring DI依赖注入,嘿,你的益达!

    目录 提前实例化单例Bean DI分析 DI的实现 构造参数依赖 一:定义分析 二:定义一个类BeanReference 三:BeanDefinition接口及其实现类 四:DefaultBeanFa ...

  8. Spring事务原理分析--手写Spring事务

    一.基本概念和原理 1.Spring事务 基于AOP环绕通知和异常通知的 2.Spring事务分为编程式事务.声明事务.编程事务包括注解方式和扫包方式(xml) Spring事务底层使用编程事务(自己 ...

  9. 一个老程序员是如何手写Spring MVC的

    人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十 ...

随机推荐

  1. ASP.NET Core获取请求完整的Url

    在ASP.NET项目中获取请求完整的Url: 获取System.Web命名空间下的类名为HttpRequestBase的Url方法: /// <summary>在派生类中替代时,获取有关当 ...

  2. Basic认证时添加请求头

    http Basic认证 http协议定义的一种认证方式,将客户端id和客户端密码按照"客户端ID:客户端密码"的格式拼接,并用base64编 码,放在header中请求服务端, ...

  3. MYSQL 悲观锁和乐观锁简单介绍及实现

    1:悲观锁 1.1 特点: 每次查询都会进行锁行,怕"其他人"进行数据的修改. 1.2 实现步骤: 步骤1:开启事务test1,并对id=2的记录进行查询,并加锁,如:   步骤2 ...

  4. CSS过渡约束的计算

    CSS过度约束性质 什么是CSS过度约束 当没有开启绝对定位或固定定位时 水平布局必须要满足以下等式 探寻能够设置成auto的CSS属性 等式不成立(过度约束)时的几种情况 当margin与width ...

  5. go mod管理 init 和 包导入的关系

    你创建了一个文件的名字为:lisi001 如果你初始化项目名字为lisi, go mod init lisi 那么你导包的时候就得也用lisi import ( "lisi/path&quo ...

  6. (三)MySQL锁机制 + 事务

    转: (三)MySQL锁机制 + 事务 表锁(偏读) 偏向MyISAM存储引擎.开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发最低. 查看当前数据库中表的上锁情况,0表示未上锁. sh ...

  7. PAT-1102(Invert a Binary Tree)+二叉树的镜像+层次遍历+中序遍历+已知树的结构构树

    Invert a Binary Tree pat-1102 import java.util.Arrays; import java.util.Queue; import java.util.Scan ...

  8. [个人总结]pip安装tensorboard太慢

    在执行pip install语句的时候直接指定国内豆瓣的镜像源进行下载: pip install -i https://pypi.douban.com/simple 你想下载的包的名称 例如下载ten ...

  9. ArrayList源码分析笔记

    ArrayList源码分析笔记 先贴出ArrayList一些属性 public class ArrayList<E> extends AbstractList<E> imple ...

  10. vue Element-ui el-menu 左侧导航条

    <template> <!--实现左侧导航条动态渲染(三级)--> <el-menu class="el-menu-vertical-demo" @o ...