ApplicationContext和BeanFactory关系
继承
ApplicationContext是BeanFactory的子接口
组合
在ApplicationContext具体的实现类里,通常都组合了BeanFactory的功能
如上所示
BeanFactory 作用
- 表面上只有 getBean
- 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供
DefaultListableBeanFactory
的类图DefaultSingletonBeanRegistry
的成员变量singletonObjects
存放所有单例对象kv关系案例
利用反射机制获取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()); });
ApplicationContext的扩展
类图中额外继承的接口就是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=你好 |
调用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));
- 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"));
ApplicationListener事件机制
- 继承
ApplicationEvent
自定义事件
public class UserRegisteredEvent extends ApplicationEvent { public UserRegisteredEvent(Object source) { super(source); } }
context.publishEvent()
发布事件
@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)); } }
@EventListener
监听事件
@Component public class Component2 { private static final Logger log = LoggerFactory.getLogger(Component2.class); @EventListener public void aaa(UserRegisteredEvent event) { log.debug("{}", event); log.debug("发送短信"); } }
- 测试
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 - 发送短信