目录
- BeanFactory实现
- BeanDefinition
- 后置处理器
- 单例bean创建
- 后置处理器顺序
- 总结
- ApplicationContext实现
- ClassPathXmlApplicationContext
- FileSystemXmlApplicationContext
- AnnotationConfigApplicationContext
- AnnotationConfigServletWebServerApplicationContext
BeanFactory实现
BeanDefinition
BeanDefinition顾名思义就是Bean的一些定义信息。我们平时使用的配置类、xml、组件扫描等方式都是生成 BeanDefinition 对象注册到 beanFactory 当中。
前面我们讲过DefaultListableBeanFactory
,他是BeanFactory
最重要的实现,其类图如下
下面以DefaultListableBeanFactory
为例演示。
有如下示例:
public class TestBeanFactory {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
}
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
}
static class Bean1 {
public Bean1() {
System.out.println("Bean1 构造方法");
}
}
static class Bean2 {
public Bean2() {
System.out.println("Bean2 构造方法");
}
}
}
我们直接通过new创建一个beanFactory,但是其实他的功能非常简单,其内部也没有任何的Bean。
但是我们可以通过添加一些BeanDefinition
,然后beanFactory利用BeanDefinition来创建Bean。
首先来看下如何添加BeanDefinition:
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建Config的BeanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
// 把beanDefinition注册到beanFactory
beanFactory.registerBeanDefinition("config", beanDefinition);
// 查看beanFactory中beanDefinition的名字
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
运行结果:
config
发现结果中只有config,说明我们的BeanDefinition已经注册到beanFactory中了。但是此时还是没有任何的Bean,因为还没有去使用BeanDefinition创建Bean。要创建Bean,不是beanFactory能够完成的,需要借助于后处理器,他能识别@Configuration注解和@Bean注解,从而创建对应的Bean。
后置处理器
添加后置处理器的代码如下:
// 给beanFactory添加一些内置的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
添加后再打印出BeanDefinition的名字,结果如下:
config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
可以看到,除了config,还添加了5个内置的处理器的BeanDefinition,其中internalConfigurationAnnotationProcessor
就是来处理@Configuration
注解的。
但是上面的步骤只是把BeanDefinition加到了beanFactory中,还并没有开始被使用。下面看下怎么运行后置处理器:
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建Config的BeanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
// 把beanDefinition注册到beanFactory
beanFactory.registerBeanDefinition("config", beanDefinition);
// 给beanFactory添加一些内置的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// 拿到beanFactory的后置处理器,这里有很多,其中一个就是internalConfigurationAnnotationProcessor
Map<String, BeanFactoryPostProcessor> processorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
// 执行后置处理器,当internalConfigurationAnnotationProcessor运行,就会把Bean1和Bean2的beanDefinition注册到beanFactory
processorMap.values().stream().forEach(processor -> {
processor.postProcessBeanFactory(beanFactory);
});
// 查看beanFactory中beanDefinition的名字
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
运行结果如下:
config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
bean1
bean2
可以看到bean1和bean2成功被注册到了beanFactory。
所以,beanFactory本身功能比较简单,但是可以通过一些后置处理器,补充了一些Bean的定义,即BeanDefinition。
上面是把BeanDefinition成功注册到了beanFactory,那实际我们的Bean是否已经成功创建了呢?使用如下代码:
// 获取Bean
Bean1 bean1 = beanFactory.getBean(Bean1.class);
System.out.println(bean1.getBean2());
结果如下:
Bean1 构造方法
null
可以看到,Bean1被成功创建了,且是使用getBean时,调用了其构造方法。但是他的bean2属性却是null,缺少了依赖注入的功能。这是因为还缺少了其他的后置处理器,就是Bean的后置处理器,他能够解析Autowired
注解。注意他与BeanFactory的后置处理器不同,beanFactory的后置处理器主要补充BeanDefinition,而Bean的后置处理器主要对Bean的生命周期内进行一些处理。
注意上面打印的BeanDefinition,有一个internalAutowiredAnnotationProcessor
,他就是来处理Autowired
注解的。
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建Config的BeanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
// 把beanDefinition注册到beanFactory
beanFactory.registerBeanDefinition("config", beanDefinition);
// 给beanFactory添加一些内置的后处理器,注意只是把后处理器添加到了beanFactory而已,后处理器还不会起作用
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// 拿到beanFactory的后置处理器,这里有很多,其中一个就是internalConfigurationAnnotationProcessor
Map<String, BeanFactoryPostProcessor> processorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
// 执行后置处理器,当internalConfigurationAnnotationProcessor运行,就会把Bean1和Bean2的beanDefinition注册到beanFactory
processorMap.values().stream().forEach(processor -> {
processor.postProcessBeanFactory(beanFactory);
});
// Bean 的后处理器,针对Bean的生命周期的各个阶段提供扩展,例如@Autowired。
// 注意这一步,是把后处理器与beanFactory绑定,这样创建Bean时,后处理器才能起作用
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().forEach(beanFactory::addBeanPostProcessor);
// 查看beanFactory中beanDefinition的名字
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
System.out.println("---------- 分割线 ----------");
// 获取Bean
Bean1 bean1 = beanFactory.getBean(Bean1.class);
System.out.println(bean1.getBean2());
}
运行如下:
config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
bean1
bean2
---------- 分割线 ----------
16:47:57.859 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
16:47:57.860 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config'
Bean1 构造方法
16:47:57.907 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
Bean2 构造方法
com.cys.demo02.TestBeanFactory$Bean2@3e11f9e9
可以看到,成功把bean2注入到了bean1。
单例bean创建
另外从上面的例子还可以看到,上面的分割线之后,bean1和bean2才开始创建,且他们都是单例的。也就说,只有当真正需要bean的时候,他才会去创建。我们可以使用方法preInstantiateSingletons
,主动去创建那些单例bean。代码如下:
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 省略代码
...
// 主动创建单例bean
beanFactory.preInstantiateSingletons();
System.out.println("---------- 分割线 ----------");
// 获取Bean
Bean1 bean1 = beanFactory.getBean(Bean1.class);
System.out.println(bean1.getBean2());
}
结果如下:
config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
bean1
bean2
16:56:37.614 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config'
16:56:37.624 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
Bean1 构造方法
16:56:37.663 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
Bean2 构造方法
---------- 分割线 ----------
com.cys.demo02.TestBeanFactory$Bean2@49049a04
可以看到,bean的创建在分割线之前了,也就是这些单例bean被提前创建好了。
后置处理器顺序
处理是有顺序的,不同的顺序对解析结果影响也不同。
看如下一个例子:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InterfaceAddress;
import java.util.Map;
public class TestBeanFactoryPostProcessor {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建Config的BeanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
// 把beanDefinition注册到beanFactory
beanFactory.registerBeanDefinition("config", beanDefinition);
// 给beanFactory添加一些内置的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// 拿到beanFactory的后置处理器,这里有很多,其中一个就是internalConfigurationAnnotationProcessor
Map<String, BeanFactoryPostProcessor> processorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
// 执行后置处理器,当internalConfigurationAnnotationProcessor运行,就会把Bean1和Bean2的beanDefinition注册到beanFactory
processorMap.values().stream().forEach(processor -> {
processor.postProcessBeanFactory(beanFactory);
});
// Bean 的后处理器,针对Bean的生命周期的各个阶段提供扩展,例如@Autowired
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().forEach(beanFactory::addBeanPostProcessor);
// 查看beanFactory中beanDefinition的名字
// for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
// System.out.println(beanDefinitionName);
// }
// 主动创建单例bean
beanFactory.preInstantiateSingletons();
System.out.println("---------- 分割线 ----------");
// 获取Bean
Bean1 bean1 = beanFactory.getBean(Bean1.class);
System.out.println(bean1.getInter());
}
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
@Bean
public Bean3 bean3() {
return new Bean3();
}
@Bean
public Bean4 bean4() {
return new Bean4();
}
}
interface Inter {};
static class Bean3 implements Inter{};
static class Bean4 implements Inter{};
static class Bean1 {
public Bean1() {
System.out.println("Bean1 构造方法");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
@Autowired
private Inter inter;
public Inter getInter() {
return inter;
}
}
static class Bean2 {
public Bean2() {
System.out.println("Bean2 构造方法");
}
}
}
与前面不同的是,又重新定义了Bean3和Bean4,他们都实现了接口Inter,然后在Bean1中,使用了@Autowired注入一个Inter类型的Bean,由前面Spring的基础知识,我们知道,Autowired是根据诶行匹配的,由于Bean3和Bean4都实现了Inter,容器不知道到底是注入Bean3还是Bean4,会报错。
以前的解决办法可以使用@Qualifier("bean3")
指定注入bean3。除此以外,我们还可以直接修改Bean1中成员变量的名字,如下:
static class Bean1 {
public Bean1() {
System.out.println("Bean1 构造方法");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
@Autowired
private Inter bean3;
public Inter getInter() {
return bean3;
}
}
运行后发现这样也是可以的,这是因为容器当发现多个同一类型的bean时,容器会去比较成员变量的名字与bean的名字进行匹配,注入能够匹配名字的bean。
还有一种,如果使用@Resource,他也是按照类型匹配的,但是他有个name属性,可以指定注入的bean的名字:
static class Bean1 {
public Bean1() {
System.out.println("Bean1 构造方法");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
@Resource(name = "bean4")
private Inter bean3;
public Inter getInter() {
return bean3;
}
}
可以发现,最后注入的还是bean4。
那么问题来了,如果同时使用@Autowired和@Resource会怎么样呢?
static class Bean1 {
public Bean1() {
System.out.println("Bean1 构造方法");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
@Autowired
@Resource(name = "bean4")
private Inter bean3;
public Inter getInter() {
return bean3;
}
}
运行结果如下:
Bean1 构造方法
17:37:36.885 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
Bean2 构造方法
17:37:36.891 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
17:37:36.891 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean4'
---------- 分割线 ----------
com.cys.demo02.TestBeanFactoryPostProcessor$Bean3@506ae4d4
可以发现,最后结果是bean3,这是为什么呢?
这就和后置处理器的顺序有关了。由于AutowiredAnnotationBeanPostProcessor
是先添加到beanFactory,所以他先解析,后面的就不会再解析了。
代码验证,打印出顺序:
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建Config的BeanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
// 把beanDefinition注册到beanFactory
beanFactory.registerBeanDefinition("config", beanDefinition);
// 给beanFactory添加一些内置的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// 拿到beanFactory的后置处理器,这里有很多,其中一个就是internalConfigurationAnnotationProcessor
Map<String, BeanFactoryPostProcessor> processorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
// 执行后置处理器,当internalConfigurationAnnotationProcessor运行,就会把Bean1和Bean2的beanDefinition注册到beanFactory
processorMap.values().stream().forEach(processor -> {
processor.postProcessBeanFactory(beanFactory);
});
// Bean 的后处理器,针对Bean的生命周期的各个阶段提供扩展,例如@Autowired
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().forEach(processor -> {
System.out.println("processor:" + processor);
beanFactory.addBeanPostProcessor(processor);
});
// 主动创建单例bean
beanFactory.preInstantiateSingletons();
System.out.println("---------- 分割线 ----------");
// 获取Bean
Bean1 bean1 = beanFactory.getBean(Bean1.class);
System.out.println(bean1.getInter());
}
打印结果如下:
processor:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@49c7b90e
processor:org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@10d307f1
可以看到AutowiredAnnotationBeanPostProcessor先添加,然后是CommonAnnotationBeanPostProcessor
,CommonAnnotationBeanPostProcessor就是用来解析@Resource的。
我们也可以通过beanFactory的getDependencyComparator
方法改变后置处理器的顺序:
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().sorted(beanFactory.getDependencyComparator()).forEach(processor -> {
System.out.println("processor:" + processor);
beanFactory.addBeanPostProcessor(processor);
});
getDependencyComparator方法是由前面的AnnotationConfigUtils
工具类提供给beanFactory的:
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
// 省略代码
...
}
核心代码就是
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
也就是AnnotationAwareOrderComparator
public class AnnotationAwareOrderComparator extends OrderComparator {
/**
* Shared default instance of {@code AnnotationAwareOrderComparator}.
*/
public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
/**
* This implementation checks for {@link Order @Order} or
* {@link javax.annotation.Priority @Priority} on various kinds of
* elements, in addition to the {@link org.springframework.core.Ordered}
* check in the superclass.
*/
@Override
@Nullable
protected Integer findOrder(Object obj) {
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
return findOrderFromAnnotation(obj);
}
@Nullable
private Integer findOrderFromAnnotation(Object obj) {
AnnotatedElement element = (obj instanceof AnnotatedElement ? (AnnotatedElement) obj : obj.getClass());
MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY);
Integer order = OrderUtils.getOrderFromAnnotations(element, annotations);
if (order == null && obj instanceof DecoratingProxy) {
return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass());
}
return order;
}
// 省略代码
...
}
可以看到,它是一个单例对象,里面有findOrder
来获取处理器的顺序。
看下AutowiredAnnotationBeanPostProcessor
和CommonAnnotationBeanPostProcessor
都有个order
的属性和getOrder
的方法。CommonAnnotationBeanPostProcessor
的是在父类InitDestroyAnnotationBeanPostProcessorzh中。
总结
- beanFactory 可以通过 registerBeanDefinition 注册一个 BeanDefinition 对象
- 我们平时使用的配置类、xml、组件扫描等方式都是生成 BeanDefinition 对象注册到 beanFactory 当中
- BeanDefinition 描述了这个 bean 的创建蓝图:scope 是什么、用构造还是工厂创建、初始化销毁方法是什么,等等
- beanFactory 需要手动调用 beanFactory 后处理器对它做增强
- 例如通过解析 @Bean、@ComponentScan 等注解,来补充一些 BeanDefinition
- beanFactory 需要手动添加 bean 后处理器,以便对后续 bean 的创建过程提供增强
- 例如 @Autowired,@Resource 等注解的解析都是 bean 后处理器完成的
- bean 后处理的添加顺序会对解析结果有影响
- beanFactory 需要手动调用方法来初始化单例
因为beanFactory上面的一些局限性,一般我们使用ApplicationContext比较多,因为beanFactory需要手动做的事,他都帮我们自动做好了。
ApplicationContext实现
ApplicationContext
有4个比较典型的实现类ClassPathXmlApplicationContext
、FileSystemXmlApplicationContext
、AnnotationConfigApplicationContext
、‘AnnotationConfigServletWebServerApplicationContext’。
ClassPathXmlApplicationContext
ClassPathXmlApplicationContext
用于从类路径(classpath)中加载 XML 配置文件,进而创建和初始化 Spring 应用上下文(ApplicationContext)。当使用 ClassPathXmlApplicationContext
时,Spring 会自动从类路径中查找指定的 XML 配置文件,并根据该文件的配置创建和管理 Spring Beans。
类图如下
示例:
首先我们创建一个测试类:
public class TestApplicationContext {
public static void main(String[] args) {
}
static class Bean1 {
}
static class Bean2 {
private Bean1 bean1;
public Bean1 getBean1() {
return bean1;
}
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
}
}
里面定义了Bean1类和Bean2类,并且Bean2的属性有Bean1对象。
创建一个XML文件b01.xml
<?xml version="1.0" encoding="utf-8"?>
<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="bean1" class="com.cys.demo02.TestApplicationContext.Bean1"/>
<bean id="bean2" class="com.cys.demo02.TestApplicationContext.Bean2">
<property name="bean1" ref="bean1"/>
</bean>
</beans>
测试方法:
public static void main(String[] args) {
testClassPathXmlApplicationContext();
}
private static void testClassPathXmlApplicationContext() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("b01.xml");
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println("beanDefinitionName:" + beanDefinitionName);
}
// 获取bean2
Bean2 bean2 = context.getBean(Bean2.class);
System.out.println(bean2.getBean1());
}
结果如下:
beanDefinitionName:bean1
beanDefinitionName:bean2
com.cys.demo02.TestApplicationContext$Bean1@3e27aa33
需要注意的是,ClassPathXmlApplicationContext
在加载配置文件时会立即创建和初始化所有的单例 Bean。这意味着,如果你在配置文件中定义了一个单例 Bean,并且它有一个在初始化时执行的构造函数或 init-method
,那么当 ClassPathXmlApplicationContext
加载配置文件时,这个 Bean 的构造函数或 init-method
会被调用。
FileSystemXmlApplicationContext
FileSystemXmlApplicationContext
与ClassPathXmlApplicationContext类似,只不过他是读取系统中文件来,且文件位置不是相对于类路径了,而是绝对路径或者项目跟目录。这个用的很少。
示例:
public static void main(String[] args) {
testFileSystemXmlApplicationContext();
}
private static void testFileSystemXmlApplicationContext() {
// 注意些绝对路径,且要是双斜杠
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src//main//resources//b01.xml");
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println("beanDefinitionName:" + beanDefinitionName);
}
// 获取bean2
Bean2 bean2 = context.getBean(Bean2.class);
System.out.println(bean2.getBean1());
}
其结果一样。
AnnotationConfigApplicationContext
AnnotationConfigApplicationContext
用于加载基于 Java 配置类的应用程序上下文。与 ClassPathXmlApplicationContext
不同,AnnotationConfigApplicationContext
依赖于 Java 类(使用 @Configuration
注解)而不是 XML 文件来定义和配置 Spring Beans。
使用 AnnotationConfigApplicationContext
的主要好处是它可以利用 Java 的编译时类型检查,从而提供更强大的配置验证。此外,Java 配置通常更加简洁和灵活,因为它可以直接利用 Java 的编程能力,如条件配置、环境特定的配置等。
示例:
首先创建一个配置类:
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2(Bean1 bean1) {
Bean2 bean2 = new Bean2();
bean2.setBean1(bean1);
return bean2;
}
}
测试:
public static void main(String[] args) {
// testClassPathXmlApplicationContext();
testAnnotationConfigApplicationContext();
}
private static void testAnnotationConfigApplicationContext() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println("beanDefinitionName:" + beanDefinitionName);
}
// 获取bean2
Bean2 bean2 = context.getBean(Bean2.class);
System.out.println(bean2.getBean1());
}
结果如下:
beanDefinitionName:org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanDefinitionName:org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanDefinitionName:org.springframework.context.annotation.internalCommonAnnotationProcessor
beanDefinitionName:org.springframework.context.event.internalEventListenerProcessor
beanDefinitionName:org.springframework.context.event.internalEventListenerFactory
beanDefinitionName:testApplicationContext.Config
beanDefinitionName:bean1
beanDefinitionName:bean2
com.cys.demo02.TestApplicationContext$Bean1@6cb107fd
看到,成功创建了bean1和bean2,并把bean1注入了bean2。
另外上面五个后置处理器,也帮我们注册到了容器中。
AnnotationConfigServletWebServerApplicationContext
它是 AnnotationConfigApplicationContext
的一个子类,专门用于创建基于 Java 配置的 Servlet Web 应用程序上下文。这个类结合了 Spring Boot 的自动配置功能和 Spring MVC 的 Web 功能,使得开发者能够快速地创建和部署基于 Java 配置的 Web 应用程序。
AnnotationConfigServletWebServerApplicationContext
通常用于启动 Spring Boot 的 Web 应用程序。它会自动配置 Tomcat、Jetty 或 Undertow 等嵌入式 Web 服务器,并根据你在配置类中定义的 @Bean
和其他注解来创建和管理应用程序上下文。
示例:
使用时也需要指定配置类:
@Configuration
static class WebConfig {
/**
* tomcat服务器bean
*
* @return
*/
@Bean
public ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
/**
* dispatcherServlet的bean
*
* @return
*/
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
/**
* 绑定tomcat服务器和dispatcherServlet
*
* @param dispatcherServlet
* @return
*/
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
/**
* 控制器bean
*
* @return
*/
@Bean("/hello")
public Controller controller1() {
return new Controller() {
@Override
public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws Exception {
response.getWriter().println("hello");
return null;
}
};
}
}
测试:
public static void main(String[] args) {
// testClassPathXmlApplicationContext();
// testAnnotationConfigApplicationContext();
testAnnotationConfigServletWebServerApplicationContext();
}
private static void testAnnotationConfigServletWebServerApplicationContext() {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
}
启动后,访问http://127.0.0.1:8080/hello,正常就可以访问了。
如果启动出现这个错
exception is java.lang.NoClassDefFoundError: org/apache/catalina/WebResourceRoot
。这是因为缺少jar包,添加如下:<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> </dependency>
通过以上案例就可以大致了解一个web服务内部的核心组件,以及和tomcat的交互。