简介
在介绍实例化非懒加载的单例Bean之前,先了解一下FactoryBean
这是spring提供的一个非常重要的功能,是一个小型的工厂,可以灵活的创建出需要的Bean,在很多框架与spring整合的过程中都会用到,例如Mybatis-plus,需求是写一个Mapper注解就能成为Spring的Bean,那么这种批量动态生产Bean的功能就需要用到FactoryBean
源码解析
spring如何判断是一个FactoryBean
java
// 首先把Bean的class弄出来,并不实例化Bean
beanType = isFactoryBean -> predictBeanType-> resolveBeanClass-> doResolveBeanClass -> Class.forName
// 有了class就可以判断了
FactoryBean.class.isAssignableFrom(beanType)
其实就是使用的 Class.forName 生成了class
如何获取FactoryBean
以下是实例化非懒加载单例Bean的部分源码
java
// 通过class去判断,如果现在要实例化的Bean是一个FactoryBean,进入判断
if (isFactoryBean(beanName)) {
// 带&表示要实例化FactoryBean,不管前面有多少个&,都会只变成一个
Object bean = getBean("&" + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
// 如果是SmartFactoryBean 会有一个isEagerInit,如果isEagerInit返回true,那么会马上实例化真正的Bean,调用getObject
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) {
// SmartFactoryBean && isEagerInit返回true
getBean(beanName);
}
}
}
从上面代码可以看出,如果是一个FactoryBean,在实例化非懒加载的单例Bean的时候FactoryBean就会实例出来,如果实现的是SmartFactoryBean,那么真正的Bean也会在这个步骤实例化出来
还可以看出要获取FactoryBean,需要在beanName前面加一个&
下面就来看下这两个接口
FactoryBean接口
java
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
// 创建出来的Bean对象
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
// 默认是创建单例bean
default boolean isSingleton() {
return true;
}
}
SmartFactoryBean接口
SmartFactoryBean继承了FactoryBean,可以决定是否提前实例化对象
java
public interface SmartFactoryBean<T> extends FactoryBean<T> {
// 是否是多例
default boolean isPrototype() {
return false;
}
// 提前实例化
default boolean isEagerInit() {
return false;
}
}
使用
java
public class UserBean {
public UserBean() {
System.out.println("实例化UserBean");
}
}
@Component
public class UserFactoryBean implements FactoryBean<UserBean> {
@Override
public UserBean getObject() throws Exception {
return new UserBean();
}
@Override
public Class<?> getObjectType() {
return UserBean.class;
}
}
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
}
}
上面代码运行的时候控制台什么都不会打出,也就是并没有实例化UserBean
修改为 SmartFactoryBean,并且isEagerInit返回true
java
@Component
public class UserFactoryBean implements SmartFactoryBean<UserBean> {
@Override
public UserBean getObject() throws Exception {
return new UserBean();
}
@Override
public Class<?> getObjectType() {
return UserBean.class;
}
@Override
public boolean isEagerInit() {
return true;
}
}
控制台输出
实例化UserBean
获取Bean
既然FactoryBean可以通过getObject生成一个新的Bean,那么这个新的Bean如何获得,FactoryBean又如何获取,前面也介绍了,可以加一个&,下面来获取一下
java
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(context.getBean("userFactoryBean"));
System.out.println(context.getBean("&userFactoryBean"));
System.out.println(context.getBean("&&&userFactoryBean"));
}
}
实例化UserBean
com.shura.beans.UserBean@77556fd
com.shura.beans.UserFactoryBean@368239c8
com.shura.beans.UserFactoryBean@368239c8
为什么加多个&也可以
spring通过一个循环
java
public static String transformedBeanName(String name) {
// 没有&直接返回
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
// 循环截取掉 &
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)); // 如果还有&继续截取
return beanName;
});
}
通过上面例子我们知道,对于一个FactoryBean,其实会实例化两个Bean,一个是FactoryBean本身,一个是通过getObject方法获取出来的Bean
通过beanName获取的是getObject方法获取出来的Bean,如果beanName前面加上一个或者多个&符号,那么获取的是FactoryBean
何时调用getObject
在spring中每实例化完Bean后,都会接着这么一行代码
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
sharedInstance为实例化出来的对象,name为传入进来的名字如&userFactoryBean,beanName便是处理后的name为 userFactoryBean,
java
// 一个缓存,缓存了通过FactoryBean的getObject获得的对象,key为不带&的
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 判断是不是应该获得一个FactoryBean
if (BeanFactoryUtils.isFactoryDereference(name)) {
// 进入这表示beanInstance应该要是一个FactoryBean
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 不是的话就报错
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// 能执行到这里,那么期望beanInstance不是一个FactoryBean
if (!(beanInstance instanceof FactoryBean)) {
// 确实不是,那么就返回,通常情况我们的Bean就在这返回
return beanInstance;
}
// 后面逻辑表示,期望不是FactoryBean,是现在得到的实例是一个FactoryBean,那么应该要调用getObject获得真正对象
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
} else {
// 从缓存中拿一下
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 到这肯定确定beanInstance是一个FactoryBean,直接强转
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
// synthetic为true,表示是由硬编码创建的可以不用进行PostProcessor,其实也表示不允许改动
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
上面源码的最重要的部分就是,我希望获得的是getObject返回的bean,但是现在得到的是一个FactoryBean,那么就调用getObject返回真正的Bean
getObjectFromFactoryBean源码分析
java
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// 如果是单例会在 factoryBeanObjectCache 缓存,那么就要先从缓存中取,这里很多判断是用来保证bean只实例化一次的逻辑,可以不用看
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 执行getObject()方法,返回的object不可能为null(会返回NullBean)
object = doGetObjectFromFactoryBean(factory, beanName);
// 可能另一个线程已经创建
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
// 执行后置处理postProcess
object = postProcessObjectFromFactoryBean(object, beanName);
}
if (containsSingleton(beanName)) {
// 缓存起来
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
// 表示不是单例,那么直接调用getObject返回就行了
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
// 执行后置处理postProcess
object = postProcessObjectFromFactoryBean(object, beanName);
}
return object;
}
}
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
// 去掉一些异常判断逻辑,就是调用的getObject方法
return factory.getObject();
}
以上就是FactoryBean的所有逻辑了,最终是调用的getObject获取Bean
Mybatis-plus应用FactoryBean
例如 MapperFactoryBean,Mybaties将在后面介绍,源码先展示
java
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
private boolean addToConfig = true;
public MapperFactoryBean() {
}
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
protected void checkDaoConfig() {
super.checkDaoConfig();
Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = this.getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Exception var6) {
this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6);
throw new IllegalArgumentException(var6);
} finally {
ErrorContext.instance().reset();
}
}
}
public T getObject() throws Exception {
return this.getSqlSession().getMapper(this.mapperInterface);
}
public Class<T> getObjectType() {
return this.mapperInterface;
}
public boolean isSingleton() {
return true;
}
public void setMapperInterface(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return this.mapperInterface;
}
public void setAddToConfig(boolean addToConfig) {
this.addToConfig = addToConfig;
}
public boolean isAddToConfig() {
return this.addToConfig;
}
}
欢迎关注,学习不迷路!