前言
理解FactoryBean是非常非常有必要的,因为在Spring中FactoryBean最为典型的一个应用就是用来创建AOP的代理对象,不仅如此,而且对理解Mybatis核心源码也非常有帮助!如果甘愿crud,做个快乐的码农,那我就哦豁豁豁豁豁豁豁豁豁豁豁豁豁豁…

文章目录

  • 1、BeanFactory
    • 1.1 BeanFactory 源码
    • 1.2、BeanFactory 使用场景
  • 2、FactoryBean
    • 2.1、为什么会有FactoryBean?
    • 2.2 、FactoryBean 源码
    • 2.3 、FactoryBean代码示例
    • 2.4 FactoryBean使用场景

BeanFactory和FactoryBean同样都是spring的接口,名字看起来很相似,但是我觉得要混淆还是很困难的!尽管Spring揭秘一书的作者都喜欢写上这一句。

请不要混淆BeanFactory 和 FactoryBean。

1、BeanFactory

BeanFactory,以Factory结尾,表示它是一个工厂(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是工厂的顶层接口,也是IOC容器的核心接口,因此BeanFactory中定义了管理Bean的通用方法,如 getBeancontainsBean 等,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是个接口,并不是IOC容器的具体实现,所以Spring容器给出了很多种实现,如 DefaultListableBeanFactoryXmlBeanFactoryApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。

1.1 BeanFactory 源码

public interface BeanFactory {//对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,//如果需要得到工厂本身,需要转义String FACTORY_BEAN_PREFIX = "&";//根据bean的名字,获取在IOC容器中得到bean实例Object getBean(String name) throws BeansException;//根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;Object getBean(String name, Object... args) throws BeansException;<T> T getBean(Class<T> requiredType) throws BeansException;<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;//提供对bean的检索,看看是否在IOC容器有这个名字的beanboolean containsBean(String name);//根据bean名字得到bean实例,并同时判断这个bean是不是单例boolean isSingleton(String name) throws NoSuchBeanDefinitionException;boolean isPrototype(String name) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;//得到bean实例的Class类型@NullableClass<?> getType(String name) throws NoSuchBeanDefinitionException;//得到bean的别名,如果根据别名检索,那么其原名也会被检索出来String[] getAliases(String name);
}

1.2、BeanFactory 使用场景

1、从Ioc容器中获取Bean(byName or byType)
2、检索Ioc容器中是否包含指定的Bean
3、判断Bean是否为单例

2、FactoryBean

首先FactoryBean是一个Bean,但又不仅仅是一个Bean,这样听起来矛盾,但为啥又这样说呢?其实在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个FactoryBean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似

2.1、为什么会有FactoryBean?

一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean。至于为什么会有FactoryBean?原因有两个:

1、
在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。

2、
由于第三方库不能直接注册到spring容器,于是可以实现org.springframework.bean.factory.FactoryBean接口,然后给出自己对象的实例化代码即可。

2.2 、FactoryBean 源码

public interface FactoryBean<T> {//从工厂中获取bean【这个方法是FactoryBean的核心】@NullableT getObject() throws Exception;//获取Bean工厂创建的对象的类型【注意这个方法主要作用是:该方法返回的类型是在ioc容器中getbean所匹配的类型】@NullableClass<?> getObjectType();//Bean工厂创建的对象是否是单例模式default boolean isSingleton() {return true;}
}

方法介绍:
1、
getobject ()方法会返回该FactoryBean “生产” 的对象实例,我们需要实现该方法以给出自己的对象实例化逻辑;
2、
getobjectTYype ()方法仅返回getobject ()方法所返回的对象的类型,如果预先无法确定,则返回null; 特别注意这个方法主要作用是:该方法返回的类型是在ioc容器中getbean所匹配的类型,也就是说ioc中有很多类型的bean,要找到这个bean就是通过getobjectTYype ()方法的返回值类型!好吧,我举个例子

public class XXX implements FactoryBean {@Overridepublic Object getObject() throws Exception {return new YYY;}       @Overridepublic Class<?> getObjectType() {  //注意这个方法主要作用是:该方法返回的类型是在ioc容器中getbean所匹配的类型return AAA.class;}
}那么要想在ioc中找到XXX这个类的bean(实际上是YYY) ,在getbean的时候写法如下public class Demo1 {public static void main(String[] args) {AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);annotationConfigApplicationContext.getBean( AAA.class ); // 【注意这里是AAA.class】}
}

3、
isSingleton ()方法返回结果用于表明,工厂方法(getobject ())所“生产”的对象是否要以singleton形式存在于容器中。如果以singleton形式存在,则返回true,否则返回false;

FactoryBean表现的是一个工厂的职责。 即一个Bean A如果实现了FactoryBean接口,那么A就变成了一个工厂,根据A的名称获取到的实际上是工厂调用getObject()返回的对象,而不是A本身,如果要获取工厂A自身的实例,那么需要在名称前面加上’&'符号。 通俗点表达就是

getObject(’ name ‘)返回工厂中的实例
getObject(’ &name ')返回工厂本身的实例

通常情况下,bean 无须自己实现工厂模式,Spring 容器担任了工厂的 角色;但少数情况下,容器中的 bean 本身就是工厂,作用是产生其他 bean 实例。由工厂 bean 产生的其他 bean 实例,不再由 Spring 容器产生,因此与普通 bean 的配置不同,不再需要提供 class 元素。

2.3 、FactoryBean代码示例

1、创建一个Appconfig类,扫描com.yichun下的所有子包

@Configuration
@ComponentScan("com.yichun")
public class Appconfig {}

2、创建一个StudentBean类并实现FactoryBean,并重写其两个方法

@Component("studentBean")
public class StudentBean implements FactoryBean {@Overridepublic Object getObject() throws Exception {return new TeacherBean();}@Overridepublic Class<?> getObjectType() {  //注意这个方法主要作用是:该方法返回的类型是在ioc容器中getbean所匹配的类型return StudentBean.class;}//一个学生学习方法public void study(){System.out.println("学生学习。。。");}
}

3、再创建一个TeacherBean类

public class TeacherBean {public void teacher(){System.out.println("老师教书。。。。");}
}

4、测试StudentBean类型

public class Demo1 {public static void main(String[] args) {AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);StudentBean studentBean = (StudentBean)annotationConfigApplicationContext.getBean("studentBean");studentBean.study();}
}


加上“&”符号

public class Demo1 {public static void main(String[] args) {AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);//加上了“&”符号StudentBean studentBean = (StudentBean)annotationConfigApplicationContext.getBean("&studentBean");studentBean.study();}
}


运行成功

5、测试一下teacherBean类型

public class Demo1 {public static void main(String[] args) {AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);    TeacherBean teacherBean = (TeacherBean) annotationConfigApplicationContext.getBean("studentBean");       teacherBean.teacher();}
}

运行成功

2.4 FactoryBean使用场景

使用场景一:
FactoryBean在Spring中最为典型的一个应用就是用来创建AOP的代理对象。
我们知道AOP实际上是Spring在运行时创建了一个代理对象,也就是说这个对象,是我们在运行时创建的,而不是一开始就定义好的,这很符合工厂方法模式。更形象地说,AOP代理对象通过Java的反射机制,在运行时创建了一个代理对象,在代理对象的目标方法中根据业务要求织入了相应的方法。这个对象在Spring中就是——ProxyFactoryBean

所以,FactoryBean为我们实例化Bean提供了一个更为灵活的方式,我们可以通过FactoryBean创建出更为复杂的Bean实例。

当然在spring中,Spring容器内部许多地方了使用FactoryBean。下面是一些比较常见的FactoryBean实现:

JndiobjectFactoryBean
LocalSessionFactoryBean
SqlMapClientFactoryBean
ProxyFactoryBean
TransactionProxyFactoryBean

使用场景二:
Mybatis中的SqlSessionFactoryBean

<bean id="tradeSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="trade" /><property name="mapperLocations" value="classpath*:mapper/trade/*Mapper.xml" /><property name="configLocation" value="classpath:mybatis-config.xml" /><property name="typeAliasesPackage" value="com.bytebeats.mybatis3.domain.trade" /></bean>

package org.mybatis.spring;public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);......
}

另外提一下,阿里开源的分布式服务框架 Dubbo中的Consumer 也使用到了FactoryBean,

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"><!-- 当前应用信息配置 --><dubbo:application name="demo-consumer" /><!-- 暴露服务协议配置 --><dubbo:protocol name="dubbo" port="20813" />    <!-- 暴露服务配置 --><dubbo:reference id="demoService" interface="com.alibaba.dubbo.config.spring.api.DemoService"  /></beans>

<dubbo:reference 对应的Bean是com.alibaba.dubbo.config.spring.ReferenceBean 类。

使用场景三:
Hibernate中的SessionFactoryBean。这里就不再概述。

最后本文难免会有不正之处,欢迎指正评判!欢迎指正评判!欢迎指正评判!!!

参考:
《Spring揭秘》王福强
https://zhuanlan.zhihu.com/p/87382038
https://www.cnblogs.com/aspirant/p/9082858.html

浅谈Spring中的BeanFactory与FactoryBean相关推荐

  1. 浅谈spring中的设计模式(转)

    工厂模式 BeanFactory,从xml或者注解加载BeanDefinition,然后实例化对象,其中AbstractAutowiredCapableBeanFactory实现了主要的逻辑 单例模式 ...

  2. 浅谈Spring中JDK动态代理与CGLIB动态代理

    前言 Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式 ...

  3. 浅谈 Spring IOC和AOP

    浅谈 Spring IOC和AOP IOC 控制反转 以前创建对象的主动权和时机是由于自己把握的,现在将这种权利转移到Spring容器中,并且根据配置文件去创建对象管理对象 ioc的注入方式有三种:构 ...

  4. 浅谈:Spring Boot原理分析,切换内置web服务器,SpringBoot监听项目(使用springboot-admin),将springboot的项目打成war包

    浅谈:Spring Boot原理分析(更多细节解释在代码注释中) 通过@EnableAutoConfiguration注解加载Springboot内置的自动初始化类(加载什么类是配置在spring.f ...

  5. 浅谈Spring IOC和DI及Spring工厂类

    浅谈Spring IOC和DI及Spring的工厂类 文章目录 浅谈Spring IOC和DI及Spring的工厂类 一. IOC 1.什么是IOC 2.为什么使用IOC 传统开发模式的弊端 3. 使 ...

  6. 浅谈 Spring IOC

    浅谈 Spring IOC 什么是IOC 理解 IOC 和 DI Spring IOC 相关操作个人总结 什么是IOC Ioc-Inversion of Control,即"控制反转&quo ...

  7. 由openSession、getCurrentSession和HibernateDaoSupport浅谈Spring对事物的支持

    由openSession.getCurrentSession和HibernateDaoSupport浅谈Spring对事物的支持 Spring和Hibernate的集成的一个要点就是对事务的支持,op ...

  8. 浅谈Spring定时任务

    浅谈Spring定时任务 三种定时任务基于原理 多定时任务并发配置 动态定时任务 定时任务Demo 三种定时任务基于原理 SpringBoot配置定时任务主要有Spring Schedule.JDK自 ...

  9. 浅谈Spring IOC的理解

    浅谈Spring IOC的理解 学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊 ...

最新文章

  1. 国内IDC即将迎来快速增长时期
  2. 使用lucce分词怎么_真小叮当深度学习:自然语言处理(三)文本处理之分词专题...
  3. 【OpenCV入门指南】第五篇 轮廓检测 上
  4. [armv9]-ARMV8/ARMV9安全架构介绍(ARMv9 CCA)
  5. java集合租车_Java入门第二季 租车系统
  6. 【转帖】Reporting Service rdl报表,在aspx页面显示一张完整的RDL报表
  7. Linux命令之tar等
  8. DotNetCore中异步编程的实用演练
  9. Spring 字符编码过滤
  10. 网络管理与维护作业6
  11. ecshop /goods.php SQL Injection Vul
  12. 电脑c盘空间不足怎么清理_C盘空间不足怎么办?如何给C盘扩容?
  13. 助力公共事业服务,RPA大显身手
  14. python圣诞节_圣诞节,用Python给自己加顶“圣诞帽”
  15. C++学习(二八一)Gradle下载目录里的随机码是什么
  16. 2个Python学习网站制作教程
  17. Dynamics 365 安装Report Authoring Extension时,提示重新启动的问题
  18. ZZULIOJ1081-1090
  19. ios服务器需要开启ipv6的支持,关于ios苹果APP审核 支持IPv6的问题解答
  20. influx db高可用部署方案

热门文章

  1. 基于Vue 表格行上下移动
  2. HTML实例网页代码, 本实例适合于初学HTML的同学 (个人博客网站)
  3. 运维教程之Microsoft SQL server 2008 R2图文+视频安装
  4. 基于web的微信公众号程序自动化测试-java
  5. 计算机主机突然出响声,电脑主机箱声音突然很大如何解决
  6. Python绘制股票日K图(九)给折线图加标签
  7. 「黑马程序员」微信小程序最新接口
  8. PCIe系列第八讲、MSI和MSI-X中断机制
  9. 给机械专业大学生的回信
  10. 检测软键盘的弹起与隐藏【绝对经典,好用】