ApplicationContext拓展功能

本文详细介绍了Spring的ApplicationContext在初始化过程中涉及的关键步骤,包括属性设置、刷新上下文的具体流程,如环境准备、加载BeanFactory、激活BeanFactory后处理器、注册BeanPostProcessor等。在刷新上下文中,Spring对BeanFactory进行功能填充,如支持SpEL、属性编辑器、AspectJ等功能,并实现了Bean生命周期管理和事件广播机制。最后,文章总结了ApplicationContext相对于BeanFactory的拓展功能,如SpEL支持、 Aware接口、消息源和生命周期管理等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、属性设置

对于ApplicationContext,其实例化前必须要设置的就是配置文件的路径--configLocation。例如:

对于非Web环境下的ClasspathXmlApplicationContext,需要通过构造函数或调用setConfigLocation设置配置文件路径;

对于Web环境下的XmlWebApplicationContext,会使用web.xml中配置的contextConfigLocation作为配置文件路径

//另外Web环境下使用的WebXmlApplicationContext还会保存ServletContext对象以及一些Web环境下的参数。

二、刷新上下文

refresh方法基本算是ApplicationContext最重要的方法之一,基本包含了ApplicationContext的大部分功能。需要注意的是,refresh方法并不是在ApplicationContext接口中定义的,而是在其子接口ConfigurableApplicationContext中定义的。下面是refresh的实现(代码位于AbstractApplicationContext):

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 准备刷新的上下文
			prepareRefresh();

			// 初始化BeanFactory,并读取配置文件
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 对BeanFactory进行填充
			prepareBeanFactory(beanFactory);

			try {
				// 模版方法,由子类对初始化好的BeanFactory进行额外的处理
				postProcessBeanFactory(beanFactory);

				// 调用BeanFactoryPostProcessor后处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册Bean处理器
				registerBeanPostProcessors(beanFactory);

				// 初始化Message源,与国际化处理相关
				initMessageSource();

				// 初始化应用消息广播器,并作为一个Bean注册到BeanFactory中
				initApplicationEventMulticaster();

				// 模版方法,交由子类实现,刷新前的特殊处理
				onRefresh();

				// 在注册的bean列表中查找Listener类型的bean,注册到消息广播器中
				registerListeners();

				// 提前初始化单例bean(非惰性的)
				finishBeanFactoryInitialization(beanFactory);

				// 通知生命周期处理器LifecycleProcessor刷新过程,并且发出ContextRefreshEvent事件
				finishRefresh();
			}

			catch (BeansException ex) {
				//log..
				// 销毁已经创建好的bean
				destroyBeans();
				// Reset 'active' flag.
				cancelRefresh(ex);
				throw ex;
			}
			finally {
				resetCommonCaches();
			}
		}
	}

刷新的流程为:

  1. 初始化的准备工作,如系统属性或环境变量的准备和验证
  2. 创建BeanFactory,并读取xml配置文件
  3. 对BeanFactory进行功能填充
  4. 通过模版方法模式,交由子类覆盖方法postProcessBeanFactory,对BeanFactory做额外处理
  5. 激活BeanFactory后处理器
  6. 注册拦截Bean创建的Bean处理器
  7. 初始化Message源
  8. 初始化消息广播器
  9. 留给子类初始化其他bean
  10. 将注册的Listener bean注册到消息广播器中
  11. 提前初始化单例bean(非惰性)
  12. 完成刷新,发出ContextRefreshEvent事件,并通知生命周期处理器LifecycleProcessor刷新过程

1、环境准备

主要是做些准备工作,对属性进行初始化和验证工作

	protected void prepareRefresh() {
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);
		
		//log...
		// 交由子类覆盖
		initPropertySources();

		// 验证需要的属性是否都已经被放入环境中
		getEnvironment().validateRequiredProperties();

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
	}

2、加载BeanFactory

ApplicationContext通过obtainFreshBeanFactory函数创建BeanFactory,自此方法后也就拥有了BeanFactory的所有功能:

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		//委托给了refreshBeanFactory方法
		refreshBeanFactory();
		//因为创建BeanFactory实在子类中实现的,所以需要通过getBeanFactory才能获取到实例
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

下面是refreshBeanFactory的实现(位于AbstractRefreshableApplicationContext):

	protected final void refreshBeanFactory() throws BeansException {
		//如果已经创建过BeanFactory,则销毁所有已经创建的Bean并且重新创建BeanFactory
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			//实例化
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			//设置一些属性
			customizeBeanFactory(beanFactory);
			//加载xml配置文件
			loadBeanDefinitions(beanFactory);
			//将BeanFactory实例设置到ApplicationContext中
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

初始化流程:

  1. 如果已经创建过,则销毁、清理掉以前创建的BeanFactory
  2. 实例化BeanFactory
  3. 定制BeanFactory
  4. 加载xml配置文件

a、实例化BeanFactory

实例化的代码比较简单,直接新建了一个DefaultListableBeanFactory,并且传入父ApplicationContext(如果存在的话)中的BeanFactory作为父BeanFactory,下面是实例化代码:

	protected DefaultListableBeanFactory createBeanFactory() {
		//如果存在父ApplicationContext,会通过它获取父BeanFactory传出构造函数
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}

getInternalParentBeanFactory实现:

	protected BeanFactory getInternalParentBeanFactory() {
		return (getParent() instanceof ConfigurableApplicationContext) ?
				((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
	}

如果父ApplicationContext类型是ConfigurableApplicationContext,则获取其中的BeanFactory,否则将父ApplicationContext作为BeanFactory传入。

b、定制BeanFactory

	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		//allowBeanDefinitionOverriding:是否允许覆盖同名称的不同定义的对象
		if (this.allowBeanDefinitionOverriding != null) {
			beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		//allowCircularReferences:是否允许循环依赖
		if (this.allowCircularReferences != null) {
			beanFactory.setAllowCircularReferences(this.allowCircularReferences);
		}
	}

主要是对allowBeanDefinitionOverriding和allowCircularReferences属性进行设置,在AbstractRefreshableApplicationContext中并未对这两个属性进行设置,而是需要由子类来进行配置。

c、加载配置文件

	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// 为指定的BeanFactory创建XmlBeanDefinitionReader
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// 
<think>好的,用户的问题是关于服务扩展模块的核心代码实现,并且提到了Spring Boot中的循环依赖案例。我需要先理解用户的需求。他们可能正在开发一个Spring Boot应用,遇到了服务扩展的问题,或者想要设计一个可扩展的服务模块,同时可能遇到了循环依赖的问题。 首先,服务扩展模块的核心实现通常涉及设计模式,比如策略模式或工厂模式。这样可以根据不同的情况动态选择不同的实现。需要结合Spring的特性,比如依赖注入和Bean管理。然后,用户提到的循环依赖,可能需要解决在Spring中Bean之间相互引用的问题,常见的解决方法有使用构造器注入、@Lazy注解或者调整依赖关系。 接下来,用户需要示例代码。我应该提供一个结构清晰的例子,展示如何定义服务接口、不同实现,以及如何动态选择实现。同时,要避免循环依赖,可能需要用@Lazy或者接口注入。例如,主服务类依赖扩展服务,而扩展服务可能需要主服务的某些功能,这时候需要用@Lazy延迟加载。 还要注意代码中的Spring注解,比如@Service,@Autowired,@Qualifier,或者@Primary,这些可以帮助管理Bean的注入。另外,动态选择实现可以使用ApplicationContext来获取特定Bean,或者使用条件注解如@ConditionalOnProperty。 然后,用户可能遇到的问题包括配置错误、Bean注入失败、循环依赖导致启动失败等,需要给出解决方法,比如检查@ComponentScan范围,使用接口隔离,或者调整注入方式。 最后,生成的相关问题需要围绕服务扩展和循环依赖,比如设计模式的应用、动态配置、解决循环依赖的方法以及性能优化等。确保引用正确,比如用户提供的引用是关于循环依赖案例的,所以在回答中提到循环依赖时引用[^1]。</think>### 服务扩展模块核心代码实现方式示例 #### 一、服务扩展模块架构设计 服务扩展模块通常采用策略模式+工厂模式实现,结合Spring框架特性实现动态扩展。核心要素包含: 1. 服务接口定义:$ServiceInterface$ 2. 扩展点注解:$@Extension$ 3. 策略选择器:$ServiceSelector$ 4. 配置中心集成:$ConfigCenter$ #### 二、核心代码实现 ```java // 1. 定义扩展接口 public interface ExtensionService { String execute(String input); } // 2. 实现扩展点(示例两个扩展实现) @Extension(name = "AES") @Service public class AesExtension implements ExtensionService { public String execute(String input) { return "AES processed: " + input; } } @Extension(name = "RSA") @Service public class RsaExtension implements ExtensionService { @Autowired @Lazy // 解决循环依赖关键注解 private MainService mainService; public String execute(String input) { return mainService.enrichData("RSA processed: " + input); } } // 3. 服务选择器工厂 @Service public class ExtensionFactory { private Map<String, ExtensionService> extensions = new ConcurrentHashMap<>(); @Autowired public void initExtensions(List<ExtensionService> services) { services.forEach(service -> { Extension annotation = service.getClass().getAnnotation(Extension.class); extensions.put(annotation.name(), service); }); } public ExtensionService getExtension(String type) { return extensions.getOrDefault(type, new DefaultExtension()); } } // 4. 主服务调用 @Service public class MainService { @Autowired private ExtensionFactory factory; public String processRequest(String type, String data) { return factory.getExtension(type).execute(data); } public String enrichData(String data) { return "Enriched: " + data; } } ``` #### 三、循环依赖解决方案 当出现`MainService` ↔ `RsaExtension`循环依赖时: 1. 使用`@Lazy`延迟加载(如示例代码所示) 2. 推荐接口分离设计: ```java public interface MainServiceFacade { String enrichData(String data); } // MainService实现该接口 @Service public class MainService implements MainServiceFacade { /*...*/ } ``` #### 四、配置示例(application.yml) ```yaml extensions: active: AES,RSA # 控制扩展启用状态 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值