spring步步前行(IOC)-整理篇

从之前的ioc部分的源码分析等,我们对spring-ioc部分的相关已经有了一部分认识和了解,但是还是有很多人对里面一些部分的理解还是很模糊,好比既然有了beanFactory那factoryBean是干什么的,在ioc中有很多相关的aware这种后缀的类的命名,感觉应该有声明上的相似,但是却可能在之前的文章都一笔带过了…

​ 鉴于诸如此类的,我想通过demo的方式,从表现形式上来区分所谓的beanFactory和FactoryBean,以及aware这类的意义

BeanFactory与FactoryBean

对于FactoryBean而言,想要体现factoryBean的强大的话,需结合AOP才能体现出来其强大,这里我们先初步分析,留待之后与AOP结合分析,为什么要与AOP结合分析,我们先看看官方描述

出自FactoryBean官方注释说明:

		A bean that implements this interface cannot be used as a normal bean. A FactoryBean is defined in a bean style, but the object exposed for bean references ({@link #getObject()}) is always the object that it creates.

		This interface is heavily used within the framework itself, for example for the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for custom components as well; however, this is only common for infrastructure code.

虽然FactoryBean定义为一个bean的形式,但是会通过getObject方法将一些对象暴露出来,我们可以通过ProxyFactoryBean的getObject中先了解下可知任何实现了beanFactory的bean都可通过getObject获取这个类型的bean

官方在AOP的ProxyFactoryBean或JndiObjectFactoryBean中有这两个类可作为示例,接口是在框架内大量使用,也能被使用在自定义的组建,然后这个仅在基础结构代码中常见

上一篇咱们简单的提及了factoryBean, 我们借助beanFactory通过"&"+beanName的方法查找class,现在我们就看下spring对这块的官方说明

在这里插入图片描述

即在beanFactory中有这一个说明,就是其通过&这个符号来获取factoryBean,到此factoryBean我们就了解到,其FactoryBean的getObject()返回的对象,而不是FactoryBean本身, 如果要获取FactoryBean对象,可以在id前面加一个&符号来获取

废话不多说直接上实例:

首先我们既然要看factorybean,那我们就实现一个,既然官方为我们提供了ProxyFactoryBean和JndiObjectFactoryBean中两个类作为示例,那我们就从示例中类比写出一个简单的factoryBean来印证

  • 实现factorybean接口

    public class ProxyMyFactoryBean implements FactoryBean {
    
        public Object getObject() throws Exception {
            return null;
        }
    
        public Class<?> getObjectType() {
            return null;
        }
    
        public boolean isSingleton() {
            return false;
        }
    }
    
  • factoryBean中只有三个方法,我们一边结合官方注释和官方示例的ProxyFactoryBean来"丰满"各个方法

    • getObject方法

      在这里插入图片描述

      官方的描述是这样的"返回一个在factory中被管理的类的实例"

    • isSingleton()方法

      在这里插入图片描述

      即在factory中被管理的类是否是单例的

      在ProxyFactoryBean中其实现的getObject()的方法用了以上两个方法

      在这里插入图片描述我们不关心其中间的实现,我们就关注其返回结果,可发现,如果是单例的话,就通过创建单例的方式创建一个实例返回,否则的话,就直接创建一个对象返回

    • getObjectType方法

      在这里插入图片描述

      可了解其是返回factoryBean创建的实例的类型,可能有些人跟我一样理解不了要这玩意儿干啥,我们再看看其具体描述"这个方法允许在不实例化对象的情况下检查特定类型的bean,例如在autowiring时",感觉有点用还是不太清楚,看看示例辅助下

      在这里插入图片描述

      从这里我们也关注其返回的结果,

      • 单例实例时,就返回该实例的class对象,否则的话获取代理接口,
      • 如果是一个的多就返回该代理接口的class对象
      • 如果是多个的话就创建一个组合接口的class对象
      • 如果targetName不为null且beanFactory不为null就从beanFactory中找到tagetName的class类型返回
      • 如果均不符合,那就返回targetSource的class

      简单理解就是返回我们getObject创建实例的关联类的class

  • "丰满"我们的factoryBean

    • 准备工作,由于其是返回示例所以我们需要创建类来辅助我们

      public class TargetA {
          public void print() {
              System.out.println("-----print--AAA----succeed---");
          }
      }
      public class TargetB {
          public void print() {
              System.out.println("-----print--BBB----succeed---");
          }
      }
      
    • "丰满”工作

      public class ProxyMyFactoryBean implements FactoryBean {
      
          private String targetName;
      
          public void setTargetName(String targetName) {
              this.targetName = targetName;
          }
      
          public Object getObject() throws Exception {
              if("aaa".equals(targetName)) {
                  return new TargetA();
              }
              return new TargetB();
          }
      
          public Class<?> getObjectType() {
              if("aaa".equals(targetName)) {
                  return TargetA.class;
              }
              return TargetB.class;
          }
      
          public boolean isSingleton() {
              return false;
          }
      }
      
    • 创建bean的xml配置factorybean信息

      <bean id="proxyMyFactoryBean" class="org.tutor.spring.ioc.bean.ProxyMyFactoryBean">
              <property name="targetName" value="aaa"/>
      </bean>
      
    • 运行结果

      在这里插入图片描述

      从其运行结果我们都能获取到targetA的实例用以操控

  • 总结

    beanFactory就不在此处详细介绍,不过我们做一下从上面运行的方式,我们都能看到无论beanFactory还是FactoryBean我们都能获取我们想要的实例对象

    • beanFactory相当于bean的容器,可以理解成工厂,内可以帮我们创建bean,对bean进行管理

    • factoryBean虽然也可以创建bean,其更多的是对class上进行代理处理,从我们的测试方法,我们很容易就可以想到,明显代理的痕迹

      这里我引用一张图加以理解

      在这里插入图片描述

      就是我们通过设置目标的class属性从factoryBean中获取目标class的代理对象

      可能有人会疑问为什么会有这样的设计,其实spring在aop中已经回答我们,不过我们也可以从代理模式的优点能理解其意义也是可以

      • 在符合开闭原则的情况下对目标对象进行功能扩展

      那么我们就可以大胆的猜想,其就是为了让我们在持有目标对象时,丰富对象功能,也可以不在关注具象实现,有需求方关注(具体我们在AOP处,对ProxyFactoryBean的应用处可了解)

BeanNameAware与BeanFactoryAware

在这里插入图片描述

BeanNameAware是对于需要获取在beanFactory的beanName的时候就实现

在这里插入图片描述

BeanFactoryAware是由对应的BeanFactory实现的,即可获取该bean所在的beanFactory名称,可以获取配置他们的BeanFactory的引用

总结

由于BeanNameAware和BeanFactoryAware均都是spring内实现,故其实对我们应用及其有限,但它们对spring而言,却不一样,我们可以从spring代码书写来理解

  • BeanNameAware

    在这里插入图片描述

    类似这样,本身springLifeBean没有什么意义,只是我们做的一个标记,便于理解

  • BeanFactoryAware

    这个方法可能是在根据某个配置文件创建了一个新工厂之后,Spring才调用这个方法,并把BeanFactory注入到Bean中。
    让bean获取配置自己的工厂之后,当然可以在Bean中使用这个工厂的getBean()方法,但是,实际上非常不推荐这样做,因为结果是进一步加大Bean与Spring的耦合,而且,能通过DI注入进来的尽量通过DI来注入。
    当然,除了查找bean,BeanFactory可以提供大量其他的功能,例如销毁singleton模式的Bean。
    factory.preInstantiateSingletons();方法。preInstantiateSingletons()方法立即实例化所有的Bean实例,有必要对这个方法和Spring加载bean的机制做个简单说明。
    方法本身的目的是让Spring立即处理工厂中所有Bean的定义,并且将这些Bean全部实例化。因为Spring默认实例化Bean的情况下,采用的是lazy机制,换言之,如果不通过getBean()方法(BeanFactory或者ApplicationContext的方法)获取Bean的话,那么为了节省内存将不实例话Bean,只有在Bean被调用的时候才实例化它们

    引用自网上对BeanFactoryAware的描述

Springbean的初始化顺序

​ 对于IOC我们也分析有一段时间了,既然IOC是对bean的操作,那么我们还没有正面关注过,接下来,通过bean的初始化过程,继续巩固一路走来的IOC分析

​ 在我们分析SpringFactory的refresh时候,其依次顺序是aware 然后InitializingBean,最后进入的是postProcessor,那我们通过实现这些接口看看其的顺序是否跟我们的refresh分析是否相左

  • 准备工作

    创建一个类,实现’BeanFactoryAware,BeanNameAware,BeanFactoryPostProcessor,BeanPostProcessor,InitializingBean’这些接口

    public class TestLifeCycleBean implements BeanFactoryAware,BeanNameAware,BeanFactoryPostProcessor,BeanPostProcessor,InitializingBean {
    
        private String name;
    
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public TestLifeCycleBean() {
            System.out.println("into... 构造函数");
        }
    
        /**
         * init-method
         */
        public void initMethod(){
            System.out.println("into... init-method");
        }
    
        public void say(){
            System.out.println("into... say hello I am "+name);
        }
    
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            System.out.println("into... setBeanFactory and beanFactory is "+beanFactory);
        }
    
        public void setBeanName(String s) {
            System.out.println("into...  setBeanName and name is "+s);
        }
    
        public void afterPropertiesSet() throws Exception {
            System.out.println("into... InitializingBean接口的afterPropertiesSet and name is "+ name);
        }
    
    
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
            System.out.println("into... BeanFactoryPostProcessor接口的postProcessBeanFactory and this beanFactory is "+configurableListableBeanFactory);
        }
    
        public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
            System.out.println("into... BeanPostProcessor接口的postProcessBeforeInitialization: "+o.getClass());
            return o;
        }
    
        public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
            System.out.println("into... BeanPostProcessor接口的postProcessAfterInitialization: "+o.getClass());
            return o;
        }
    }
    

    在这里可能我们打印的结果可能是这样的

    在这里插入图片描述

    很明显BeanPostProcessor的相关方法并没有产生作用,这是我们之前的大战BeanPostProcessor有说明,我们只用实例化一个bean即可

    在这里插入图片描述

    总结其springbean的初始化顺序

    • 1.先执行构造函数
    • 2.之行BeanNameAware方法
    • 3.执行BeanFactoryAware方法
    • 4.之行InitializingBean方法
    • 5.执行指定的init-method方法
    • 6.执行BeanFactoryPostProcessor方法
    • 7.最后才有BeanPostProcessor方法

回顾之前的refresh

有没有豁然开朗的感觉?!就先整理这些吧,持续整理更新…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章