推荐先阅读
:Spring全家桶
本篇乃个人笔记,系统学习请转步:Spring高级49讲
容器与 bean
容器接口
BeanFactory 与 ApplicationContext 的区别
- BeanFactory 是 ApplicationContext 的父接口
- BeanFactory 是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能。
- BeanFactory 控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能,都由它的实现类提供
- ApplicationContext 组合并扩展了 BeanFactory 的功能
- 国际化、通配符方式获取一组 Resource 资源、整合 Environment 环境、事件发布与监听
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()); });
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); }
System.out.println(context.getEnvironment().getProperty("java_home")); System.out.println(context.getEnvironment().getProperty("server.port"));
context.getBean(Component1.class).register();
|
注意
- 如果 jdk > 8, 运行时请添加 –add-opens java.base/java.lang=ALL-UNNAMED,这是因为这些版本的 jdk 默认不允许跨 module 反射
- 事件发布还可以异步,请自行查阅 @EnableAsync,@Async 的用法
用户注册与发送短信之间的解耦(事件方式实现)
@Component public class Component1 { private static final Logger log = LoggerFactory.getLogger(Component1.class);
@Autowired private 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) { log.debug("{}", event); log.info("发送短信"); } }
|
public class UserRegisteredEvent extends ApplicationEvent { public UserRegisteredEvent(Object source) { super(source); } }
|
国际化
public class TestMessageSource { public static void main(String[] args) { GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("messageSource", MessageSource.class, () -> { ResourceBundleMessageSource ms = new ResourceBundleMessageSource(); ms.setDefaultEncoding("utf-8"); ms.setBasename("messages"); return ms; });
context.refresh();
System.out.println(context.getMessage("hi", null, Locale.ENGLISH)); System.out.println(context.getMessage("hi", null, Locale.CHINESE)); System.out.println(context.getMessage("hi", null, Locale.JAPANESE)); } }
|
注意
- ApplicationContext 中 MessageSource bean 的名字固定为 messageSource
- 使用 SpringBoot 时,国际化文件名固定为 messages
- 空的 messages.properties 也必须存在
容器实现
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 的功能,并非继承而来。
DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class) .setScope("singleton").getBeanDefinition(); beanFactory.registerBeanDefinition("config", beanDefinition);
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> { beanFactoryPostProcessor.postProcessBeanFactory(beanFactory); });
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream() .sorted(beanFactory.getDependencyComparator()) .forEach(beanPostProcessor -> { System.out.println(">>>>" + beanPostProcessor); beanFactory.addBeanPostProcessor(beanPostProcessor); });
for (String name : beanFactory.getBeanDefinitionNames()) { System.out.println(name); }
beanFactory.preInstantiateSingletons(); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
System.out.println(beanFactory.getBean(Bean1.class).getInter());
System.out.println("Common:" + (Ordered.LOWEST_PRECEDENCE - 3)); System.out.println("Autowired:" + (Ordered.LOWEST_PRECEDENCE - 2));
|
- beanFactory 可以通过 registerBeanDefinition 注册一个 bean definition 对象
- 我们平时使用的配置类、xml、组件扫描等方式都是生成 bean definition 对象注册到 beanFactory 当中
- bean definition 描述了这个 bean 的创建蓝图:scope 是什么、用构造还是工厂创建、初始化销毁方法是什么,等等
- beanFactory 需要手动调用 beanFactory 后处理器对它做增强
- 例如通过解析 @Bean、@ComponentScan 等注解,来补充一些 bean definition
- beanFactory 需要手动添加 bean 后处理器,以便对后续 bean 的创建过程提供增强
- 例如 @Autowired,@Resource 等注解的解析都是 bean 后处理器完成的
- bean 后处理的添加顺序会对解析结果有影响.
- beanFactory 需要手动调用方法来初始化单例
- beanFactory 需要额外设置才能解析 ${} 与 #{}
- bean 后处理器会有排序的逻辑
ClassPathXmlApplicationContext
较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("a02.xml"); context.getBean(Bean2.class).getBean1();
|
内部实现:
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\a02.xml")); for (String name : beanFactory.getBeanDefinitionNames()) { System.out.println(name); }
|
FileSystemXmlApplicationContext
基于磁盘路径下 xml 格式的配置文件来创建
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src\\main\\resources\\a02.xml");
|
AnnotationConfigApplicationContext
️较为经典的容器, 基于 java 配置类来创建
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
|
AnnotationConfigServletWebServerApplicationContext
较为经典的容器, 基于 java 配置类来创建, 用于 web 环境
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
|
Bean 的生命周期
一个受 Spring 管理的 bean,生命周期主要阶段有
- 创建:根据 bean 的构造方法或者工厂方法来创建 bean 实例对象
- 依赖注入:根据 @Autowired,@Value 或其它一些手段,为 bean 的成员变量填充值、建立关系
- 初始化:回调各种 Aware 接口,调用对象的各种初始化方法
- 销毁:在容器关闭时,会销毁所有单例对象(即调用它们的销毁方法)
- prototype 对象也能够销毁,不过需要容器这边主动调用
一些资料会提到,生命周期中还有一类 bean 后处理器:BeanPostProcessor,会在 bean 的初始化的前后,提供一些扩展逻辑。
但这种说法是不完整的,见下面的演示1: bean 生命周期
bean 生命周期
@SpringBootApplication public class A03 { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A03.class, args); context.close(); } }
|
@Component public class LifeCycleBean { private static final Logger log = LoggerFactory.getLogger(LifeCycleBean.class);
public LifeCycleBean() { log.debug("构造"); }
@Autowired public void autowire(@Value("${JAVA_HOME}") String home) { log.debug("依赖注入: {}", home); }
@PostConstruct public void init() { log.debug("初始化"); }
@PreDestroy public void destroy() { log.debug("销毁"); } }
|
@Component public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor { private static final Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);
@Override public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) log.debug("<<<<<< 销毁之前执行, 如 @PreDestroy"); }
@Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) log.debug("<<<<<< 实例化之前执行, 这里返回的对象会替换掉原本的 bean"); return null; }
@Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) { log.debug("<<<<<< 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段");
} return true; }
@Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) log.debug("<<<<<< 依赖注入阶段执行, 如 @Autowired、@Value、@Resource"); return pvs; }
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) log.debug("<<<<<< 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties"); return bean; }
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) log.debug("<<<<<< 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强"); return bean; } }
|
输出内容:
<<<<<< 实例化之前执行, 这里返回的对象会替换掉原本的 bean 构造 <<<<<< 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段 <<<<<< 依赖注入阶段执行, 如 @Autowired、@Value、@Resource 依赖注入: 成功 <<<<<< 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties 初始化 <<<<<< 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强 LiveReload server is running on port 35729 Started TestApplication in 0.345 seconds (JVM running for 0.814) <<<<<< 销毁之前执行, 如 @PreDestroy 销毁
|
模板方法设计模式
public class TestMethodTemplate { public static void main(String[] args) { MyBeanFactory beanFactory = new MyBeanFactory(); beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired")); beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource")); beanFactory.getBean(); }
static class MyBeanFactory { public Object getBean() { Object bean = new Object(); System.out.println("构造 " + bean); System.out.println("依赖注入 " + bean); for (BeanPostProcessor processor : processors) { processor.inject(bean); } System.out.println("初始化 " + bean); return bean; }
private List<BeanPostProcessor> processors = new ArrayList<>();
public void addBeanPostProcessor(BeanPostProcessor processor) { processors.add(processor); } }
static interface BeanPostProcessor { public void inject(Object bean); } }
|
输出内容:
构造 java.lang.Object@73f792cf 依赖注入 java.lang.Object@73f792cf 解析 @Autowired 解析 @Resource 初始化 java.lang.Object@73f792cf
|
bean 后处理器排序
public class TestProcessOrder {
public static void main(String[] args) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
List<BeanPostProcessor> list = new ArrayList<>(List.of(new P1(), new P2(), new P3(), new P4(), new P5())); list.sort(beanFactory.getDependencyComparator());
list.forEach(processor->{ processor.postProcessBeforeInitialization(new Object(), ""); }); }
@Order(1) static class P1 implements BeanPostProcessor { private static final Logger log = LoggerFactory.getLogger(P1.class);
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { log.debug("postProcessBeforeInitialization @Order(1)"); return bean; } }
@Order(2) static class P2 implements BeanPostProcessor { private static final Logger log = LoggerFactory.getLogger(P2.class);
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { log.debug("postProcessBeforeInitialization @Order(2)"); return bean; }
}
static class P3 implements BeanPostProcessor, PriorityOrdered { private static final Logger log = LoggerFactory.getLogger(P3.class);
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { log.debug("postProcessBeforeInitialization PriorityOrdered"); return bean; }
@Override public int getOrder() { return 100; } }
static class P4 implements BeanPostProcessor, Ordered { private static final Logger log = LoggerFactory.getLogger(P4.class);
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { log.debug("postProcessBeforeInitialization Ordered"); return bean; }
@Override public int getOrder() { return 0; } }
static class P5 implements BeanPostProcessor { private static final Logger log = LoggerFactory.getLogger(P5.class);
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { log.debug("postProcessBeforeInitialization"); return bean; } } }
|
收获
- 实现了 PriorityOrdered 接口的优先级最高
- 实现了 Ordered 接口与加了 @Order 注解的平级, 按数字升序
- 其它的排在最后
Bean 后处理器
作用
public class A04 { public static void main(String[] args) { GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1", Bean1.class); context.registerBean("bean2", Bean2.class); context.registerBean("bean3", Bean3.class); context.registerBean("bean4", Bean4.class);
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); context.registerBean(AutowiredAnnotationBeanPostProcessor.class); context.registerBean(CommonAnnotationBeanPostProcessor.class);
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
context.refresh();
System.out.println(context.getBean(Bean1.class));
context.close(); } }
|
收获
- @Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能,这些扩展功能由 bean 后处理器来完成
- 每个后处理器各自增强什么功能
- AutowiredAnnotationBeanPostProcessor 解析 @Autowired 与 @Value
- CommonAnnotationBeanPostProcessor 解析 @Resource、@PostConstruct、@PreDestroy
- ConfigurationPropertiesBindingPostProcessor 解析 @ConfigurationProperties
- 另外 ContextAnnotationAutowireCandidateResolver 负责获取 @Value 的值,解析 @Qualifier、泛型、@Lazy 等
@Autowired bean 后处理器运行分析
public class DigInAutowired { public static void main(String[] args) throws Throwable { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerSingleton("bean2", new Bean2()); beanFactory.registerSingleton("bean3", new Bean3()); beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor(); processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1(); System.out.println(bean1); processor.postProcessProperties(null, bean1, "bean1"); System.out.println(bean1);
Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor .class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class); findAutowiringMetadata.setAccessible(true); InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata .invoke(processor, "bean1", Bean1.class, null); System.out.println(metadata);
metadata.inject(bean1, "bean1", null); System.out.println(bean1);
Field bean3 = Bean1.class.getDeclaredField("bean3"); DependencyDescriptor dd1 = new DependencyDescriptor(bean3, false); Object o = beanFactory.doResolveDependency(dd1, null, null, null); System.out.println(o);
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class); DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), true); Object o1 = beanFactory.doResolveDependency(dd2, null, null, null); System.out.println(o1);
Method setHome = Bean1.class.getDeclaredMethod("setHome", String.class); DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setHome, 0), true); Object o2 = beanFactory.doResolveDependency(dd3, null, null, null); System.out.println(o2);
} }
|
收获
- AutowiredAnnotationBeanPostProcessor.findAutowiringMetadata 用来获取某个 bean 上加了 @Value @Autowired 的成员变量,方法参数的信息,表示为 InjectionMetadata
- InjectionMetadata 可以完成依赖注入
- InjectionMetadata 内部根据成员变量,方法参数封装为 DependencyDescriptor 类型
- 有了 DependencyDescriptor,就可以利用 beanFactory.doResolveDependency 方法进行基于类型的查找
BeanFactory 后处理器
作用
public class A05 { private static final Logger log = LoggerFactory.getLogger(A05.class);
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext(); context.registerBean("config", Config.class);
context.registerBean(AtBeanPostProcessor.class); context.registerBean(MapperPostProcessor.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) { System.out.println(name); }
Mapper1 mapper1 = context.getBean(Mapper1.class); Mapper2 mapper2 = context.getBean(Mapper2.class);
context.close();
} }
|
- ConfigurationClassPostProcessor 可以解析
- @ComponentScan
- @Bean
- @Import
- @ImportResource
- MapperScannerConfigurer 可以解析
模拟解析 @ComponentScan
public class ComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
@Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException { try { ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class); if (componentScan != null) { for (String p : componentScan.basePackages()) { System.out.println(p); String path = "classpath*:" + p.replace(".", "/") + "/**/*.class"; System.out.println(path); CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path); AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator(); for (Resource resource : resources) { MetadataReader reader = factory.getMetadataReader(resource); AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata(); if (annotationMetadata.hasAnnotation(Component.class.getName()) || annotationMetadata.hasMetaAnnotation(Component.class.getName())) { AbstractBeanDefinition bd = BeanDefinitionBuilder .genericBeanDefinition(reader.getClassMetadata().getClassName()) .getBeanDefinition(); String name = generator.generateBeanName(bd, beanFactory); beanFactory.registerBeanDefinition(name, bd); } } } } } catch (IOException e) { e.printStackTrace(); } } }
|
收获
- Spring 操作元数据的工具类 CachingMetadataReaderFactory
- 通过注解元数据(AnnotationMetadata)获取直接或间接标注的注解信息
- 通过类元数据(ClassMetadata)获取类名,AnnotationBeanNameGenerator 生成 bean 名
- 解析元数据是基于 ASM 技术
TODO…