Spring ApplicationContext初始化过程

Spring-01篇章

一、Spring 简介

Spring是一个开源的Java平台,它提供了全面的基础设施支持来帮助Java开发者更容易地开发Java应用程序。Spring框架的核心特点是依赖注入(DI)和面向切面编程(AOP),这些使得开发者能够以更简洁和模块化的方式构建应用程序。

Spring的主要特点包括:

  1. 依赖注入:Spring通过依赖注入(DI)来实现组件之间的解耦,这意味着组件的依赖关系由Spring容器在运行时注入,而不是在代码中硬编码。

  2. 面向切面编程:Spring支持面向切面编程(AOP),允许开发者将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来。

  3. 事务管理:Spring提供了声明式事务管理,使得事务管理更加简单和透明。

  4. 数据访问:Spring提供了对各种数据访问技术的集成,如JDBC、Hibernate、JPA等。

  5. Web支持:Spring提供了对多种Web框架的集成,如Spring MVC、Spring WebFlux等。

  6. 安全性:Spring Security是一个功能强大的安全和认证框架,可以与Spring应用程序集成。

  7. 测试:Spring提供了对单元测试和集成测试的支持,使得测试Spring应用程序更加容易。

  8. 模块化:Spring框架是高度模块化的,开发者可以根据需要选择使用特定的模块。

  9. 集成:Spring提供了与其他企业级技术的集成,如消息传递、任务调度等。

  10. 社区和文档:Spring拥有一个活跃的社区和丰富的文档资源,为开发者提供了大量的学习材料和支持。

Spring框架广泛应用于企业级Java应用开发,它简化了Java应用的开发,提高了代码的可维护性和可测试性。随着时间的推移,Spring已经发展成一个庞大的生态系统,包括Spring Boot、Spring Cloud等子项目,进一步简化了微服务架构的开发和部署。

二、使用及源码讲解

1.导入依赖包

本次演示使用的jdk版本为11,spring版本为 5.3.39

以下是pom文件示例

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.simple.code.generator</groupId>
  <artifactId>spring-simple</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>spring-simple</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <dependencies>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.39</version>
    </dependency>

  </dependencies>
</project>

然后我们创建一个HelloService的接口用于演示,并为接口创建实现类,具体代码如下:

HelloService

package com.simple.code.generator.service;

public interface HelloService {

    void sayHello();

}

HelloServiceImpl

package com.simple.code.generator.service.impl;

import com.simple.code.generator.service.HelloService;

public class HelloServiceImpl implements HelloService {

    public void sayHello() {
        System.out.println("hello world !!!");
    }
}

编写一个main函数进行测试执行,并查看输出结果。

package com.simple.code.generator;

import com.simple.code.generator.service.HelloService;
import com.simple.code.generator.service.impl.HelloServiceImpl;

public class Main {

    public static void main(String[] args) {
        HelloService helloService = new HelloServiceImpl();
        helloService.sayHello();
    }

}

整体结构目录见截图

执行后接下来我们需要思考的问题是,已经引入了spring依赖包,为什么还要进行new对象的操作来获取方式呢,我们将代码稍加改造,在HelloServiceImpl增加@Service注解

package com.simple.code.generator.service.impl;

import com.simple.code.generator.service.HelloService;
import org.springframework.stereotype.Service;

@Service
public class HelloServiceImpl implements HelloService {

    public void sayHello() {
        System.out.println("hello world !!!");
    }
}

将Main入口调用改成如下,修改后再次执行,发现我们不再需要显示的去进行new对象调用,直接从容器中获取对象即可访问到sayHello的内容。接下来我们将通过这个案例去分析讲解什么是AnnotationConfigApplicationContext,以及HelloService是如何被加载初始化的。

package com.simple.code.generator;

import com.simple.code.generator.service.HelloService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

    public static void main(String[] args) {
        //com.simple.code.generator 对应需要扫描的包名
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.simple.code.generator");
        context.getBean(HelloService.class).sayHello();
    }

}

2.HelloService注册到容器过程

我们看到AnnotationConfig ApplicationContext的类图如下,接下来我们将围绕ResourceLoader和BeanFactory讲解Context的初始化过程。

如图展示,我们在创建AnnontationConfigApplicationContext在创建的时候会同时创建AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner。创建后紧跟着会调用ClassPathBeanDefinitionScanner的scan函数扫描我们创建时传入的包路径进行代码文件扫描,扫描后通过GenericApplicationContext的registerBeanDefinition和 registerAlias将找到的文件注册到context容器中,到这一步我们已经看到并掌握了容器扫描以及注册bean的过程,感兴趣的可以随着流程图看下源码中的细节部分。接下来我们继续分析容器的启动过程。

我们继续查看refresh函数,它会执行父类的refresh函数启动spring context容器,并将第一步扫描到的类信息进行初始化,核心代码如下。到这里我们从class的扫描到装载以及初始化容器的过程简单的带大家查看了一遍。

@Override
	public void refresh() throws BeansException, IllegalStateException {
		this.startupShutdownLock.lock();
		try {
			this.startupShutdownThread = Thread.currentThread();

			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);
				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (RuntimeException | Error ex ) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				contextRefresh.end();
			}
		}
		finally {
			this.startupShutdownThread = null;
			this.startupShutdownLock.unlock();
		}
	}

总结

以上就是今天要讲的内容,本文仅仅简单介绍了spring的使用,而spring提供了IOC、AOP、DI等功能我将会在后续的文章中一一详细描述。如描述有误还望大家不吝赐教,感谢各位耐心观看!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值