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

image

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,273评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,349评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,709评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,520评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,515评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,158评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,755评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,660评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,203评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,287评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,427评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,122评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,801评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,272评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,393评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,808评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,440评论 2 359

推荐阅读更多精彩内容