ApplicationContext 了,ApplicationContext 继承自 BeanFactory,但是它不应该被理解为 BeanFactory 的实现类,而是说其内部持有一个实例化的 BeanFactory(DefaultListableBeanFactory)。以后所有的 BeanFactory 相关的操作其实是委托给这个实例来处理的。
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationfile.xml");
}
最基本启动一个Spring容器的例子
-
ApplicationContext: 这是Spring Framework中的一个核心接口,它代表了Spring IoC容器,并负责实例化、配置和管理应用程序中的对象。ApplicationContext可以加载配置文件、管理Bean之间的依赖关系,并提供了访问Bean的机制。
2.ClassPathXmlApplicationContext: 是ApplicationContext接口的实现类之一,用于从类路径中加载XML配置文件。它会在类路径中搜索指定的配置文件,并根据配置文件中的定义来实例化和配置Bean。
public class App {
public static void main(String[] args) {
// 用我们的配置文件来启动一个 ApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
System.out.println("context 启动成功");
// 从 context 中取出我们的 Bean,而不是用 new MessageServiceImpl() 这种方式
MessageService messageService = context.getBean(MessageService.class);
// 这句将输出: hello world
System.out.println(messageService.getMessage());
}
}
-
ApplicationContext 继承了 ListableBeanFactory,这个 Listable 的意思就是,通过这个接口,我们可以获取多个 Bean,大家看源码会发现,最顶层 BeanFactory 接口的方法都是获取单个 Bean 的。
-
ApplicationContext 继承了 HierarchicalBeanFactory,Hierarchical 单词本身已经能说明问题了,也就是说我们可以在应用中起多个 BeanFactory,然后可以将各个 BeanFactory 设置为父子关系。
-
AutowireCapableBeanFactory 这个名字中的 Autowire 大家都非常熟悉,它就是用来自动装配 Bean 用的,但是仔细看上图,ApplicationContext 并没有继承它,不过不用担心,不使用继承,不代表不可以使用组合,如果你看到 ApplicationContext 接口定义中的最后一个方法 getAutowireCapableBeanFactory() 就知道了
启动过程分析
1.第一步,我们肯定要从 ClassPathXmlApplicationContext 的构造方法说起
2.接下来,就是 refresh()
,这里简单说下为什么是 refresh(),而不是 init() 这种名字的方法。因为 ApplicationContext 建立起来以后,其实我们是可以通过调用 refresh() 这个方法重建的,refresh() 会将原来的 ApplicationContext 销毁,然后再重新执行一次初始化操作。
为什么是 refresh() 而不是 init()?
-
ApplicationContext 生命周期管理:
-
ApplicationContext 在被创建后,其生命周期可能会涉及到多个阶段和状态变化。init() 通常用于单个 Bean 的初始化阶段,而不是整个 ApplicationContext 的初始化和刷新过程。
-
-
Spring IoC 容器的特性:
-
Spring IoC 容器的初始化不仅仅是单纯地实例化 Bean,还包括资源加载、依赖注入、生命周期管理等复杂的操作。refresh() 方法能够确保在容器需要更新时,能够重新加载所有配置,而不仅仅是执行初始化操作。
-
-
Bean 的生命周期与容器的生命周期分离:
-
Spring 设计中,Bean 的生命周期由容器管理,而不同于容器本身的生命周期。因此,ApplicationContext 提供了 refresh() 方法,来明确表达容器状态的刷新,与单个 Bean 的初始化操作不同。
-
-
清晰的语义:
-
refresh() 方法的名称清晰地表明了它的功能:刷新容器的状态。这比简单的 init() 方法更具描述性和准确性,能够让开发人员清晰地理解其作用,从而更好地管理 ApplicationContext 的生命周期。
-
创建 Bean 容器前的准备工作
protected void prepareRefresh() {
创建 Bean 容器,加载并注册 Bean
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // 关闭旧的 BeanFactory (如果有),创建新的 BeanFactory,加载 Bean 定义、注册 Bean 等等 refreshBeanFactory();
初始化 BeanFactory
protected final void refreshBeanFactory() throws BeansException
注意,这个方法是全文最重要的部分之一,这里将会初始化 BeanFactory、加载 Bean、注册 Bean 等等。
当然,这步结束后,Bean 并没有完成初始化。这里指的是 Bean 实例并未在这一步生成。
ApplicationContext 继承自 BeanFactory,但是它不应该被理解为 BeanFactory 的实现类,而是说其内部持有一个实例化的 BeanFactory(DefaultListableBeanFactory)。以后所有的 BeanFactory 相关的操作其实是委托给这个实例来处理的。
obtainFreshBeanFactory()
在 refresh()
方法中,obtainFreshBeanFactory()
负责获取一个全新的Bean工厂实例,也就是 BeanFactory
的初始化过程。这一步骤涉及以下关键操作:
-
创建BeanFactory实例: Spring 使用
DefaultListableBeanFactory
或其子类作为默认的BeanFactory
实现。这个过程通常由createBeanFactory()
方法完成,它会创建一个新的DefaultListableBeanFactory
实例。
javaCopy Codeprotected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // 创建一个新的BeanFactory实例 refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 设置BeanFactory的类加载器等属性 customizeBeanFactory(beanFactory); return beanFactory; }
2. 加载Bean定义
一旦 BeanFactory
初始化完成,接下来的步骤是加载Bean的定义信息。这些定义通常来源于配置文件(如XML文件)、注解或者基于Java的配置类。Spring 使用不同的 BeanDefinitionReader
实现类(如 XmlBeanDefinitionReader
、AnnotatedBeanDefinitionReader
等)来读取这些定义并将其注册到 BeanFactory
中。
javaCopy Codeprotected void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); // 加载Bean定义 loadBeanDefinitions(beanFactory); this.beanFactory = beanFactory; } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source", ex); } }
3. 注册Bean定义
loadBeanDefinitions(beanFactory)
方法负责将解析后的Bean定义注册到 BeanFactory
中。这一步包括解析XML文件、扫描类路径、处理注解等操作,最终将每个Bean的定义信息(包括类名、依赖关系、初始化方法等)存储在 BeanFactory
的内部数据结构中。
javaCopy Codeprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // 创建Bean定义读取器 BeanDefinitionReader beanDefinitionReader = createBeanDefinitionReader(beanFactory); // 加载Bean定义,具体实现依赖于Bean定义读取器的实现类 loadBeanDefinitions(beanDefinitionReader, beanFactory); }
4. Bean实例化与初始化
在 refresh()
方法的后续步骤中,当应用程序需要使用某个Bean时,Spring IoC容器会根据Bean的定义信息(包括类、依赖关系等)实例化相应的Bean对象。这个过程通常发生在 getBean()
方法调用时。
-
依赖注入: 在Bean实例化后,Spring会通过依赖注入机制将所需的依赖项自动注入到Bean中。
-
初始化方法: 如果Bean类实现了
InitializingBean
接口或者在配置中指定了初始化方法(如init-method
属性),Spring会在实例化和依赖注入完成后调用这些方法。
总结
在 refresh()
方法中,obtainFreshBeanFactory()
的作用是获取一个新的 BeanFactory
实例并初始化它,包括加载和注册Bean的定义。虽然在这个阶段,Bean的实例并没有完成初始化,但是这一步骤为后续的Bean实例化和依赖注入做了准备。理解这些步骤有助于我们了解Spring IoC容器是如何管理Bean的生命周期和依赖关系的。
gpt总结
理解Spring IoC容器的完整流程需要深入研究其底层源码,特别是核心模块spring-context
和spring-beans
。以下是一个简化的版本,涵盖了主要的步骤和关键类,以便于理解IoC容器的工作原理:
1. 加载配置元数据
Spring IoC容器通常从XML配置文件或基于Java的配置类中加载配置元数据。假设我们有一个简单的配置文件applicationContext.xml
:
xmlCopy Code<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userService" class="com.example.UserService"> <!-- 依赖注入 --> <property name="userDao" ref="userDao"/> </bean> <bean id="userDao" class="com.example.UserDaoImpl"/> </beans>
2. 解析Bean定义
Spring IoC容器在加载配置文件时,会使用XML解析器解析XML文件并提取Bean定义信息。关键类包括XmlBeanDefinitionReader
:
javaCopy Codepublic class XmlBeanDefinitionReader { private BeanDefinitionRegistry registry; public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) { this.registry = registry; } public void loadBeanDefinitions(Resource resource) { // 解析XML资源并注册Bean定义 // 例如从XML中读取<bean>标签,创建对应的BeanDefinition对象 } // 省略其他方法 }
3. 注册Bean定义
注册过程由BeanDefinitionRegistry
接口及其实现类负责,通常使用DefaultListableBeanFactory
:
javaCopy Codepublic class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry { private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(); @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { // 将BeanDefinition注册到容器中 beanDefinitionMap.put(beanName, beanDefinition); } // 省略其他方法 }
4. 实例化Bean
当应用程序需要获取Bean时,通过Bean工厂获取Bean的实例。关键类包括DefaultListableBeanFactory
中的getBean()
方法:
javaCopy Codepublic class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry { @Override protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { // 使用反射创建Bean的实例 // 根据BeanDefinition中的信息,实例化Bean对象 } @Override public Object getBean(String name) throws BeansException { // 从容器中获取Bean实例 return doGetBean(name, null, null, false); } // 省略其他方法 }
5. 依赖注入
依赖注入是IoC容器的核心功能之一,通过反射或其他手段将Bean所需的依赖注入到Bean中。Spring使用AutowiredAnnotationBeanPostProcessor
等后置处理器来实现依赖注入:
javaCopy Codepublic class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessProperties(Object bean, String beanName) throws BeansException { // 通过反射扫描Bean的属性,解析@Autowired等注解,并进行依赖注入 } // 省略其他方法 }
6. 生命周期管理
Spring IoC容器还管理Bean的生命周期,包括初始化和销毁。例如,AbstractAutowireCapableBeanFactory
负责调用Bean的初始化方法和销毁方法
BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
区别总结
-
执行时机:
-
BeanFactoryPostProcessor
在 Spring 容器实例化 BeanDefinition 之后、实例化 Bean 之前执行。 -
BeanPostProcessor
在 Bean 实例化之后、依赖注入完成之前执行。
-
-
作用对象:
-
BeanFactoryPostProcessor
作用于 BeanDefinition 的元数据,可以影响 Spring 容器中所有 Bean 的创建过程。 -
BeanPostProcessor
作用于具体的 Bean 实例,只影响特定的 Bean 实例。
-
-
典型用途:
-
BeanFactoryPostProcessor
用于对 BeanFactory 的配置进行修改,如动态注册 Bean。 -
BeanPostProcessor
用于在 Bean 的初始化过程中进行额外的处理,如 AOP 代理的创建。
-
综上所述,BeanFactoryPostProcessor 和 BeanPostProcessor 是 Spring 中用于定制和扩展 Bean 实例化过程的重要接口,各自在不同阶段提供了不同的扩展能力。
BeanFactoryPostProcessor
接口允许我们在 Spring 容器实例化了 BeanDefinition(即配置元数据)之后,在实例化具体的 Bean 对象之前对其进行后处理。这意味着它可以在 Spring IOC 容器读取了所有的配置元数据(包括 Bean 的定义和属性)后,在实例化任何 Bean 之前介入。
具体来说:
-
BeanDefinition 解析和注册阶段: 在 Spring 启动时,容器会读取配置文件或者注解等配置元数据,并根据这些信息创建对应的 BeanDefinition 对象,这些对象描述了每个 Bean 的定义、类型、依赖关系等信息。
-
BeanFactoryPostProcessor 的介入: 在 BeanDefinition 注册完成之后,容器会调用注册的
BeanFactoryPostProcessor
实现类的方法。这时,BeanFactoryPostProcessor
可以查看并修改容器中的 BeanDefinition,但还没有实例化任何 Bean。 -
Bean 实例化阶段: 一旦所有注册的
BeanFactoryPostProcessor
执行完毕,容器就会根据 BeanDefinition 实例化具体的 Bean 对象,并进行依赖注入等后续处理。
因此,BeanFactoryPostProcessor
提供了一个在 Spring 容器准备实例化 Bean 之前修改 BeanDefinition 的机会,但它并不直接处理实际的 Bean 实例。这种机制允许我们在 Spring 容器加载配置信息后,但在实例化 Bean 之前,对容器中的 BeanDefinition 进行修改或者扩展,以满足特定的需求或者进行定制化配置
BeanFactory 和 FactoryBean的区别
在 Spring 框架中,有两个与 IoC 容器相关的重要概念:FactoryBean 和 BeanFactory。它们虽然名字相似,但是在 Spring 中扮演的角色和功能却有所不同。
BeanFactory
BeanFactory 是 Spring IoC 容器的核心接口之一。它提供了 IoC 容器最基本的功能,包括:
-
Bean 实例化:负责根据配置信息实例化 bean 对象。
-
依赖注入:将 bean 的依赖关系动态注入到对象中,实现松耦合。
-
生命周期管理:管理 bean 的生命周期,包括初始化和销毁。
-
配置管理:读取和解析配置元数据,包括 bean 的定义、作用域、属性等。
BeanFactory 的实现类通常包括 DefaultListableBeanFactory
和 XmlBeanFactory
等,它们是 Spring IoC 容器的具体实现。BeanFactory 采用延迟加载策略,即在第一次请求时才会实例化 bean,从而节省资源。
实例化bean和初始化bean是一个概念吗
实例化Bean和初始化Bean是两个相关但不完全相同的概念。
-
实例化Bean:
-
实例化Bean是指在容器中创建Bean的实际对象。这通常发生在容器根据Bean的定义信息(如类路径、构造函数参数等)使用反射或其他手段创建Bean的实例的过程。
-
实例化过程确保了容器可以通过Bean的定义来创建具体的对象,但此时还未涉及到依赖注入或其他初始化操作。
-
-
初始化Bean:
-
初始化Bean是指在实例化之后,容器对Bean进行额外的处理和配置,以使Bean处于可用状态。这包括依赖注入、调用初始化方法、应用BeanPostProcessors等操作。
-
初始化过程确保了Bean的各种依赖已经被注入,并且Bean处于一种可以被应用程序使用的状态。
-
在Spring IoC容器中,这两个过程是逐步进行的:
-
实例化Bean:容器根据Bean的定义创建Bean的实例对象。
-
初始化Bean:容器对实例化后的Bean进行依赖注入、初始化方法调用等操作,确保Bean准备好被应用程序使用。
因此,虽然它们通常在文档或讨论中一起提到,但它们确实表示两个不
FactoryBean
FactoryBean 是一个特殊的 bean,它本身是一个工厂类,用来创建或管理其他的 bean 实例。在 Spring 中,FactoryBean 接口定义了创建 bean 实例的标准方法和生命周期。通常,我们可以通过两种方式来实现 FactoryBean:
-
通过实现 FactoryBean 接口:自定义一个类,实现 FactoryBean 接口,并在其实现方法中定义 bean 的创建逻辑。
javaCopy Codepublic class MyFactoryBean implements FactoryBean<MyBean> { @Override public MyBean getObject() throws Exception { // 返回创建的 bean 实例 return new MyBean(); } @Override public Class<?> getObjectType() { return MyBean.class; } @Override public boolean isSingleton() { return true; // true 表示该 bean 是单例的 } }
-
通过继承 Spring 提供的抽象类:Spring 提供了几个抽象类,如
AbstractFactoryBean
,简化了 FactoryBean 的实现。
FactoryBean 提供了一种非常灵活的方式来定义 bean 的创建过程,允许开发者在获取 bean 实例之前执行一些定制化的逻辑。它常用于复杂的对象创建、资源管理或者代理对象的创建。
区别总结
-
BeanFactory 是 Spring IoC 容器的核心接口,负责管理 bean 的生命周期、依赖注入等基础功能。
-
FactoryBean 是一个特殊的 bean,它本身是一个工厂,用来创建或管理其他的 bean 实例。通过实现 FactoryBean 接口或者继承 Spring 提供的抽象类,可以定制化 bean 的创建过程。
在实际应用中,开发者可以根据需要选择合适的方式来定义和管理 bean,以实现更灵活、可维护和可测试的代码。
FactoryBean 接口在 Spring 中被广泛用于定义复杂或者特殊需求的 bean 创建过程。以下是一些比较出名的组件或模块,它们利用了 FactoryBean 接口来实现自定义的 bean 创建逻辑:
-
HibernateTemplate
-
HibernateTemplate
是 Spring 提供的一个简化 Hibernate 数据访问的类,它通过实现 FactoryBean 接口来创建SessionFactory
和HibernateTemplate
对象。这种方式使得 Hibernate 的配置和管理变得更加灵活,允许开发者在创建时进行一些自定义的初始化操作。
-
javaCopy Codepublic class HibernateTemplateFactoryBean implements FactoryBean<HibernateTemplate>, InitializingBean {
private SessionFactory sessionFactory;
private HibernateTemplate hibernateTemplate;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public HibernateTemplate getObject() throws Exception {
return this.hibernateTemplate;
}
@Override
public Class<?> getObjectType() {
return HibernateTemplate.class;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void afterPropertiesSet() {
this.hibernateTemplate = new HibernateTemplate(this.sessionFactory);
// 可以进行其他的初始化操作
}