前言

首先看一下接口定义


public interface FactoryBean<T> { /**
* 返回对象实例
*/
@Nullable
T getObject() throws Exception; /**
* 返回对象类型,
*/
@Nullable
Class<?> getObjectType(); /**
* 该工厂管理的对象是否为单例?
*/
default boolean isSingleton() {
return true;
} }

由接口定义可以看出来,实现这个接口的bean不是主要功能,getObject()创建的对象才是重点。那么在这我们就可以猜到了,可以是使用FactoryBean创建一些实例化过程比较复杂的bean

FactoryBean的注册

FactoryBean的处理逻辑在AbstractBeanFactory.doGetBean方法内


protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//获取bean名称
final String beanName = transformedBeanName(name);
Object bean;
//省略部分内容
//这里就是FactoryBean的相关处理,下面会展开说
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
//省略部分内容 return (T) bean;
}

看一下具体的逻辑,这里需要注意Spring关于bean的name有个潜规则,凡是以&开头的bean名称都默认为FactoryBean


protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // 如果beanName以工厂引用&开头
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 如果name以&开头,而beanInstance不是FactoryBean类型,则抛异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
} // 如果beanInstance不是FactoryBean类型,则直接返回beanInstance
// 或者name以&开头,也直接返回beanInstance,说明我们就想获取FactoryBean实例
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
} Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 此时beanInstance是FactoryBean类型,而name又不是以&开头; 这是我们示例工程的情况,也是最普通、用的最多的情况
// 将beanInstance强转成FactoryBean类型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// 从缓存中获取我们需要的实例对象
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 调用FactoryBean的getObject方法创建我们需要的实例对象
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
} protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
//针对单例的处理
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
//通过factory.getObject获取
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
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)) {
//将获取到的对象放到factoryBeanObjectCache单例缓存map进行存储
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
//非单例的处理,直接通过factory.getObejct获取,然后再返回给用户
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;
}
}

生成bean对象的方法:


private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException { Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();//生成对象
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
} // Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;}

Spring的实现

Spring中实现这个接口的bean有很多,但是我们最熟悉也是最重要的就是在我之前文章中提到过得ProxyFactoryBean这个bean是实现AOP技术的重点,简单回顾一下吧

public Object getObject() throws BeansException {
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}

Spring扩展点之FactoryBean接口的更多相关文章

  1. Spring扩展点之Aware接口族

    引言 Spring中提供了各种Aware接口,方便从上下文中获取当前的运行环境,比较常见的几个子接口有:BeanFactoryAware,BeanNameAware,ApplicationContex ...

  2. Spring扩展点-v5.3.9

    Spring 扩展点 **本人博客网站 **IT小神 www.itxiaoshen.com 官网地址****:https://spring.io/projects/spring-framework T ...

  3. Spring之BeanFactory和FactoryBean接口的区别

    目录 一.BeanFactory接口 二.FactoryBean接口 1.简单实现 2.增强实现 3.FactoryBean的实际使用案例 三.总结 @   Spring框架中的BeanFactory ...

  4. Spring扩展点之BeanPostProcessor

    前言 BeanPostProcessor接口是Spring中一个非常重要的接口,它的接口定义如下 public interface BeanPostProcessor { Object postPro ...

  5. Spring扩展点之BeanFactoryPostProcessor

    前言 BeanFactoryPostProcessor接口是Spring中一个非常重要的接口,它的接口定义如下 public interface BeanFactoryPostProcessor { ...

  6. spring扩展点之PropertyPlaceholderConfigurer

    原理机制讲解 https://leokongwq.github.io/2016/12/28/spring-PropertyPlaceholderConfigurer.html 使用时多个配置讲解 ht ...

  7. spring mvc 提供的几个常用的扩展点

    转载 :http://blog.csdn.net/gufachongyang02/article/details/43836105 这是spring3 mvc的核心流程图:   SpirngMVC的第 ...

  8. Spring钩子方法和钩子接口的使用详解

    本文转自:http://www.sohu.com/a/166804449_714863 前言 SpringFramework其实具有很高的扩展性,只是很少人喜欢挖掘那些扩展点,而且官方的Refrenc ...

  9. Spring中的扩展点

    Spring作为一个常用的IOC框架,在设计上预留了很多的扩展点,很多第三方开源框架,包括Spring自身也是基于这些扩展点实现的,这很好的体现了对修改关闭.对扩展开放的原则.总的来说Spring的扩 ...

随机推荐

  1. 获取 Docker 容器的 IP 地址

    docker inspect --format='{{.NetworkSettings.IPAddress}}' yourContainerIdOrContainerName

  2. 每天一道Rust-LeetCode(2019-06-06)

    每天一道Rust-LeetCode(2019-06-02) Z 字形变换 坚持每天一道题,刷题学习Rust. 原题 题目描述 示例: 输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种 ...

  3. Fishing Master (思维+贪心)

    题目网站:http://acm.hdu.edu.cn/showproblem.php?pid=6709 Problem Description Heard that eom is a fishing ...

  4. ProceedingJoinPoint获取实现类接口上的注解

    使用aspectj处理拦截aop,需要获取实现类接口上的注解 public Object around(ProceedingJoinPoint pjp) throws Throwable{ long ...

  5. Linux学习笔记-第1天(补发)- 新的开始

    本来不打算补发第一天的笔记,第一天讲的内容并不多,且大部分内容都是书本上已有的,就没有写多少笔记. 其实在学习的过程中我挺好奇其它同学各种千奇百怪的问题.想法是怎么来的,我怎么想不出来这些.或许这就是 ...

  6. [Taro] taro 缓存

    taro 缓存 Taro.clearStorageSync() 清除全部缓存 Taro.setStorage(key,value)设置缓存 Taro.getStorage(key)获取缓存 Taro. ...

  7. OAuth2.0 自我领悟

    grant_type 授权模式 authorization_code 标准的Server授权模式,授权码模式 password 基于用户密码的授权模式,用户密码模式 client_credential ...

  8. 分页条件传参bug之解决

    问题描述:以对象作为参数,对象中包含PageNum.PageSize.Condition对象等.对应的@RequestBody为如PageReqDTO reqDTO时,如果使用postman时,不在b ...

  9. 好用的低延迟vps

    ZeptoVM是一个俄罗斯的云提供商, 由于提供了黑龙江北边的机房, 所以延迟比较低 注意一定要选Khabarovsk节点, 这个节点延迟很低, 我在上海延迟大约有70ms 缺点就是比较贵, 按照年付 ...

  10. 【转】python实现Telnet操作

    # -*- coding: utf-8 -*- import logging import telnetlib import time import sys import os host_ip = ' ...