扫描下方二维码或者微信搜索公众号
菜鸟飞呀飞
,即可关注微信公众号,阅读更多Spring源码分析文章
首先需要说明的是,FactoryBean和BeanFactory虽然名字很像,但是这两者是完全不同的两个概念,用途上也是天差地别。BeanFactory是一个Bean工厂,在一定程度上我们可以简单理解为它就是我们平常所说的Spring容器(注意这里说的是简单理解为容器),它完成了Bean的创建、自动装配等过程,存储了创建完成的单例Bean。而FactoryBean通过名字看,我们可以猜出它是Bean,但它是一个特殊的Bean,究竟有什么特殊之处呢?它的特殊之处在我们平时开发过程中又有什么用处呢?
FactoryBean的特殊之处在于它可以向容器中注册两个Bean,一个是它本身,一个是FactoryBean.getObject()方法返回值所代表的Bean。先通过如下示例代码来感受下FactoryBean的用处吧。
package com.tiantang.study.component;
import com.tiantang.study.service.UserService;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
@Component
public class CustomerFactoryBean implements FactoryBean<UserService> {
@Override
public UserService getObject() throws Exception {
return new UserService();
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
}
package com.tiantang.study.service;
public class UserService {
public UserService(){
System.out.println("userService construct");
}
}
com.tiantang.study.component
package com.tiantang.study.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.tiantang.study.component")
public class AppConfig {
}
public class MainApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println("容器启动完成");
UserService userService = applicationContext.getBean(UserService.class);
System.out.println(userService);
Object customerFactoryBean = applicationContext.getBean("customerFactoryBean");
System.out.println(customerFactoryBean);
}
}
在进行源码分析之前,我们可以先看下这两个问题:
com.tiantang.study.component
这个包下的类,按照我们的常规理解,这个时候应该只会有CustomerFactoryBean这个类被放进Spring容器中了,UserService并没有被扫描。而我们在测试时却可以通过applicationContext.getBean(UserService.class)
从容器中获取到Bean,为什么?CustomerFactoryBean
类的单例对象在容器中的beanName是customerFactoryBean。所以这个时候我们调用方法getBean(beanName)通过beanName去获取Bean,这个时候理论上应该返回的是CustomerFactoryBean类的单例对象。然而,我们将结果打印出来,却发现,这个对象的hashCode竟然和userService对象的hashCode一模一样,这说明这两个对象是同一个对象,为什么会出现这种情况呢?为什么不是CustomerFactoryBean类的实例对象呢?以上3个问题的答案可以用一个答案解决,那就是FactoryBean是一个特殊的Bean。我们自定义的CustomerFactoryBean实现了FactoryBean接口,所以当CustomerFactoryBean被扫描进Spring容器时,实际上它向容器中注册了两个bean,一个是CustomerFactoryBean类的单例对象;另外一个就是getObject()方法返回的对象,在demo中,我们重写的getObject()方法中,我们通过new UserService()返回了一个UserService的实例对象,所以我们从容器中能获取到UserService的实例对象。如果我们想通过beanName去获取CustomerFactoryBean的单例对象,需要在beanName前面添加一个
&
符号,如下代码,这样就能根据beanName获取到原生对象了。
public class MainApplication {
public static void main(String[] args) {
CustomerFactoryBean rawBean = (CustomerFactoryBean) applicationContext.getBean("&customerFactoryBean");
System.out.println(rawBean);
}
}
通过上面的示例代码,我们知道了FactoryBean的作用,也知道该如何使用FactoryBean,那么接下来我们就通过源码来看看FactoryBean的工作原理。
public void preInstantiateSingletons() throws BeansException {
// 从容器中获取到所有的beanName
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 在此处会根据beanName判断bean是不是一个FactoryBean,实现了FactoryBean接口的bean,会返回true
// 此时当beanName为customerFactoryBean时,会返回true,会进入到if语句中
if (isFactoryBean(beanName)) {
// 然后通过getBean()方法去获取或者创建单例对象
// 注意:在此处为beanName拼接了一个前缀:FACTORY_BEAN_PREFIX
// FACTORY_BEAN_PREFIX是一个常量字符串,即:&
// 所以在此时容器启动阶段,对于customerFactoryBean,应该是:getBean("&customerFactoryBean")
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// 下面这一段逻辑,是判断是否需要在容器启动阶段,就去实例化getObject()返回的对象,即是否调用FactoryBean的getObject()方法
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
}
}
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
if (mbd.isSingleton()) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
}
return (T) bean;
}
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
}
// 如果bean不是factoryBean,那么会直接返回Bean
// 或者bean是factoryBean但name是以&特殊符号开头的,此时表示要获取FactoryBean的原生对象。
// 例如:如果name = &customerFactoryBean,那么此时会返回CustomerFactoryBean类型的bean
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 如果是FactoryBean,那么先从cache中获取,如果缓存不存在,则会去调用FactoryBean的getObject()方法。
Object object = null;
if (mbd == null) {
// 从缓存中获取。什么时候放入缓存的呢?在第一次调用getObject()方法时,会将返回值放入到缓存。
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 在getObjectFromFactoryBean()方法中最终会调用到getObject()方法
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 如果BeanFactory的isSingleton()方法返回值是true,表示getObject()返回值对象是单例的
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// 再一次判断缓存中是否存在。(双重检测机制,和平时写线程安全的代码类似)
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 在doGetObjectFromFactoryBean()中才是真正调用getObject()方法
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
// 下面是进行后置处理,和普通的bean的后置处理没有任何区别
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
// 放入到缓存中
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
// 非单例
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 调用getObject()方法
object = factory.getObject();
}
return object;
}
Spring的代码实在是写的太好了,每个方法几乎都复用性比较高,这就导致了总是方法中套方法,层级比较深,所以最后以一张流程图总结下FactoryBean的创建流程。
看完这一段的源码分析,这个时候能理解demo中打印结果了吧。
现在知道了FactoryBean的原理,那么在平时工作中,你见过哪些FactoryBean的使用场景。如果没有留意过的话,笔者在这里就拿Spring整合Mybatis的原理来举例吧。
mybatis-spring
,然后是配置数据源。最后还需要一个配置,如果你是通过XML配置的话,还需要如下配置:<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
// ...省略其他代码
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
}
public void afterPropertiesSet() throws Exception {
// buildSqlSessionFactory()方法会根据mybatis的配置进行初始化。
this.sqlSessionFactory = buildSqlSessionFactory();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {
}
getSqlSession().getMapper(this.mapperInterface)
返回了一个对象。这一行代码最终会调用到MapperProxyFactory的newInstance()方法,为每一个Mapper创建一个代理对象。public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
@Override
public Class<T> getObjectType() {
return this.mapperInterface;
}
@Override
public boolean isSingleton() {
// 返回true是为了让Mapper接口是一个单例的
return true;
}
}
public class MapperProxyFactory<T> {
protected T newInstance(MapperProxy<T> mapperProxy) {
// JDK动态代理
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
在SpringBoot中整合MyBatis的原理是一样的,虽然使用的是mybatis-spring-boot-starter这个依赖,但最终的整合原理和Spring是一模一样的。SpringBoot的最主要的功能是自动配置,和其他框架的整合原理与Spring相比几乎没变。
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnBean({DataSource.class})
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class})
public class MybatisAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
// 省略部分代码
return factory.getObject();
}
}
扫描下方二维码即可关注微信公众号菜鸟飞呀飞,一起阅读更多Spring源码。