码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • Spring-FactoryBean的源码——简略解析(上)


    在spring中,如果一个bean的创建过程很复杂,我们可以使用FactoryBean。
    比如像下面的情况,我定义一套webService框架。

    1. public interface WebService {
    2. void service();
    3. }
    4. public class DefaultWebService implements WebService {
    5. private String serviceName;
    6. public DefaultWebService(String serviceName) {
    7. this.serviceName = serviceName;
    8. }
    9. @Override
    10. public void service() {
    11. System.out.println(serviceName + ": current support service for you....");
    12. }
    13. }
    14. public class WebServiceWrapper implements WebService {
    15. private WebService webService;
    16. public WebServiceWrapper(WebService webService) {
    17. this.webService = webService;
    18. }
    19. @Override
    20. public void service() {
    21. System.out.println("befor service, we need do something....");
    22. webService.service();
    23. }
    24. }

    WebService接口定义服务的标准,DefaultWebService是一个默认实现,WebServiceWrapper的主要作用是在实际服务之前,做一些检查,准备等工作。
    因此当我们使用WebService,实际上是希望使用的是WebServiceWrapper。

    现在webService框架实现好了,并打包出来了,现在我需要在项目中利用使用spring注解特性去使用。

    那该怎么办呢?我可以实现spring提供的FactoryBean接口,就像下面这样:

    1. @Component
    2. public class WebServiceFactoryBean implements FactoryBean {
    3. @Override
    4. public boolean isSingleton() {
    5. return true;
    6. }
    7. @Override
    8. public Object getObject() throws Exception {
    9. return this.createWebService();
    10. }
    11. @Override
    12. public Class getObjectType() {
    13. return WebService.class;
    14. }
    15. private Object createWebService() {
    16. DefaultWebService webService = new DefaultWebService("Backend Service");
    17. // create a proxy
    18. WebServiceWrapper webServiceWrapper = new WebServiceWrapper(webService);
    19. return webServiceWrapper;
    20. }
    21. }
    1. @Component
    2. public class WebServiceFactoryBean implements FactoryBean {
    3. @Override
    4. public boolean isSingleton() {
    5. return true;
    6. }
    7. @Override
    8. public Object getObject() throws Exception {
    9. return this.createWebService();
    10. }
    11. @Override
    12. public Class getObjectType() {
    13. return WebService.class;
    14. }
    15. private Object createWebService() {
    16. DefaultWebService webService = new DefaultWebService("Backend Service");
    17. // create a proxy
    18. WebServiceWrapper webServiceWrapper = new WebServiceWrapper(webService);
    19. return webServiceWrapper;
    20. }
    21. }

    紧接着,就可以利用spring的功能去使用了

    1. @RestController
    2. public class TestController {
    3. @Autowired
    4. private WebService webService;
    5. @GetMapping(value = "webService")
    6. public void webService() {
    7. webService.service();
    8. }
    9. }

    http://localhost:8080/webService,控制台会输出:
    befor service, we need do something....
    Backend Service: current support service for you....

    通过输出我们知道,该webService,注入的应该是WebServiceWrapper。
    这里的主要疑问是,我们使用@Component托管spring的bean是WebServiceFactoryBean。但是最后在TestController中,WebServiceWrapper的相关信息,只有是怎么被注入的呢?也就是spring是怎么利用FactoryBean来实现特定bean工厂的呢?

    spring托管一个bean大概的流程是:
    bean信息扫描->实例化->依赖注入->初始化

    首先看下bean扫描阶段,在所有扫描出来的BeanDefinition中,没有发现WebServiceWrapper的相关信息,只有WebServiceFactoryBean的相关信息。所以spring不是在扫描阶段解析出WebServiceFactoryBean相关信息的。

    再看下WebServiceFactoryBean的实例化过程:

    1. public void preInstantiateSingletons() throws BeansException {
    2. // Trigger initialization of all non-lazy singleton beans...
    3. for (String beanName : beanNames) {
    4. RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    5. if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    6. if (isFactoryBean(beanName)) {
    7. Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
    8. }
    9. else {
    10. getBean(beanName);
    11. }
    12. }
    13. }
    14. }

    这段源码中,有个判断是说如果当前bean是FactoryBean,那么获取该FactoryBean本身时,beanName要加上一个特殊的前缀“&”。由于WebServiceFactoryBean是一个FactoryBean,所以此时调用的是:Object bean = getBean(FACTORY_BEAN_PREFIX + beanName),入参是:&webServiceFactoryBean
    spring中getBean会去调用doGetBean():

    1. protected T doGetBean(
    2. String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    3. throws BeansException {
    4. // Create bean instance.
    5. if (mbd.isSingleton()) {
    6. sharedInstance = getSingleton(beanName, () -> {
    7. try {
    8. return createBean(beanName, mbd, args);
    9. }
    10. catch (BeansException ex) {
    11. // Explicitly remove instance from singleton cache: It might have been put there
    12. // eagerly by the creation process, to allow for circular reference resolution.
    13. // Also remove any beans that received a temporary reference to the bean.
    14. destroySingleton(beanName);
    15. throw ex;
    16. }
    17. });
    18. beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    19. }
    20. }

    先创建一个bean实例,然后通过getObjectForBeanInstance()返回一个实例。
    这里疑问是,我明明都创建好了一个实例,我直接返回不就好了吗,为什么还要通过getObjectForBeanInstance()返回呢?下面看看该方法得描述:

    1. /**
    2. 获取给定bean实例的对象,可以是bean实例本身,也可以是FactoryBean所创建的对象。
    3. */
    4. protected Object getObjectForBeanInstance(
    5. Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    6. // 判断beanName是否以FactoryBean "&"特殊前缀开头,如果是以"&"开头
    7. // 说明当前获取的是FactoryBean本身
    8. if (BeanFactoryUtils.isFactoryDereference(name)) {
    9. if (beanInstance instanceof NullBean) {
    10. return beanInstance;
    11. }
    12. if (!(beanInstance instanceof FactoryBean)) {
    13. throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
    14. }
    15. if (mbd != null) {
    16. mbd.isFactoryBean = true;
    17. }
    18. return beanInstance;
    19. }
    20. // 如果该bean不是FactoryBean那么直接返回
    21. if (!(beanInstance instanceof FactoryBean)) {
    22. return beanInstance;
    23. }
    24. // 否则就利用FactoryBean返回该bean
    25. Object object = null;
    26. if (mbd != null) {
    27. mbd.isFactoryBean = true;
    28. }
    29. else {
    30. object = getCachedObjectForFactoryBean(beanName);
    31. }
    32. if (object == null) {
    33. // Return bean instance from factory.
    34. FactoryBean factory = (FactoryBean) beanInstance;
    35. // Caches object obtained from FactoryBean if it is a singleton.
    36. if (mbd == null && containsBeanDefinition(beanName)) {
    37. mbd = getMergedLocalBeanDefinition(beanName);
    38. }
    39. boolean synthetic = (mbd != null && mbd.isSynthetic());
    40. object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    41. }
    42. return object;
    43. }

    上面的逻辑也是很清晰了,最后看下

    1. protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
    2. Object object = doGetObjectFromFactoryBean(factory, beanName);
    3. if (shouldPostProcess) {
    4. try {
    5. object = postProcessObjectFromFactoryBean(object, beanName);
    6. }
    7. catch (Throwable ex) {
    8. throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
    9. }
    10. }
    11. return object;
    12. }
    13. private Object doGetObjectFromFactoryBean(FactoryBean factory, String beanName) throws BeanCreationException {
    14. Object object;
    15. try {
    16. if (System.getSecurityManager() != null) {
    17. AccessControlContext acc = getAccessControlContext();
    18. try {
    19. object = AccessController.doPrivileged((PrivilegedExceptionAction) factory::getObject, acc);
    20. }
    21. catch (PrivilegedActionException pae) {
    22. throw pae.getException();
    23. }
    24. }
    25. else {
    26. **object = factory.getObject();**
    27. }
    28. }
    29. catch (FactoryBeanNotInitializedException ex) {
    30. throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    31. }
    32. catch (Throwable ex) {
    33. throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    34. }
    35. // Do not accept a null value for a FactoryBean that's not fully
    36. // initialized yet: Many FactoryBeans just return null then.
    37. if (object == null) {
    38. if (isSingletonCurrentlyInCreation(beanName)) {
    39. throw new BeanCurrentlyInCreationException(
    40. beanName, "FactoryBean which is currently in creation returned null from getObject");
    41. }
    42. object = new NullBean();
    43. }
    44. return object;
    45. }
    46. 相关阅读:
      Linux下spi网卡dm9051驱动移植及(具体)驱动调试分析总结
      【原创】基于Jsp+Servlet的篮球俱乐部网站(JavaWeb毕毕业设计)
      Springboot项目中打印SQL语句日志
      idea Springboot闲置物品交易平台VS开发mysql数据库web结构java编程计算机网页源码maven项目
      java毕业设计跨境电商网站源码+lw文档+mybatis+系统+mysql数据库+调试
      zotero卸载不了占用了71GB……
      目前的一些关于机器学习的感悟
      常见编写JavaScript代码时容易出现的错误(5)
      简述人工智能,及其三大学派:符号主义、连接主义、行为主义
      数据结构——图
    47. 原文地址:https://blog.csdn.net/qq_38334677/article/details/127838904
      • 最新文章
      • 攻防演习之三天拿下官网站群
        数据安全治理学习——前期安全规划和安全管理体系建设
        企业安全 | 企业内一次钓鱼演练准备过程
        内网渗透测试 | Kerberos协议及其部分攻击手法
        0day的产生 | 不懂代码的"代码审计"
        安装scrcpy-client模块av模块异常,环境问题解决方案
        leetcode hot100【LeetCode 279. 完全平方数】java实现
        OpenWrt下安装Mosquitto
        AnatoMask论文汇总
        【AI日记】24.11.01 LangChain、openai api和github copilot
      • 热门文章
      • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
        奉劝各位学弟学妹们,该打造你的技术影响力了!
        五年了,我在 CSDN 的两个一百万。
        Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
        面试官都震惊,你这网络基础可以啊!
        你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
        心情不好的时候,用 Python 画棵樱花树送给自己吧
        通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
        13 万字 C 语言从入门到精通保姆级教程2021 年版
        10行代码集2000张美女图,Python爬虫120例,再上征途
      Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
      正则表达式工具 cron表达式工具 密码生成工具

      京公网安备 11010502049817号