spring中factorybean和beanfactory区别
在Spring中存在着BeanFactory和FactoryBean两个接口,很多人容易搞错甚至不知道他们之间的区别。实际上它们的区别特别大,它们俩都不是同一个东西。BeanFactory就是Bean工厂,就是Spring中底层的IOC容器。而FactoryBean是干嘛的呢?
为什么要提供该接口
一般情况下,Spring是通过反射机制利用Bean的Class属性指定实现类来实例化Class。但是在某些情况下,实例化Bean过程比较复杂,传统的方式就不太适合用来实例化Bean。所以Spring提供了FactoryBean这么一个接口,可以通过该接口实现定制实例化Bean的逻辑。接口定义如下:
public interface FactoryBean<T> { String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; /** * 返回工厂管理的实例实例对象 */ T getObject() throws Exception; /** * 返回FactoryBean创建的实例的类型 */ Class<?> getObjectType(); /** * 是否是单例 */ default boolean isSingleton() { return true; } }
该定义为Spring-5.2.12.RELEASE版本中的内容。一共就三个接口,作用分别是返回实例对象、类型、是否是单例。
如何使用上面已经介绍FactoryBean的作用,下面示例展示如何使用。
public interface FactoryBean<T> { String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; /** * 返回工厂管理的实例实例对象 public class FactoryBeanDemo { public static void main(String[] args) { //创建IOC容器 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); //读取配置文件 BeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions("spring-factory-bean.xml"); //获取UserService实例 UserService us1 = (UserService) beanFactory.getBean("userService"); System.out.println(us1); //获取UserServiceFactoryBean实例 UserServiceFactoryBean usfb = (UserServiceFactoryBean) beanFactory.getBean("&userService"); System.out.println(usfb); } } class UserServiceFactoryBean implements FactoryBean<UserService>{ public UserServiceFactoryBean() { System.out.println("调用无参构造函数创建UserServiceFactoryBean:"+this); } @Override public UserService getObject() throws Exception { return new UserService(); } @Override public Class<?> getObjectType() { return UserService.class; } } class UserService{ public UserService() { System.out.println("调用无参构造函数创建UserService:"+this); } }
spring-factory-bean.xml配置文件内容如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userService" class="com.buydeem.factorybean.UserServiceFactoryBean"/> </beans>
运行后的打印结果如下:
调用无参构造函数创建UserServiceFactoryBean:com.buydeem.factorybean.UserServiceFactoryBean@627551fb
调用无参构造函数创建UserService:com.buydeem.factorybean.UserService@614ddd49
com.buydeem.factorybean.UserService@614ddd49
com.buydeem.factorybean.UserServiceFactoryBean@627551fb
打印的结果你一定很意外,因为我们的配置文件中我们注册的userService它的class为com.buydeem.factorybean.UserServiceFactoryBean,而我们通过getBean("userService")得到的却是UserService类型,而不是UserServiceBean类型。
因为FactoryBean是一个特殊的Bean。我们自定义的UserServiceFactoryBean实现了FactoryBean接口,该类型会在容器中先后注册两个Bean,其中第一个先创建的为UserServiceFactoryBean,放在一级缓存里面,第二个是只有手动context.getBean的时候,才会通过调用第一个UserServiceFactoryBean实例的getObject()方法返回该对象实例,然后放到缓存里面,以便下次调用就不用再创建了。而且我们通过BeanName获取的默认为UserService而不是UserServiceFactoryBean,如果想要获取UserServiceFactoryBean,只需要在名字前添加&即可。
在使用Mybatis时我们通常需要创建SqlSessionFactory实例,该实例创建过程较为复杂。而在使用Mybatis与Spring整合时,我们可以使用SqlSessionFactoryBean来创建SqlSessionFactory。还有使用factorybean实现动态代理的aop技术有ProxyFactoryBean(代理工厂对象)和TranstractionProxyFactoryBean(事务代理工厂对象)
spring中相关源码
AbstractBeanFactory中doGetBean源码如下:
doGetBean方法内容较多,我只截取了一段。该段代码为创建单例Bean时的主要代码,它首先创建sharedInstance这个实例Bean,接着调用getObjectForBeanInstance获取真正的实例。运行我们之前的示例代码,打断点调试可以知道,sharedInstance实际上就是UserServiceFactoryBean实例,而bean才是UserService实例。
getObjectFromFactoryBean该方法的核心就是判断之前创建的sharedInstance是不是FactoryBean,如果是则获取真正的bean。
本文转自:https://www.jianshu.com/p/cbf92e66f61e
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?