Spring5_03容器与bean(01-08)

165 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。


1.BeanFactory 与 ApplicationContext 的功能

1.1BeanFactory 与 ApplicationContext

image.png

/*
    BeanFactory 与 ApplicationContext 的区别
 */
@SpringBootApplication
public class A01 {

    private static final Logger log = LoggerFactory.getLogger(A01.class);

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {

        // 返回的就是spring容器:可配置的 ApplicationContext
        // ConfigurableApplicationContext 是 ApplicationContext的子接口
        // 通过option+command+U查看类图
        ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
        /*
            1. 到底什么是 BeanFactory
                - 它是 ApplicationContext 的父接口
                - 它才是 Spring 的核心容器, 主要的 ApplicationContext 实现【组合】了它的功能
         */
        // BeanFactory是ApplicationContext的一个成员变量
        System.out.println(context);
    }
}
  • (1)到底什么是 BeanFactory
    • 它是 ApplicationContext 的父接口
    • 它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能(BeanFactory是ApplicationContext的一个成员变量)

1.2BeanFactory 的功能 DefaultListableBeanFactory

command + f12 查看接口中的所有方法

image.png

image.png

  • (2)BeanFactory 能干点啥

    • 表面上只有 getBean
    • 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供(DefaultListableBeanFactory)
 public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
     ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
     System.out.println(context);
     Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
     singletonObjects.setAccessible(true);
     
     ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
     Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
     
     map.entrySet().stream().filter(e -> e.getKey().startsWith("component"))
             .forEach(e -> {
                 System.out.println(e.getKey() + "=" + e.getValue());
             });
 }
 
 // 注册的2个bean
 @Component
 public class Component1 {
     private static final Logger log = LoggerFactory.getLogger(Component1.class);
 }
 
 @Component
 public class Component2 {
     private static final Logger log = LoggerFactory.getLogger(Component2.class);
 }

打印结果

 component1=com.itheima.a01.Component1@4d8539de
 component2=com.itheima.a01.Component2@3eba57a7

1.3ApplicationContext的功能

  • (3)ApplicationContext 比 BeanFactory 多点啥(扩展的功能主要体现在继承的4个父接口上)⭐️

    • 多语言能力(国际化能力)
    • 通配符匹配资源的能力
    • 发布事件对象
    • 环境信息

功能1:多语言能力

 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));

存在的未解决的问题

Exception in thread "main" org.springframework.context.NoSuchMessageException: No message found under code 'hi' for locale 'zh_CN'.

功能2:匹配资源的能力

 Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
 for (Resource resource : resources) {
     System.out.println(resource);
 }

打印的结果

 URL [jar:file:/Users/cat/environment/repo/org/springframework/boot/spring-boot/2.5.5/spring-boot-2.5.5.jar!/META-INF/spring.factories]
 URL [jar:file:/Users/cat/environment/repo/org/springframework/boot/spring-boot-autoconfigure/2.5.5/spring-boot-autoconfigure-2.5.5.jar!/META-INF/spring.factories]
 URL [jar:file:/Users/cat/environment/repo/org/springframework/spring-beans/5.3.10/spring-beans-5.3.10.jar!/META-INF/spring.factories]

功能3:环境信息

 System.out.println(context.getEnvironment().getProperty("JAVA_8_HOME"));
 System.out.println(context.getEnvironment().getProperty("JAVA_11_HOME"));
 System.out.println(context.getEnvironment().getProperty("spring.messages.basename"));

打印的结果

 /Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home
 /Library/Java/JavaVirtualMachines/jdk-11.0.14.jdk/Contents/Home
 messages://messages_zh.properties

功能4:发布事件(如实现用户注册和发布事件的解耦)

 @EventListener
 public void aaa(UserRegisteredEvent event) {
     log.debug("{}", event);
     log.debug("发送短信");
 }

工作中的使用如下

基于自定义注解、AOP和Spring事件发布实现日志记录

总结一下

a. BeanFactory 与 ApplicationContext 并不仅仅是简单接口继承的关系, ApplicationContext 组合并扩展了 BeanFactory 的功能

b. 又新学一种代码之间解耦途径