- BeanFactory和ApplicationContext有什
- JAVA-每日一面 2022-01-16
- BeanFactory 和 ApplicationContext
- BeanFactory和ApplicationContext
- BeanFactory和ApplicationContext
- BeanFactory 和 ApplicationContext
- BeanFactory和ApplicationContext
- BeanFactory 和 ApplicationContext
- BeanFactory和ApplicationContext
- 简述BeanFactory和ApplicationContext
一、类图
@SpringBootApplication
public class SpringDemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringDemoApplication.class, args);
}
}


BeanFactory 接口
- 典型功能有:getBean
ApplicationContext 接口
是 BeanFactory 的子接口。它扩展了 BeanFactory 接口的功能,如:
- 国际化
- 通配符方式获取一组 Resource 资源
- 整合 Environment 环境(能通过它获取各种来源的配置信息)
- 事件发布与监听,实现组件之间的解耦
二、ApplicationContext
DefaultSingletonBeanRegistry:管理所有的单例对象
@SpringBootApplication
public class SpringDemoApplication {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringDemoApplication.class, args);
/*
BeanFactory:
- 表面上只有 getBean
- 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供
*/
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
singletonObjects.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
map.entrySet().forEach(e -> System.out.println(e.getKey() + "=" + e.getValue()));
}
}
1.国际化
public class TestMessageSource {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("messageSource", MessageSource.class, () -> {
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
ms.setDefaultEncoding("utf-8");
ms.setBasename("messages");
return ms;
});
context.refresh();
System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
System.out.println(context.getMessage("hi", null, Locale.CHINESE));
System.out.println(context.getMessage("hi", null, Locale.JAPANESE));
}
}
- ApplicationContext 中 MessageSource bean 的名字固定为 messageSource
- 使用 SpringBoot 时,国际化文件名固定为 messages
- 空的 messages.properties 也必须存在
- 国际化文件均在 src/resources 目录下
2.通配符方式获取一组 Resource 资源
@SpringBootApplication
public class SpringDemoApplication {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringDemoApplication.class, args);
Resource[] resources = applicationContext.getResources("classpath*:META-INF/spring.factories");
for (Resource resource : resources) {
System.out.println(resource);
}
}
}
URL [jar:file:/Users/hongcaixia/Documents/work/repository/org/springframework/boot/spring-boot/2.5.6/spring-boot-2.5.6.jar!/META-INF/spring.factories]
URL [jar:file:/Users/hongcaixia/Documents/work/repository/org/springframework/spring-beans/5.3.12/spring-beans-5.3.12.jar!/META-INF/spring.factories]
URL [jar:file:/Users/hongcaixia/Documents/work/repository/org/springframework/boot/spring-boot-autoconfigure/2.5.6/spring-boot-autoconfigure-2.5.6.jar!/META-INF/spring.factories]
3.EnvironmentCapable:获取配置信息
@SpringBootApplication
public class SpringDemoApplication {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringDemoApplication.class, args);
System.out.println(applicationContext.getEnvironment().getProperty("JAVA_HOME"));
System.out.println(applicationContext.getEnvironment().getProperty("server.port"));
}
}
4.发布事件:ApplicationEventPublisher
发布者:
@SpringBootApplication
public class SpringDemoApplication {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringDemoApplication.class, args);
applicationContext.publishEvent(new UserRegisteredEvent(applicationContext));
}
}
public class UserRegisteredEvent extends ApplicationEvent {
public UserRegisteredEvent(Object source) {
super(source);
}
}
订阅者:
@Component
public class SubComponent {
private static final Logger log = LoggerFactory.getLogger(SubComponent.class);
@EventListener
public void sub(UserRegisteredEvent event) {
log.debug("订阅:{}", event);
}
}
2023-12-11 10:43:03.772 INFO 89813 --- [ main] com.hcx.springdemo.SubComponent : 订阅:com.hcx.springdemo.UserRegisteredEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@477b4cdf, started on Mon Dec 11 10:43:03 CST 2023]
三、BeanFactory的实现
DefaultListableBeanFactory:
package com.hcx.springdemo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 org.springframework.core.Ordered;
import javax.annotation.Resource;
public class BeanFactoryTest {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 的定义(class, scope, 初始化, 销毁)
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition("config", beanDefinition);
// 给 BeanFactory 添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// BeanFactory 后处理器主要功能,补充了一些 bean 定义
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
//执行bean工厂的后置处理器
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
.sorted(beanFactory.getDependencyComparator())
.forEach(beanPostProcessor -> {
System.out.println(">>>>" + beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
// 提前创建好所有的单例bean
beanFactory.preInstantiateSingletons();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
// System.out.println(beanFactory.getBean(Bean1.class).getBean2());
System.out.println(beanFactory.getBean(Bean1.class).getInter());
/*
beanFactory 不会做的事
1. 不会主动调用 BeanFactory 后处理器
2. 不会主动添加 Bean 后处理器
3. 不会主动初始化单例
4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }
bean 后处理器会有排序的逻辑
*/
System.out.println("Common:" + (Ordered.LOWEST_PRECEDENCE - 3));
System.out.println("Autowired:" + (Ordered.LOWEST_PRECEDENCE - 2));
}
@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 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() {
log.debug("构造 Bean1()");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
@Autowired
@Resource(name = "bean4")
private Inter bean3;
public Inter getInter() {
return bean3;
}
}
static class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("构造 Bean2()");
}
}
}
- beanFactory 可以通过 registerBeanDefinition 注册一个 bean definition 对象
配置类、xml、组件扫描等方式都是生成 bean definition 对象注册到 beanFactory 当中
bean definition 描述了这个 bean 的创建蓝图:scope 是什么、用构造还是工厂创建、初始化销毁方法是什么,等等 - beanFactory 需要手动调用 beanFactory 后处理器对它做增强
通过解析 @Bean、@ComponentScan 等注解,来补充一些 bean definition - beanFactory 需要手动添加 bean 后处理器,以便对后续 bean 的创建过程提供增强
@Autowired,@Resource 等注解的解析都是 bean 后处理器完成的
bean 后处理的添加顺序会对解析结果有影响,@Autowired,@Resource 等 - beanFactory 需要手动调用方法来初始化单例
- beanFactory 需要额外设置才能解析 ${} 与 #{}
四、ApplicationContext 实现
- ClassPathXmlApplicationContext:基于classpath下 xml 格式的配置文件来创建
- FileSystemXmlApplicationContext:基于磁盘路径下 xml 格式的配置文件来创建
- AnnotationConfigApplicationContext:基于 java 配置类来创建
- AnnotationConfigServletWebServerApplicationContext: 基于 java 配置类来创建, 用于 web 环境
package com.hcx.springdemo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.Controller;
/*
常见 ApplicationContext 实现
*/
public class ApplicationContextTest {
private static final Logger log = LoggerFactory.getLogger(ApplicationContextTest.class);
public static void main(String[] args) {
// 1.基于 classpath 下 xml 格式的配置文件来创建
testClassPathXmlApplicationContext();
// 2..基于磁盘路径下 xml 格式的配置文件来创建
testFileSystemXmlApplicationContext();
//ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext 相当于:在beanFactory上进行的如下增强
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println("读取之前...");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println("读取之后...");
// 把bean标签转换成bean定义,将读取结果放入beanFactory
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// 读取
reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\a02.xml"));
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
// 3.基于 java 配置类来创建
testAnnotationConfigApplicationContext();
// 4.基于 java 配置类来创建, 用于 web 环境
testAnnotationConfigServletWebServerApplicationContext();
}
// 1.️较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建
private static void testClassPathXmlApplicationContext() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("a02.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
// 2.基于磁盘路径下 xml 格式的配置文件来创建
private static void testFileSystemXmlApplicationContext() {
// 绝对路径或者相对路径
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src\\main\\resources\\a02.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
// 3.较为经典的容器, 基于 java 配置类来创建;已经加好了对应的后置处理器
private static void testAnnotationConfigApplicationContext() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
// 4.️较为经典的容器, 基于 java 配置类来创建, 用于 web 环境
private static void testAnnotationConfigServletWebServerApplicationContext() {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
}
@Configuration
static class WebConfig {
@Bean
public ServletWebServerFactory servletWebServerFactory(){
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean("/hello")
public Controller controller1() {
return (request, response) -> {
response.getWriter().print("hello");
return null;
};
}
}
/**
* 配置类也是一个bean
*/
@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;
}
}
static class Bean1 {
}
static class Bean2 {
private Bean1 bean1;
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
public Bean1 getBean1() {
return bean1;
}
}
}
网友评论