Spring 容器接口

ApplicationContext和BeanFactory关系

继承

类图
类图
ApplicationContext是BeanFactory的子接口

组合

在ApplicationContext具体的实现类里,通常都组合了BeanFactory的功能
notion image
如上所示
 
 

BeanFactory 作用

  • 表面上只有 getBean
    • notion image
  • 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供
DefaultListableBeanFactory 的类图
notion image
DefaultSingletonBeanRegistry 的成员变量singletonObjects存放所有单例对象kv关系
notion image
案例
利用反射机制获取beanFactory的singletonObjects 字段值
@Component public class Component1 { private static final Logger log = LoggerFactory.getLogger(Component1.class); @Autowired private ApplicationEventPublisher context; public void register() { log.debug("用户注册"); context.publishEvent(new UserRegisteredEvent(this)); } }
@Component public class Component2 { private static final Logger log = LoggerFactory.getLogger(Component2.class); @EventListener public void aaa(UserRegisteredEvent event) { log.debug("{}", event); log.debug("发送短信"); } }
ConfigurableApplicationContext context = SpringApplication.run(A01.class, args); 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()); });
notion image

ApplicationContext的扩展

notion image
类图中额外继承的接口就是ApplicationContext的扩展功能

国际化 MessageSource

ApplicationContext 接口扩展了一个名为 MessageSource 的接口,因此提供了国际化(“i18n”)功能。
MessageSource 接口定义和主要方法如下
public interface MessageSource { // 获取消息: code消息key args替换内支持{} default默认值 loc语言 String getMessage(String code, Object[] args, String default, Locale loc); String getMessage(String code, Object[] args, Locale loc) String getMessage(String code, Object[] args, Locale loc) }
 
在resources目录下新建messages.properties文件
messages_en.properties
hi=Hello
messages_ja.properties
hi=こんにちは
messages_zh.properties
hi=你好
notion image
调用getMessage方法
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));
notion image
  • ApplicationContext 中 MessageSource bean 的名字固定为 messageSource
  • 使用 SpringBoot 时,国际化文件名固定为 messages
  • 空的 messages.properties 也必须存在
 

ResourceLoader 访问资源

• 通过 ResourceLoader 接口访问资源,例如 URL 和文件
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories"); for (Resource resource : resources) { System.out.println(resource); }
 
URL [file:/E:/study/spring/spring-framwork/show/target/classes/META-INF/spring.factories] URL [jar:file:/E:/evn/maven/maven_repository/org/springframework/boot/spring-boot/2.5.5/spring-boot-2.5.5.jar!/META-INF/spring.factories] URL [jar:file:/E:/evn/maven/maven_repository/org/springframework/boot/spring-boot-autoconfigure/2.5.5/spring-boot-autoconfigure-2.5.5.jar!/META-INF/spring.factories] URL [jar:file:/E:/evn/maven/maven_repository/org/springframework/spring-beans/5.3.10/spring-beans-5.3.10.jar!/META-INF/spring.factories] URL [jar:file:/E:/evn/maven/maven_repository/org/mybatis/spring/boot/mybatis-spring-boot-autoconfigure/2.2.0/mybatis-spring-boot-autoconfigure-2.2.0.jar!/META-INF/spring.factories] URL [jar:file:/E:/evn/maven/maven_repository/com/alibaba/druid-spring-boot-starter/1.2.8/druid-spring-boot-starter-1.2.8.jar!/META-INF/spring.factories] URL [jar:file:/E:/evn/maven/maven_repository/org/springframework/spring-test/5.3.10/spring-test-5.3.10.jar!/META-INF/spring.factories]

EnvironmentCapable获取环境变量

System.out.println(context.getEnvironment().getProperty("java_home")); System.out.println(context.getEnvironment().getProperty("server.port"));
 
notion image

ApplicationListener事件机制

 
  1. 继承ApplicationEvent 自定义事件
    1. public class UserRegisteredEvent extends ApplicationEvent { public UserRegisteredEvent(Object source) { super(source); } }
  1. context.publishEvent() 发布事件
    1. @Component public class Component1 { private static final Logger log = LoggerFactory.getLogger(Component1.class); @Autowired private ApplicationEventPublisher context; public void register() { log.debug("用户注册"); context.publishEvent(new UserRegisteredEvent(this)); } }
  1. @EventListener监听事件
    1. @Component public class Component2 { private static final Logger log = LoggerFactory.getLogger(Component2.class); @EventListener public void aaa(UserRegisteredEvent event) { log.debug("{}", event); log.debug("发送短信"); } }
  1. 测试 context.getBean(Component1.class).register();
[DEBUG] 17:09:30.963 [main] com.onethink.a01.Component1 - 用户注册 [DEBUG] 17:09:30.964 [main] com.onethink.a01.Component2 - com.onethink.a01.UserRegisteredEvent[source=com.onethink.a01.Component1@415795f3] [DEBUG] 17:09:30.964 [main] com.onethink.a01.Component2 - 发送短信