美文网首页
一次讲透彻 beanFactory和factoryBean

一次讲透彻 beanFactory和factoryBean

作者: 撸代码的大白 | 来源:发表于2020-05-14 15:46 被阅读0次

    这个问题说简单很简单,说很难也很难。很多博客或者文章并没有讲的通俗易懂。

    这两个都是接口,为了更通俗易懂的来讲明白这个问题,我们反其道而行之,先讲解factoryBean。

    我们先来实现一下factoryBean接口:

    MyFactoryBean

    其中Apple是一个普通的类,实现了Phone接口:

    Apple

    注意Apple没有加注解,也没有通过@Configuration去new,更没有通过配置文件。却可以自动注入:

    TestFactoryBean

    这个TestFactoryBean的test方法可以正常执行Apple的方法。

    执行context.getBean(TestFactoryBean.class).test();结果为:aaaaaaaaaaaa 苹果手机打电话

    通过上面的代码,我们可以发现FactoryBean可以起到,将普通类交给Spring容器管理的作用。

    估计有的同学会有疑惑,这怎么跟脱了裤子放屁一样,直接@bean或者@Component把Apple交给spring管理不就完事儿了么。其实正是因为做不到直接交给spring管理或者直接交给Spring管理会跟预期不一致,才会想这么个办法。

    当然这么解释过于简单,我们从spring容器初始化的主要流程来解释一下。方便不同基础的同学来理解。

    我们都知道,spring容器是管理bean的,我们可以通过很多方式将自己定义的class交给spring去管理。比如说xml、注解、config、@import等等。那么spring是怎么管理这些bean的呢?

    首先需要有个对象去描述class,熟悉反射的同学会知道对于某个类,java是用Class对象去描述的,提供了可以获取类的属性、方法、元数据的方法。那么spring的bean是与普通的class是有区别的,除了class的一些属性,还有scope、lazy、primary等等。于是spring定义了BeanDefinition来描述spring的bean。我们可以理解为bean的定义。

    理解的bean的定义,那么我们可以简单的认为,spring容器的初始化主要是做了两件事儿:

    1、将所有需要被spring管理的bean对应的BeanDefinition生成,并放入到map里。

    2、根据BeanDefinition将需要实例化的bean实例化成对象。(实例化过程中很重要的一点是对@Autowired的引用进行赋值)

    说到这里,大家可能有疑问了,这他喵的跟FactoryBean有什么关系?

    别急,思考一下如果要实现这两步,一般要怎么做?我觉得如果没接触过spring,我的大体思路是这样的:

    1、定位文件资源,并使用classloader将class加载到jvm内。并构造BeanDefinition。

    2、通过反射调用其构造方法,将类实例化。放入到map内。

    3、遍历map内的对象,并对其属性赋值。

    对于常规的类,这样的做法没什么问题。但是有些情况就不行。我举个特殊的例子,当然这只是FactoryBean的其中一个作用。如果说,在容器启动的时候你只有一个接口叫A。A没有任何实现,需要动态代理去生成实现类,假设这个实现类最后生成出来实现类是proxy$1。

    那么你怎么去完成构造BeanDefinition和实例化?

    构造BeanDefinition可以简单的理解为:

    BeanDefinition bd = new BeanDefinition(xxx.class)

    但问题是,class是运行时才生成的,没法知道是哪个,这怎么办呢?写成proxy$1.class?这明显是不行的。写A.class?这肯定也是不行的。

    怎么将这个过程动态化呢?BeanDefinition bd = new BeanDefinition(xxx.class)这个传参是没办法解决了,需要传入一个确定的class。于是spring想了个办法,在new BeanDefinition的时候放入一个第三方的类xxxFactoryBean.class。

    这样第一步"生成BeanDefinition,并放入到map"里完成了

    那当需要实例化A的实现时候怎么办呢?spring判断,如果BeanDefinition内对应的class是实现了FactoryBean接口的,那不直接返回FactoryBean本身的实例,而是调用实例的方法即getObject。

    到现在是不是可以理解FactoryBean了呢:总结来说,就是一种方法,要么是解决生成BeanDefinition的困难;要么是解决反射实例化bean时候遇到的困难,将spring不好自动化处理的逻辑写到getObject方法内。

    那么如果不想获得A的实现类,而想获得xxxFactoryBean本身怎么办呢?spring想了个办法,context.getBean("&myFactoryBean"),在beanName前加了个&符号。这个思路是不是很好理解?当一个类特殊时,弄一个特殊的字符来标识一下,很符合if else的思维,哈哈哈哈。

    理解了FactoryBean,再理解beanFactory就简单多了,顾名思义,就是工厂,工厂是干啥的,不就是生产Spring bean的。不用解释太多,我们可以简单的理解为ApplicationContext是spring容器,ApplicationContext主要做事的就是 DefaultListableBeanFactory(一种beanFactory实现)。

    如果还是不懂,我只能劝退你了,学小马哥做java劝退师。

    相关文章

      网友评论

          本文标题:一次讲透彻 beanFactory和factoryBean

          本文链接:https://www.haomeiwen.com/subject/msoznhtx.html