1 定义bean的方式

常见的定义Bean的方式有:
通过xml的方式,例如:
<bean id="dictionaryRelMap" class="java.util.HashMap"/>
通过注解的方式,在Class上使用@Component等注解,例如
@Component
public class xxxServicer{
....
}
通过在@Configuration类下的@Bean的方式,例如
@Configuration
public class xxxConfiguration{
@Bean
public myBean myBean(){
return new myBean();
}
}
虽然这三种定义Bean的方式不一样,对应的处理细节也不一样,但是从大的逻辑上来看,都是一样。主要的流程如下图: 最关键的就是问题就是这么去找到定义Bean的方式,然后生成BeanDefinition后注册到Spring上下文中,由Spring自动创建Bean的实例。
2 BeanDefinition
BeanDefinition是一个接口,用来描述一个Bean实例,例如是SINGLETON还是PROTOTYPE,属性的值是什么,构造函数的参数是什么等。简单来说,通过一个BeanDefinition我们就可以完成一个Bean实例化。 BeanDefinition及其主要的子类:
下面简单说一下各个子类:
3 通过xml文件定义Bean
通过xml定义Bean是最早的Spring定义Bean的方式。因此,怎么把xml标签解析为BeanDefinition(), 入口是在org.springframework.beans.factory.xml.XmlBeanDefinitionReader这个类,但是实际干活的是在org.springframework.beans.factory.xml.BeanDefinitionParserDelegate。代码很多,但实际逻辑很简单,就是解析Spring定义的<bean> <property> 等标签 。
4 通过@Component等Spring支持的注解加载Bean
如果要使用@Component等注解定义Bean,一个前提条件是:有<context:component-scan/>或者@ComponentScan注解。但这2个方式还是有一点点区别:
4.1 <context:component-scan/>
由于<context:component-scan/>是一个xml标签,因此是在解析xml,生成的类org.springframework.context.annotation.ComponentScanBeanDefinitionParser,关键代码:
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
//获取base-package标签
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// 实际处理类是ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
//扫描basePackage下所有的类,如果有@Component等标签就是注册到Spring中
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
4.2 @ComponentScan
注解对应生成的类是org.springframework.context.annotation.ComponentScanAnnotationParser 其实最后实际干活的还是ClassPathBeanDefinitionScanner这个。ComponentScanAnnotationParser类的生成是伴随着@Configuration这个注解处理过程中(意思说@ComponentScan必须和@Configuration一起使用)。而处理@Configuration其实是org.springframework.context.annotation.ConfigurationClassPostProcessor。是不是感觉有点绕。
其实简单来说,在处理@Configuration的时候发现有@ComponentScan注解,就会生成ComponentScanAnnotationParser去扫描@Component注解
4.3 ClassPathBeanDefinitionScanner
上面说到了,无论注解还是标签的方式,最后都会交给ClassPathBeanDefinitionScanner这个类来处理,这个类做的就是1.扫描basePackage下所有class,如果有@Component等注解,读取@Component相关属性,生成ScannedGenericBeanDefinition,注册到Spring中。
5 通过@Bean方式
前面说了@ComponentScan是在@Configuration处理过程中的一环,既然@Bean注解也是必须和@Configuration一起使用,那么说明@Bean的处理也是在@Configuration中,其实最后是交给ConfigurationClassBeanDefinitionReader这个类来处理的,关键代码:
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
TrackedConditionEvaluator trackedConditionEvaluator) {
//如果自己是通过@Import注解定义的,那么需要把自己注册到Spring中
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//这里就是处理方法上的@Bean
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//处理@ImportResource,里面解析xml就是上面说到的解析xml的XmlBeanDefinitionReader
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
6 把BeanDefinition实例化
前面分别说了怎么把不同定义Bean的方式转换为BeanDefinition加入到Spring中去(确切来说是保持在BeanFactory的BeanDefinitionMap中),实例是在ApplicationContext最后阶段,关键代码在DefaultListableBeanFactory中
@Override
public void preInstantiateSingletons() throws BeansException {
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
}
通过getBean最后最后实例的代码,在AbstractAutowireCapableBeanFactory中
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
//处理xxAware接口
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 调用BeanPostProcessors#postProcessBeforeInitialization
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//初始化,先判断是否是InitializingBean,
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 调用BeanPostProcessors#postProcessAfterInitialization
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
从上面初始化可以看出,InitializeBean和BeanPostProcessors的调用顺序
7 总结
综上分析,Spring加载Bean其实大的思想都是一样的,先读取相关信息生成BeanDefinition,然后通过BeanDefinition初始化Bean。如果知道了上面了套路以后,就可以清楚怎么自定义Xml标签或者自定义注解向Spring中注入Bean。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# spring
# 加载bean
# bean
# 加载顺序
# 动态加载bean
# 在springboot中实现个别bean懒加载的操作
# 如何正确控制springboot中bean的加载顺序小结篇
# Spring动态加载bean后调用实现方法解析
# Spring bean 加载执行顺序实例解析
# 详解Spring简单容器中的Bean基本加载过程
# 详解Spring中Bean的加载的方法
# 解析spring加载bean流程的方法
# 是在
# 是一个
# 子类
# 说了
# 自定义
# 就可以
# 过程中
# 都是
# 加载
# 有一
# 就会
# 也不
# 就必须
# 说到
# 是从
# 很简单
# 相关信息
# 但这
# 可以看出
# 中去
相关文章:
大连网站设计制作招聘信息,大连投诉网站有哪些?
如何快速搭建自助建站会员专属系统?
香港网站服务器数量如何影响SEO优化效果?
如何构建满足综合性能需求的优质建站方案?
免费网站制作模板下载,除了易企秀之外还有什么H5平台可以制作H5长页面,最好是免费的?
盘锦网站制作公司,盘锦大洼有多少5G网站?
,怎么在广州志愿者网站注册?
视频网站制作教程,怎么样制作优酷网的小视频?
魔毅自助建站系统:模板定制与SEO优化一键生成指南
建站之星代理费用多少?最新价格详情介绍
C#如何在一个XML文件中查找并替换文本内容
已有域名和空间,如何快速搭建网站?
建站主机助手选型指南:2025年热门推荐与高效部署技巧
教学论文网站制作软件有哪些,写论文用什么软件
?
再谈Python中的字符串与字符编码(推荐)
网站制作中优化长尾关键字挖掘的技巧,建一个视频网站需要多少钱?
如何制作公司的网站链接,公司想做一个网站,一般需要花多少钱?
宝塔建站助手安装配置与建站模板使用全流程解析
深圳网站制作案例,网页的相关名词有哪些?
建站主机系统SEO优化与智能配置核心关键词操作指南
如何通过免费商城建站系统源码自定义网站主题与功能?
高端网站建设与定制开发一站式解决方案 中企动力
攀枝花网站建设,攀枝花营业执照网上怎么年审?
建站之星如何优化SEO以实现高效排名?
如何配置FTP站点权限与安全设置?
如何快速查询网址的建站时间与历史轨迹?
免费公司网站制作软件,如何申请免费主页空间做自己的网站?
如何在IIS7上新建站点并设置安全权限?
如何通过万网虚拟主机快速搭建网站?
建站之星如何开启自定义404页面避免用户流失?
如何配置IIS站点权限与局域网访问?
深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?
如何制作一个表白网站视频,关于勇敢表白的小标题?
,制作一个手机app网站要多少钱?
制作假网页,招聘网的薪资待遇,会有靠谱的吗?一面试又各种折扣?
一键网站制作软件,义乌购一件代发流程?
如何高效配置IIS服务器搭建网站?
如何高效完成自助建站业务培训?
如何通过商城自助建站源码实现零基础高效建站?
建站之星CMS五站合一模板配置与SEO优化指南
魔方云NAT建站如何实现端口转发?
如何在云主机上快速搭建多站点网站?
如何获取PHP WAP自助建站系统源码?
湖北网站制作公司有哪些,湖北清能集团官网?
宝塔面板如何快速创建新站点?
定制建站价位费用解析与套餐推荐全攻略
如何通过FTP服务器快速搭建网站?
建站10G流量真的够用吗?如何应对访问高峰?
网站制作公司排行榜,抖音怎样做个人官方网站
在线ppt制作网站有哪些,请推荐几个好的课件下载的网站?
*请认真填写需求信息,我们会在24小时内与您取得联系。