Spring源码-AbastractApplicationContext.refresh()简单流程

Spring源码-AbastractApplicationContext.refresh()

1.prepareRefresh()

刷新前的准备

  1. 设置容器的启动时间
  2. 设置活跃状态为true
  3. 设置关闭状态为false
  4. *getEnvironment()*获取环境对象,验证所需属性文件是否都已放入环境中
  5. 准备监听器和事件的集合对象 ,默认为空的集合

2.obtainFreshBeanFactory()

  1. 创建容器对象:ConfigurableListableBeanFactory
  2. 加载xml配置文件的属性值到当前工厂中,最重要的是BeanDefinition

2.1.refreshBeanFactory()

创建容器对象:DefaultListableBeanFactory并设置一些BeanDefinition

//创建DefaultListableBeanFactory对象
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖
customizeBeanFactory(beanFactory);
//XML文件读取及解析
loadBeanDefinitions(beanFactory);

在这里插入图片描述

ListableBeanFactory:实现此接口的bean factories可以枚举它们的所有的bean instances

HierarchicalBeanFactory:

  1. 所有要应用到有层级体系的容器类(有父BeanFactory的那种),都应该实现此接口
  2. 此接口的getParentBeanFactory方法可以得到此BeanFactory的父BeanFactory,但是设置一个BeanFactory的父BeanFactory的方法却没有在此接口中,而是在ConfigurableBeanFactory中

2.2.getBeanFactory()

获取容器对象:ConfigurableListableBeanFactory

1.3.prepareBeanFactory()

初始化BeanFactory:进行BeanFactory中的属性设置

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		// 设置beanFactory的classloader为当前context的classloader
		beanFactory.setBeanClassLoader(getClassLoader());
		// 设置beanfactory的表达式语言处理器
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		// 为beanFactory增加一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具类
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		// 添加beanPostProcessor,ApplicationContextAwareProcessor此类用来完成某些Aware对象的注入
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		// 设置要忽略自动装配的接口,很多同学理解不了为什么此处要对这些接口进行忽略,原因非常简单,这些接口的实现是由容器通过set方法进行注入的,
		// 所以在使用autowire进行注入的时候需要将这些接口进行忽略
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		// 设置几个自动装配的特殊规则,当在进行ioc初始化的如果有多个实现,那么就使用指定的对象进行注入
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Register early post-processor for detecting inner beans as ApplicationListeners.
		// 注册BPP
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		// 增加对AspectJ的支持,在java中织入分为三种方式,分为编译器织入,类加载器织入,运行期织入,编译器织入是指在java编译器,采用特殊的编译器,将切面织入到java类中,
		// 而类加载期织入则指通过特殊的类加载器,在类字节码加载到JVM时,织入切面,运行期织入则是采用cglib和jdk进行切面的织入
		// aspectj提供了两种织入方式,第一种是通过特殊编译器,在编译器,将aspectj语言编写的切面类织入到java类中,第二种是类加载期织入,就是下面的load time weaving,此处后续讲
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// Register default environment beans.
		// 注册默认的系统环境bean到一级缓存中
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}

1.4.postProcessBeanFactory()

扩展实现方法,默认不做操作

1.5.invokeBeanFactoryPostProcessors()

实例化并按顺序执行BeanFactoryPostProcessor:增强BeanDefinition信息

1.6.registerBeanPostProcessors()

注册BeanPostProcessor

1.7.initMessageSource()

国际化处理:为上下文初始化message源,即不同语言的消息体

1.8.initApplicationEventMulticaster()

初始化事件监听多路广播器

1.9.onRefresh()

扩展实现方法,默认不做操作

SpringBoot此处会创建启动tomcat容器

1.10.registerListeners()

注册监听器:在所有注册的bean中查找listener bean,注册到消息广播器中

1.11.finishBeanFactoryInitialization()

实例化、初始化剩下的非懒加载的单实例(单例对象)

  1. 实例化,先通过反射创建对象 createBeanInstance 获取所有的构造器,如果有进行实例化(determineConstructorsFromBeanPostProcessors)
  2. InstantiateBean 获取实例化策略 getinstantiationStrategy().instantiate() cglib
  3. 获取bean的构造器,通过newInstance获取bean对象,但是此时是半初始化状态
  4. addsingletonfactory解决循环依赖问题(BeanPostprocessors)
  5. popluteBean 对bean进行填充属性
  6. invokeAwareMethods 填充一些aware接口属性
  7. applyBeanPostProcessorsBeforeInitialization 包含n多个对象,要挨个处理
  8. invokeinitMethod
  9. applyBeanPostProcessorsAfterInitialization 对象创建完毕
  10. registerdisposableBeanIfNecessary钩子函数,当bean需要销毁时,执行销毁
  11. AfterSingleCreation移除缓存中对bean加载状态的记录对应开头的beforesinglecreation记录当前bean的加载状态
  12. addsingleton防止循环依赖
  13. 首先会生成对象并且判断是不是factoryBean,会调用getObject返回再对象

1.12.finishRefresh()

完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人

1.13.resetCommonCaches()

重置缓存

重置Spring的常见反射元数据缓存,特别是ReflectionUtils, AnnotationUtils, ResolvableType和CachedIntrospectionResults缓存重置Spring的常见反射元数据缓存,特别是ReflectionUtils, AnnotationUtils, ResolvableType和CachedIntrospectionResults缓存

<think>好的,我需要分析用户提供的配置中的UUID是否生效,以及如果不能生效的话如何实现Kafka的广播消费。首先,用户的配置中使用了${random.uuid}来生成group-id。在Spring Boot中,这种占位符通常会被解析成一个随机的UUID,所以理论上应该是生效的。但需要确认是否在配置文件中正确使用了Spring的随机值生成功能。 接下来,关于Kafka的广播消费,通常每个消费者组内的消费者实例会共同消费主题的分区,而广播消费通常指的是每个消费者实例都能独立消费所有消息,这可以通过为每个实例分配唯一的group-id来实现。例如,使用UUID确保每个消费者的组ID不同,这样每个消费者都会被视为独立的组,从而接收到所有消息。但用户可能在这里混淆了组内广播和组间广播。如果用户希望同一组内的所有消费者都能接收所有消息,这在Kafka中是不支持的,因为Kafka保证每个分区只能被组内的一个消费者消费。因此,要实现类似广播的效果,每个消费者必须属于不同的组,或者使用不同的主题。 可能需要检查用户的配置是否正确应用了随机UUID,并且确认Kafka的配置是否正确,比如bootstrap servers和topic名称是否正确。此外,用户可能需要确保Kafka的消费者配置中是否启用了必要的参数,比如是否设置了正确的key和value的反序列化类,以及是否正确处理了偏移量提交等。 总结问题:UUID的使用是否正确,以及如何调整配置实现广播消费。可能的解决方案包括确认随机UUID的生成是否正确,或者调整消费者组的策略,比如为每个消费者实例分配唯一组ID,或者使用多个主题进行广播。</think>在提供的配置中,`local-cache-refresh.group-id=${random.uuid}` 使用了 Spring 的随机值生成功能,理论上可以生成随机 UUID 并生效。但需注意以下几点: 1. **UUID 生效前提**: - 配置需位于 Spring Boot 的 `application.yml` 或 `application.properties` 中。 - 确保 Spring 环境正确解析 `${random.uuid}`,生成唯一消费者组 ID,避免与其他实例冲突。 2. **广播消费的实现**: Kafka 本身不支持组内广播(同一组内所有消费者接收所有消息),但可通过以下方式模拟广播: - **唯一组 ID**:为每个消费者实例分配不同的组 ID(如使用 `${random.uuid}`),此时每个实例独立消费全量消息。 - **多副本订阅**:将同一消费者组的多个实例部署到不同节点,但需注意 Kafka 的分区分配机制(每个分区仅被组内一个消费者消费)。 3. **配置优化建议**: - 检查 `KAFKA_BOOTSTRAP_SERVERS` 地址是否正确,确保网络可达。 - 若需严格广播,可结合 Kafka 的 `ConsumerFactory` 动态创建多个消费者实例,绑定不同组 ID。 ```properties # 示例:动态组 ID 的完整 Kafka 消费者配置 local-cache-refresh.broker=${KAFKA_BOOTSTRAP_SERVERS:sz-base-service-test.crd.tp-link.com:9092,sz-base-service-test.crd.tp-link.com:9093} local-cache-refresh.group-id=${random.uuid} # 确保每个实例组 ID 唯一 local-cache-refresh.topic=${LOCAL_CACHE_REFRESH_KAFKA_TOPIC:local.cache.refresh} local-cache-refresh.kafka-enable=${CACHE_DELETE_KAFKA_ENABLE:true} ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值