BeanFactory是 ApplicationContext 的父接口,它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能

另一方面,BeanFactory是ApplicationContext一个成员变量

表面上只有 getBean,实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供
applicationContext对beanfactory的功能拓展主要体现在四个扩展接口:MessageSource(国际化)、ResourcePatternResolver(通配符方式获取一组 Resource 资源 )、ApplicationEventPublisher(事件发布与监听,实现组件之间的解耦 )、EnvironmentCapable上(整合 Environment 环境(能通过它获取各种来源的配置信息))
- System.out.println(context.getMessage("hi", null, Locale.CHINA));
- System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
- System.out.println(context.getMessage("hi", null, Locale.JAPANESE));
可以通过浏览器的请求头获取这个信息 ,根据用户的使用需求返回规定的语言
通过通配符获取一系列资源。
- Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
- for (Resource resource : resources) {
- System.out.println(resource);
- }
获取来自环境变量或者properties配置文件的配置信息。
- System.out.println(context.getEnvironment().getProperty("java_home"));
- System.out.println(context.getEnvironment().getProperty("server.port"));
用于发布或者监听事件,spring中任何一个组件都可以作为监听器
- //发布事件
- context.publishEvent(new UserRegisteredEvent(context));
-
-
- //监听事件
- @EventListener
- public void aaa(UserRegisteredEvent event) {
- log.debug("{}", event);
- log.debug("发送短信");
- }
事件可以用于解耦功能,比如,对于一个注册功能,在注册成功之后可能需要发送短信、可能需要返回信息,可能两者都需要,不同的业务或者使用场景会有不一样的使用要求,这时候就不能在一个方法里面吧注册功能写死了,可以发事件:先获取事件发布器,然后发布事件
- @Autowired
- private ApplicationEventPublisher context;
-
- public void register() {
- log.debug("用户注册");
- context.publishEvent(new UserRegisteredEvent(this));
- }
接着另一个业务监听到事件之后就去执行相应的业务,做到注册功能和后续功能的解耦合。
- @EventListener
- public void aaa(UserRegisteredEvent event) {
- log.debug("{}", event);
- log.debug("发送短信");
- }
BeanFactory的实现之一:DefaultListableBeanFactory,这个实现获得的对象是一个bean容器,先创建一个实例对象得到spring核心容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
一开始创建好里面是没有任何的bean的,所以需要给这个BeanFactory添加一些bean的定义,不是直接添加对象,因为对象是BeanFactory帮你创建的,所以你需要告诉的是bean的信息,bean 的定义(class, scope, 初始化, 销毁),再有BeanFactory根据定义创建对象。
例如,我们有如下的类和类的依赖引用关系
- @Configuration
- static class Config {
- @Bean
- public Bean1 bean1() {
- return new Bean1();
- }
-
- @Bean
- public Bean2 bean2() {
- return new Bean2();
- }
-
-
- }
- 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;
- }
-
- }
-
- static class Bean2 {
- private static final Logger log = LoggerFactory.getLogger(Bean2.class);
-
- public Bean2() {
- log.debug("构造 Bean2()");
- }
- }
- }
- AbstractBeanDefinition beanDefinition =
- BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
- beanFactory.registerBeanDefinition("config", beanDefinition);
这一段代码是创建了一个config类的bean,并且把这个bean放到了bean容器beanFactory中,通过打印bean容器发现此时容器里只有一个config对象的信息,并没有把bean1和bean2的信息加入到容器中,即没有解析config类中的注解,是因为解析注解并不是有BeanDefinition完成,需要另外一个工具类——BeanFactory后处理器,后处理器可以扩展beanfactory功能,例如解析注解
先把常用的后处理器放入bean工厂,让bean工厂有这么些个bean,但是如果要用到这些后处理器还需要建立这些处理器与beanFactory的联系并执行。
- // 给 BeanFactory 添加一些常用的后处理器
- AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
添加后处理器之后需要运行该后处理器:因为处理器是beanfactory对象,所以要先把这些对象获取了,然后再去执行
- // BeanFactory 后处理器主要功能,补充了一些 bean 定义
- beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
- beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
- });
此时去打印beanFactory中的bean就可以发现里面是把bean1和bean2的信息也创建并加入进容器了。
这时候根据getBean(Bean1.class).getBean2()会发现返回值是一个null,即Bean1类中的@Autowired注解失效 ,没有创建出bean2对象这个依赖注解还需要Bean后处理器来解决。
- // Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
- beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
- .sorted(beanFactory.getDependencyComparator())
- .forEach(beanPostProcessor -> {
- System.out.println(">>>>" + beanPostProcessor);
- beanFactory.addBeanPostProcessor(beanPostProcessor);
- });
因为beanFactory一开始只是在容器中存放各个bean的信息,只有当getBean的时候才会去创建bean对象,而有时候我们为了性能考虑会像提前把bean对象创建好,这时候就可以用到下面这个方法
beanFactory.preInstantiateSingletons(); // 准备好所有单例
1. 不会主动调用 BeanFactory 后处理器
2. 不会主动添加 Bean 后处理器
3. 不会主动初始化单例
4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }
四个比较经典的实现类:
到类路径下读取配置文件
- // ⬇️较为经典的容器, 基于 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());
- }
- // ⬇️基于磁盘路径下 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());
- }
上面这两个类的实现原理是借助了DefaultListableBeanFactory,读取xml文件,把读取到的bean信息形成bean放入bean工厂里面
- DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
- System.out.println("读取之前...");
- for (String name : beanFactory.getBeanDefinitionNames()) {
- System.out.println(name);
- }
- System.out.println("读取之后...");
- XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
- reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\a02.xml"));
- for (String name : beanFactory.getBeanDefinitionNames()) {
- System.out.println(name);
- }
基于注解配置的实现
- private static void testAnnotationConfigServletWebServerApplicationContext() {
- AnnotationConfigServletWebServerApplicationContext context =
- new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
- for (String name : context.getBeanDefinitionNames()) {
- System.out.println(name);
- }
- }
-
-
- @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;
- }
- }
较为经典的容器, 基于 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;
- };
- }
- }