扫描下方二维码或者微信搜索公众号
菜鸟飞呀飞
,便可关注微信公众号,阅读更多Spring源码分析文章html
首先须要说明的是,FactoryBean和BeanFactory虽然名字很像,可是这二者是彻底不一样的两个概念,用途上也是天差地别。BeanFactory是一个Bean工厂,在必定程度上咱们能够简单理解为它就是咱们日常所说的Spring容器(注意这里说的是简单理解为容器),它完成了Bean的建立、自动装配等过程,存储了建立完成的单例Bean。而FactoryBean经过名字看,咱们能够猜出它是Bean,但它是一个特殊的Bean,究竟有什么特殊之处呢?它的特殊之处在咱们平时开发过程当中又有什么用处呢?java
FactoryBean的特殊之处在于它能够向容器中注册两个Bean,一个是它自己,一个是FactoryBean.getObject()方法返回值所表明的Bean。先经过以下示例代码来感觉下FactoryBean的用处吧。spring
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获取到原生对象了。sql
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;
}
复制代码
如今知道了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源码。mybatis