曹工说Spring Boot源码(3)-- 手动注册Bean Definition不比游戏好玩吗,我们来试一下
写在前面的话
相关背景及资源:
曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享
工程结构图:

大体思路
选择bean definition实现类,并实例化bean definition
注册bean definition
get bean查看是否work
选择bean definition实现类
这次,先说目的:我们要通过代码方式手动生成bean definition并注册到bean factory。
我的思路是这样的,既然前面两节,分析了bean definition接口中的各个方法,也算对其有了基本的了解了。但
org.springframework.beans.factory.config.BeanDefinition只是一个接口,接口是不能实例化的,也无从谈起注册了。
我们从bean definition的实现类中选一个吧:
非抽象的实现类主要有以下三个:
org.springframework.beans.factory.support.GenericBeanDefinition:幸运儿,被我们选中的,也是官方推荐的,注释里提到可以动态设置GenericBeanDefinition的parent bean definition的名称;这个呢,
org.springframework.beans.factory.support.RootBeanDefinition和org.springframework.beans.factory.support.ChildBeanDefinition也能实现bean的继承关系,但是可能这种预先定义一个bean为child/parent的方式,太死了。官方自己在
ChildBeanDefinition的注释里写到:NOTE: Since Spring 2.5, the preferred way to register bean definitions programmatically is the {@link GenericBeanDefinition} class, which allows to dynamically define parent dependencies through the* {@link GenericBeanDefinition#setParentName} method. This effectively supersedes the ChildBeanDefinition class for most use cases.
注意最后那句话,supresede这个单词我还他么不太认识,专门查了下词典,意思是
取代、代替,那这句话意思就是,大部分时候,
GenericBeanDefinition取代了ChildBeanDefinition的作用。这个下面有两个子类,之前也提过,主要是供那种通过注解方式,比如
@controller这种扫描进来的bean definition。org.springframework.beans.factory.support.ChildBeanDefinition,官方都不建议用了,直接跳过吧;org.springframework.beans.factory.support.RootBeanDefinition,在@configuration中有用,后面再讲
基于上面的思路,我们选了GenericBeanDefinition,这个类可以直接new,new了之后再通过set方法设置beanClassName等。
public class GenericBeanDefinition extends AbstractBeanDefinition {
private String parentName;
/**
* 无参构造函数,但是你看到下面那一堆set方法了吧,就是让你自己设
* Create a new GenericBeanDefinition, to be configured through its bean
* properties and configuration methods.
* @see #setBeanClass
* @see #setBeanClassName
* @see #setScope
* @see #setAutowireMode
* @see #setDependencyCheck
* @see #setConstructorArgumentValues
* @see #setPropertyValues
*/
public GenericBeanDefinition() {
super();
}
}
还有一个方式是,我们看看框架里怎么用的,经过我一番搜索,

发现框架里,主要使用了org.springframework.beans.factory.support.BeanDefinitionBuilder和
org.springframework.beans.factory.support.BeanDefinitionReaderUtils,而且,框架里,还是前者用的多,也比较方便(后面有示例代码)。
注册bean definition
然后,知道怎么构造GenericBeanDefinition了,那么要怎么注册呢,这个也简单,我们看看beanFactory,
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable
不只实现了ConfigurableListableBeanFactory,还实现了BeanDefinitionRegistry。
public interface BeanDefinitionRegistry extends AliasRegistry {
/**
* 注册beanDefinition,要自己指定beanName
* Register a new bean definition with this registry.
* Must support RootBeanDefinition and ChildBeanDefinition.
* @param beanName the name of the bean instance to register
* @param beanDefinition definition of the bean instance to register
* @throws BeanDefinitionStoreException if the BeanDefinition is invalid
* or if there is already a BeanDefinition for the specified bean name
* (and we are not allowed to override it)
* @see RootBeanDefinition
* @see ChildBeanDefinition
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
...
}
所以,我们只要调用org.springframework.beans.factory.support.DefaultListableBeanFactory的注册方法即可。
这里说下beanNameGenerator,一开始我用的org.springframework.beans.factory.support.DefaultBeanNameGenerator,结果生成的bean的名称是这样的:
org.springframework.simple.TestService#0,这和我们平时使用autowired方式,生成的beanName不一样啊,不习惯。于是改成了org.springframework.context.annotation.AnnotationBeanNameGenerator,就对了!
如何表达bean间依赖
这里先介绍两种方式,分别是构造器注入和property注入。对了,先不要和我提什么autowired哈,那个是自动,这个呢,手动。也许,后面你会更懂autowired,也更懂自动。
构造器注入
核心代码:
@ToString
public class TestControllerByConstructor {
TestService testService;
/**
* 基本类型依赖
*/
private String name;
public TestControllerByConstructor(TestService testService, String name) {
this.testService = testService;
this.name = name;
}
public TestService getTestService() {
return testService;
}
public String getName() {
return name;
}
}
package org.springframework.simple;
import lombok.ToString;
@ToString
public class TestService implements ITestService{
}
/**
* 2. 构造bean definition,并在bean definition中表达bean之间的依赖关系
*/
GenericBeanDefinition iTestServiceBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder
.genericBeanDefinition(TestService.class).getBeanDefinition();
log.info("iTestServiceBeanDefinition:{}",iTestServiceBeanDefinition);
GenericBeanDefinition iTestControllerBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder
.genericBeanDefinition(TestControllerByConstructor.class)
// 这里,看这里,这里在表达依赖了
.addConstructorArgReference("testService")
.addConstructorArgValue("wire by constructor")
.getBeanDefinition();
完整代码:
package org.springframework.simple.byconstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.*;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.simple.ITestService;
import org.springframework.simple.TestService;
import org.springframework.util.Assert;
@Slf4j
public class ManualRegisterBeanDefinitionDemoByConstructor {
public static void main(String[] args) {
wireDependencyByConstructor();
}
/**
* 通过构造器的方式来注入依赖
*/
private static void wireDependencyByConstructor() {
/**
* 1:生成bean factory
*/
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
/**
* 2. 构造bean definition,并在bean definition中表达bean之间的依赖关系
*/
GenericBeanDefinition iTestServiceBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder
.genericBeanDefinition(TestService.class).getBeanDefinition();
log.info("iTestServiceBeanDefinition:{}",iTestServiceBeanDefinition);
GenericBeanDefinition iTestControllerBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder
.genericBeanDefinition(TestControllerByConstructor.class)
.addConstructorArgReference("testService")
.addConstructorArgValue("wire by constructor")
.getBeanDefinition();
/**
* 3. 注册bean definition
*/
// DefaultBeanNameGenerator generator = new DefaultBeanNameGenerator();
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
String beanNameForTestService = generator.generateBeanName(iTestServiceBeanDefinition, factory);
factory.registerBeanDefinition(beanNameForTestService, iTestServiceBeanDefinition);
String beanNameForTestController = generator.generateBeanName(iTestControllerBeanDefinition, factory);
factory.registerBeanDefinition(beanNameForTestController, TestControllerBeanDefinition);
/**
* 4. 获取bean
*/
TestControllerByConstructor bean = factory.getBean(TestControllerByConstructor.class);
log.info("TestControllerByConstructor:{}",bean);
ITestService testService = factory.getBean(ITestService.class);
log.info("testService bean:{}",testService);
Assert.isTrue(bean.getTestService() == testService);
}
}
property注入
原理类似,核心代码不同之处如下:
GenericBeanDefinition iTestControllerBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder
.genericBeanDefinition(TestControllerWireByProperty.class)
// 这里是调用的property相关方法
.addPropertyReference("t","testService")
.addPropertyValue("name","just test")
.getBeanDefinition();
总结
今天就到这里,有问题请指出哈,欢迎大家和我一起阅读spring boot源码。
源码地址:
曹工说Spring Boot源码(3)-- 手动注册Bean Definition不比游戏好玩吗,我们来试一下的更多相关文章
- 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解
写在前面的话 相关背景及资源: 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享 工程代码地址 思维导图地址 工程结构图: 正 ...
- 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享
写在前面的话&&About me 网上写spring的文章多如牛毛,为什么还要写呢,因为,很简单,那是人家写的:网上都鼓励你不要造轮子,为什么你还要造呢,因为,那不是你造的. 我不是要 ...
- 曹工说Spring Boot源码(5)-- 怎么从properties文件读取bean
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码(6)-- Spring怎么从xml文件里解析bean的
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码(7)-- Spring解析xml文件,到底从中得到了什么(上)
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码(8)-- Spring解析xml文件,到底从中得到了什么(util命名空间)
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码(9)-- Spring解析xml文件,到底从中得到了什么(context命名空间上)
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- # 曹工说Spring Boot源码(10)-- Spring解析xml文件,到底从中得到了什么(context:annotation-config 解析)
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码(11)-- context:component-scan,你真的会用吗(这次来说说它的奇技淫巧)
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码(12)-- Spring解析xml文件,到底从中得到了什么(context:component-scan完整解析)
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
随机推荐
- linux命令--文件目录操作命令
一.命令的基本格式 1.命令提示符 [root@love2 ~]# []:这是提示符的分隔符号,没有特殊含义. root:显示的是当前的登录用户. @:分隔符号,没有特殊含义.love2:当前系统的主 ...
- 解构ffmpeg(二)
通过比较DirectShow和ffmpeg两者的FilterGraph,分析ffmpeg的FilterGraph运作. 首先FilterGraph是一个图,图由点和边构成.在FilterGraph中的 ...
- Hook原理--逆向开发
今天我们将继续讲解逆向开发工程另一个重要内容--Hook原理讲解.Hook,可以中文译为“挂钩”或者“钩子”,逆向开发中改变程序运行的一种技术.按照如下过程进行讲解 Hook概述 Hook技术方式 f ...
- SpringBoot学习(一)—— idea 快速搭建 Spring boot 框架
简介 优点 Spring Boot 可以以jar包的形式独立运行,运行一个Spring Boot 项目只需要通过 java -jar xx.jar 来运行. Spring Boot 可以选择内嵌Tom ...
- vue项目页面切换到默认显示顶部
页面切换到默认显示顶部 方法一 使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样. vue-router 能做到,而且更好,它让你可以自定义路由切换时页 ...
- 🙈羞,Spring Bean 初始化/销毁竟然有这么多姿势
文章来源:http://1t.click/bfHN 一.前言 日常开发过程有时需要在应用启动之后加载某些资源,或者在应用关闭之前释放资源.Spring 框架提供相关功能,围绕 Spring Bean ...
- 协议分层(因特网5层模型)及7层OSI参考模型
目录 因特网5层模型及7层OSI参考模型 分层的体系结构: 应用层(软件) 运输层(软件) 网络层(硬件软件混合) 链路层(硬件) 物理层(硬件) OSI模型 表示层 会话层 封装 因特网5层模型及7 ...
- Linux I/O复用 —— epoll 部分源码剖析
epoll 相关的系统调用有以下三个,这里简述下当调用对应函数后,内核的具体实现 epoll_creat( ) 在内核注册文件系统 eventpollfs,挂载此文件系统 (linux一切皆文件,便于 ...
- CNCF官方大使张磊:什么是云原生?
作者|张磊 阿里云容器平台高级技术专家,CNCF 官方大使 编者说: 从 2015 年 Google 牵头成立 CNCF 以来,云原生技术开始进入公众的视线并取得快速的发展,到 2018 年包括 Go ...
- PHP安装扩展补充说明
上一篇文章中用到了,php的sodium扩展,那么如何安装PHP扩展呢?基于我之前踩过的一些坑,大致整理了几种安装php扩展的方法.已安装sodium为例 1.先做点准备工作,安装sodium依赖 r ...