区别
「BeanFactory
和FactoryBean
有哪些区别?」
BeanFactory
是一个最基础的IOC容器,提供了依赖查找,依赖注入等基础的功能FactoryBean
是创建Bean的一种方式,帮助实现复杂Bean的创建
「ApplicationContext和BeanFactory有哪些区别?」
BeanFactory
是一个最基础的IOC容器,提供了依赖查找,依赖注入等基础的功能ApplicationContext
继承了BeanFactory
,在BeanFactory
的基础上增加了企业级的功能,如AOP,资源管理(Resources)事件(Event),国际化(i18n),Environment
抽象等创建Bean的方式
常见的创建Bean的方式有如下四种
通过构造器
- 通过静态工厂方法
- 通过Bean工厂方法
通过
FactoryBean
```java @Data @ToString public class User {private Long id; private String name;
public static User createUser() {
User user = new User();
user.setId(1L);
user.setName("li");
return user;
} }
public class UserFactory {
public User createUser() {
return User.createUser();
}
}
public class UserFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return User.createUser();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
```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 -->
<bean id="user-by-constructor" class="com.javashitang.domain.User">
<property name="id" value="1"/>
<property name="name" value="li"/>
</bean>
<!-- 静态方法实例化 Bean -->
<bean id="user-by-static-method" class="com.javashitang.domain.User"
factory-method="createUser"/>
<bean id="userFactory" class="com.javashitang.factory.UserFactory"/>
<!-- Bean工厂方法实例化 Bean -->
<bean id="user-by-factory" factory-bean="userFactory" factory-method="createUser"/>
<!-- FactoryBean实例化 Bean -->
<bean id="user-by-factory-bean" class="com.javashitang.factory.UserFactoryBean"/>
</beans>
public class BeanInstantiationDemo {
public static void main(String[] args) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/bean-instantiation-context.xml");
User user1 = beanFactory.getBean("user-by-constructor", User.class);
User user2 = beanFactory.getBean("user-by-static-method", User.class);
User user3 = beanFactory.getBean("user-by-factory", User.class);
User user4 = beanFactory.getBean("user-by-factory-bean", User.class);
}
}
实现原理
在分析源码之前,先明确2个概念
「factoryBean
是配置到容器中的实现FactoryBean
接口的Bean,而subBean
是用FactoryBean
创建出来的Bean」
在Spring容器启动的过程中,会实例化非延迟的单例Bean,即调用如下方法 DefaultListableBeanFactory#preInstantiateSingletons
调用FactoryBean#getObject
的链路如下图
通过分析DefaultListableBeanFactory#preInstantiateSingletons
方法和FactoryBean#getObject
的调用链路可以分析得到
- 单例的
factoryBean
对象本身会在Spring容器启动时主动初始化。而subBean
的初始化则是在第一次从缓存中获取factoryBean
并且不为空才会触发 - 如果
factoryBean
对象实现的接口是SmartFactoryBean
且isEagerInit
方法返回true
,那么subBean
对象也会在Spring容器启动的时候主动初始化 - 如果
bean
注册的时候,beanName
对应的bean
实例是一个factoryBean
,那么通过getBean(beanName)
获取到的对象将会是subBean
对象;如果要获取工厂对象factoryBean
,需要使用getBean("&" + beanName)
- 单例的
subBean
也会缓存在Spring容器中,具体的容器是FactoryBeanRegistrySupport#factoryBeanObjectCache
,一个Map<beanName, subBean实例>
「建议大家看一下DefaultListableBeanFactory#preInstantiateSingletons
方法和FactoryBean#getObject
方法的调用链路,就能理解上面的流程了」
应用
目前在Dubbbo源码中看到了FactoryBean
的应用
「服务导出:在Dubbo中,服务提供者会被包装成ServiceBean
对象,当监听到ContextRefreshedEvent
事件时开始服务导出」
「服务调用:服务调用方会被包装成ReferenceBean
对象,ReferenceBean
实现了FactoryBean
接口和InitializingBean
接口,创建subBean
的逻辑在ReferenceBean#getObject
方法中」
「Dubbo服务引入的时机有如下2种。」
- 饿汉式:
init=true
,在Bean
生命周期的初始化阶段会调用InitializingBean#afterPropertiesSet
方法,而这个方法会调用ReferenceBean#getObject
方法,完成subBean
的创建,即ReferenceBean
实例化时完成服务引入 懒汉式:
init=false
,在ReferenceBean
对应的服务被注入到其他类中时,此时会调用AbstractApplicationContext#getBean
,获取ReferenceBean
对象,因为ReferenceBean
实现了FactoryBean
接口,所以会调用ReferenceBean#getObject
方法,完成subBean
的创建,即完成服务引入 ```java public class ReferenceBeanextends ReferenceConfig implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean { @Override public Object getObject() {
return get();
}
@Override @SuppressWarnings({“unchecked”}) public void afterPropertiesSet() throws Exception {
// 省略部分代码
if (shouldInit()) {
getObject();
}
}
} ```