Spring 高级
1 容器与Bean
1.1 接口容器
1.1.1 BeanFactory是什么
@SpringBootApplication
public class ShowApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ShowApplication.class, args);
/**
* 1、到底什么是 BeanFactory
* - 它是 ApplicationContext 的父接口
* - 它才是 Spring 的核心容器,主要的 ApplicationContext 实现 【组合】 了它的功能
*/
System.out.println(context);
}
}
1.1.2 BeanFactory作用
@SpringBootApplication
public class ShowApplication {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
ConfigurableApplicationContext context = SpringApplication.run(ShowApplication.class, args);
/**
BeanFactory 能干点啥
- 表面上只有 getBean
- 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能,都由它的实现类提供
- 例子中通过反射查看了它的成员变量 singletonObjects,内部包含了所有的单例 bean
*/
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()));
}
}
1.1.3 applicationContext和BeanFactory比较
@SpringBootApplication
public class ShowApplication {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
ConfigurableApplicationContext context = SpringApplication.run(ShowApplication.class, args);
/**
* 3、applicationContext 比 BeanFactory 多点啥
- ApplicationContext 组合并扩展了 BeanFactory 的功能
- 国际化、通配符方式获取一组 Resource 资源、整合 Environment 环境、事件发布与监听
- 新学一种代码之间解耦途径,事件解耦
*/
//context.getMessage("hello",null, Locale.CHINA);//国际化
//classpath* 加一个* 代表去jar包中找
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");//资源加载
for (Resource resource : resources) {
System.out.println(resource);
}
//获取环境变量,不区分大小写
System.out.println(context.getEnvironment().getProperty("java_home"));
}
}
1.1.4 事件处理
事件处理: 实现组件之间的解耦
UserRegisteredEvent
public class UserRegisteredEvent extends ApplicationEvent {
//事件,source: 事件源
public UserRegisteredEvent(Object source) {
super(source);
}
}
@SpringBootApplication
public class ShowApplication {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
ConfigurableApplicationContext context = SpringApplication.run(ShowApplication.class, args);
context.publishEvent(new UserRegisteredEvent(context));//发送事件
}
}
@Component
public class Component2 {
private static final Logger log= LoggerFactory.getLogger(Component2.class);
@EventListener
public void aaa(UserRegisteredEvent event){
System.out.println(event);
}
}
@Component
public class Component1 {
private static final Logger log= LoggerFactory.getLogger(Component1.class);
@Autowired
public ApplicationEventPublisher context;
public void register(){
log.info("用户注册");
context.publishEvent(new UserRegisteredEvent(this));
}
}
@Component
public class Component2 {
private static final Logger log= LoggerFactory.getLogger(Component2.class);
@EventListener
public void aaa(UserRegisteredEvent event){
System.out.println(event);
log.info("发送短信");
}
}
@SpringBootApplication
public class ShowApplication {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
ConfigurableApplicationContext context = SpringApplication.run(ShowApplication.class, args);
context.getBean(Component1.class).register();
}
}
1.2 容器实现
Spring 的发展历史较为悠久,因此很多资料还在讲解它较旧的实现,这里出于怀旧的原因,把它们都列出来,供大家参考
- DefaultListableBeanFactory,是 BeanFactory 最重要的实现,像控制反转和依赖注入功能,都是它来实现
- ClassPathXmlApplicationContext,从类路径查找 XML 配置文件,创建容器(旧)
- FileSystemXmlApplicationContext,从磁盘路径查找 XML 配置文件,创建容器(旧)
- XmlWebApplicationContext,传统 SSM 整合时,基于 XML 配置文件的容器(旧)
- AnnotationConfigWebApplicationContext,传统 SSM 整合时,基于 java 配置类的容器(旧)
- AnnotationConfigApplicationContext,Spring boot 中非 web 环境容器(新)
- AnnotationConfigServletWebServerApplicationContext,Spring boot 中 servlet web 环境容器(新)
- AnnotationConfigReactiveWebServerApplicationContext,Spring boot 中 reactive web 环境容器(新)
另外要注意的是,后面这些带有 ApplicationContext 的类都是 ApplicationContext 接口的实现,但它们是组合了 DefaultListableBeanFactory 的功能,并非继承而来
1.2.1 DefaultListableBeanFactory
package com.feng.beanfactory02;
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.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;
public class TestBeanFactory {
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);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}//结果只有config一个,发现 @Configuration 没有生效
System.out.println("===========================");
//给 BeanFactory 添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println("===========================");
//org.springframework.context.annotation.internalConfigurationAnnotationProcessor 让@Configuration生效
//BeanFactory 后处理器主要功能,补充了一些bean定义
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values()
.stream().forEach(beanFactoryPostProcessor -> beanFactoryPostProcessor.postProcessBeanFactory(beanFactory));
//当执行到internalConfigurationAnnotationProcessor时,就会解析 @Configuration下的@Bean
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
}
@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.info("构造 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.info("构造 Bean2()");
}
}
}
System.out.println("===========================");
//Bean 后处理器,针对bean的生命周期的各个阶段提供扩展,例如@Autowired @Resource ...
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
//Bean 后处理器,针对bean的生命周期的各个阶段提供扩展,例如@Autowired @Resource ...
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
beanFactory.preInstantiateSingletons();//提前准备好所有的单例(不加这句代码,默认是只会保存类的信息,只有getBean的时候才会创建实例)
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
/**
学到了什么:
a.beanFactory不会做的事
1.不会主动调用BeanFactory 后处理器
2.不会主动添加Bean 后处理器
3.不会主动初始化单例
4.不会解析beanFactory 还不会解析 ${} 与 #{}
b.bean后处理器会有排序的逻辑 (@Autowired排在@Resource前面,所以会先注入)
*/