容器与 bean
1) 容器接口
-
BeanFactory 接口,典型功能有:
-
getBean
-
-
ApplicationContext 接口,是 BeanFactory 的子接口。它扩展了 BeanFactory 接口的功能,如:
-
国际化 MessageSource
-
通配符方式获取一组 Resource 资源 ResourcePatternResolver
-
整合 Environment 环境(能通过它获取各种来源的配置信息)EnvironmentCapable
-
事件发布与监听,实现组件之间的解耦 ApplicationEventPublisher
-
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { @Nullable String getId(); String getApplicationName(); String getDisplayName(); long getStartupDate(); @Nullable ApplicationContext getParent(); AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException; }
-
可以看到,我们课上讲的,都是 BeanFactory 提供的基本功能,ApplicationContext 中的扩展功能都没有用到。
演示1 - BeanFactory 与 ApplicationContext 的区别
代码参考
/* 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 { ConfigurableApplicationContext context = SpringApplication.run(A01.class, args); /* 1. 到底什么是 BeanFactory - 它是 ApplicationContext 的父接口 - 它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能 */ System.out.println(context); /* 2. BeanFactory 能干点啥 - 表面上只有 getBean - 实际上控制反转、基本的依赖注入、直至 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()); }); /* 3. ApplicationContext 比 BeanFactory 多点啥 */ 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.publishEvent(new UserRegisteredEvent(context)); context.getBean(Component1.class).register(); /* 4. 学到了什么 a. BeanFactory 与 ApplicationContext 并不仅仅是简单接口继承的关系, ApplicationContext 组合并扩展了 BeanFactory 的功能 b. 又新学一种代码之间解耦途径 练习:完成用户注册与发送短信之间的解耦, 用事件方式、和 AOP 方式分别实现 */ } }
收获💡
通过这个示例结合 debug 查看 ApplicationContext 对象的内部结构,学到:
-
到底什么是 BeanFactory
-
它是 ApplicationContext 的父接口
-
它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能,【组合】是指 ApplicationContext 的一个重要成员变量就是 BeanFactory
-
-
BeanFactory 能干点啥
-
表面上只有 getBean
-
实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能,都由它的实现类提供
-
例子中通过反射查看了它的成员变量 singletonObjects,内部包含了所有的单例 bean
-
-
ApplicationContext 比 BeanFactory 多点啥
-
ApplicationContext 组合并扩展了 BeanFactory 的功能
-
国际化、通配符方式获取一组 Resource 资源、整合 Environment 环境、事件发布与监听
-
新学一种代码之间解耦途径,事件解耦
-
建议练习:完成用户注册与发送短信之间的解耦,用事件方式、和 AOP 方式分别实现
注意
如果 jdk > 8, 运行时请添加 --add-opens java.base/java.lang=ALL-UNNAMED,这是因为这些版本的 jdk 默认不允许跨 module 反射
事件发布还可以异步,这个视频中没有展示,请自行查阅 @EnableAsync,@Async 的用法
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 - DefaultListableBeanFactory
代码参考
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); // 给 BeanFactory 添加一些常用的后处理器 AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory); // BeanFactory 后处理器主要功能,补充了一些 bean 定义 beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> { beanFactoryPostProcessor.postProcessBeanFactory(beanFactory); }); // Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ... 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).getBean2()); System.out.println(beanFactory.getBean(Bean1.class).getInter()); /* 学到了什么: a. beanFactory 不会做的事 1. 不会主动调用 BeanFactory 后处理器 2. 不会主动添加 Bean 后处理器 3. 不会主动初始化单例 4. 不会解析beanFactory 还不会解析 ${ } 与 #{ } b. bean 后处理器会有排序的逻辑 */ System.out.println("Common:" + (Ordered.LOWEST_PRECEDENCE - 3)); System.out.println("Autowired:" + (Ordered.LOWEST_PRECEDENCE - 2)); } @Configuration static class Config { @Bean public Bean1 bean1() { return new Bean1(); } @Bean public Bean2 bean2() { return new Bean2(); } @Bean public Bean3 bean3() { return new Bean3(); } @Bean public Bean4 bean4() { return new Bean4(); } } interface Inter { } static class Bean3 implements Inter { } static class Bean4 implements Inter { } static class Bean1 { private static final Logger log = LoggerFactory.getLogger(Bean1.class); public Bean1() { log.debug("构造 Bean1()"); } @Autowired private Bean2 bean2; public Bean2 getBean2() { return bean2; } @Autowired @Resource(name = "bean4") private Inter bean3; public Inter getInter() { return bean3; } } static class Bean2 { private static final Logger log = LoggerFactory.getLogger(Bean2.class); public Bean2() { log.debug("构造 Bean2()"); } } }
收获💡
-
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 后处理的添加顺序会对解析结果有影响,见视频中同时加 @Autowired,@Resource 的例子
-
-
beanFactory 需要手动调用方法来初始化单例
-
beanFactory 需要额外设置才能解析 ${} 与 #{}
演示2 - 常见 ApplicationContext 实现
代码参考
* 常见 ApplicationContext 实现 */ public class A02 { private static final Logger log = LoggerFactory.getLogger(A02.class); public static void main(String[] args) { testClassPathXmlApplicationContext(); // testFileSystemXmlApplicationContext(); // testAnnotationConfigApplicationContext(); // testAnnotationConfigServletWebServerApplicationContext(); /*DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); System.out.println("读取之前..."); for (String name : beanFactory.getBeanDefinitionNames()) { System.out.println(name); } System.out.println("读取之后..."); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\a02.xml")); for (String name : beanFactory.getBeanDefinitionNames()) { System.out.println(name); }*/ /* 学到了什么 a. 常见的 ApplicationContext 容器实现 b. 内嵌容器、DispatcherServlet 的创建方法、作用 */ } // ⬇️较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建 private static void testClassPathXmlApplicationContext() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("a02.xml"); for (String name : context.getBeanDefinitionNames()) { System.out.println(name); } System.out.println(context.getBean(Bean2.class).getBean1()); } // ⬇️基于磁盘路径下 xml 格式的配置文件来创建 private static void testFileSystemXmlApplicationContext() { FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext( "src\\main\\resources\\a02.xml"); for (String name : context.getBeanDefinitionNames()) { System.out.println(name); } System.out.println(context.getBean(Bean2.class).getBean1()); } // ⬇️较为经典的容器, 基于 java 配置类来创建 private static void testAnnotationConfigApplicationContext() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); for (String name : context.getBeanDefinitionNames()) { System.out.println(name); } System.out.println(context.getBean(Bean2.class).getBean1()); } // ⬇️较为经典的容器, 基于 java 配置类来创建, 用于 web 环境 private static void testAnnotationConfigServletWebServerApplicationContext() { AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class); for (String name : context.getBeanDefinitionNames()) { System.out.println(name); } } @Configuration static class WebConfig { @Bean public ServletWebServerFactory servletWebServerFactory(){ return new TomcatServletWebServerFactory(); } @Bean public DispatcherServlet dispatcherServlet() { return new DispatcherServlet(); } @Bean public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) { return new DispatcherServletRegistrationBean(dispatcherServlet, "/"); } @Bean("/hello") public Controller controller1() { return (request, response) -> { response.getWriter().print("hello"); return null; }; } } @Configuration static class Config { @Bean public Bean1 bean1() { return new Bean1(); } @Bean public Bean2 bean2(Bean1 bean1) { Bean2 bean2 = new Bean2(); bean2.setBean1(bean1); return bean2; } } static class Bean1 { } static class Bean2 { private Bean1 bean1; public void setBean1(Bean1 bean1) { this.bean1 = bean1; } public Bean1 getBean1() { return bean1; } } }
收获💡
-
常见的 ApplicationContext 容器实现
-
内嵌容器、DispatcherServlet 的创建方法、作用
3) Bean 的生命周期
一个受 Spring 管理的 bean,生命周期主要阶段有
-
创建:根据 bean 的构造方法或者工厂方法来创建 bean 实例对象
-
依赖注入:根据 @Autowired,@Value 或其它一些手段,为 bean 的成员变量填充值、建立关系
-
初始化:回调各种 Aware 接口,调用对象的各种初始化方法
-
销毁:在容器关闭时,会销毁所有单例对象(即调用它们的销毁方法)
-
prototype 对象也能够销毁,不过需要容器这边主动调用
-
一些资料会提到,生命周期中还有一类 bean 后处理器:BeanPostProcessor,会在 bean 的初始化的前后,提供一些扩展逻辑。但这种说法是不完整的,见下面的演示1
BeanPostProcessor可以在bean创建前后,依赖注入时,初始化前后以及销毁之前提供一些扩展功能.
演示1 - bean 生命周期
代码参考
@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 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; } }
创建
依赖注入
初始化
可用
销毁
创建前后的增强
-
postProcessBeforeInstantiation
-
这里返回的对象若不为 null 会替换掉原本的 bean,并且仅会走 postProcessAfterInitialization 流程
-
-
postProcessAfterInstantiation
-
这里如果返回 false 会跳过依赖注入阶段
-
依赖注入前的增强
-
postProcessProperties
-
如 @Autowired、@Value、@Resource
-
初始化前后的增强
-
postProcessBeforeInitialization
-
这里返回的对象会替换掉原本的 bean
-
如 @PostConstruct、@ConfigurationProperties
-
-
postProcessAfterInitialization
-
这里返回的对象会替换掉原本的 bean
-
如代理增强
-
销毁之前的增强
-
postProcessBeforeDestruction
-
如 @PreDestroy
-
收获💡
-
Spring bean 生命周期各个阶段
-
模板设计模式, 指大流程已经固定好了, 通过接口回调(bean 后处理器)在一些关键点前后提供扩展
演示2 - 模板方法设计模式
关键代码
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(); } // 模板方法 Template Method Pattern static class MyBeanFactory { public Object getBean() { Object bean = new Object(); System.out.println("构造 " + bean); System.out.println("依赖注入 " + bean); // @Autowired, @Resource 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); // 对依赖注入阶段的扩展 } }
演示3 - bean 后处理器排序
代码参考
/* bean 后处理的的排序 */ public class TestProcessOrder { public static void main(String[] args) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory); List<BeanPostProcessor> list = new ArrayList<>(Arrays.asList(new P1(), new P2(), new P3(), new P4(), new P5())); list.sort(beanFactory.getDependencyComparator()); list.forEach(processor->{ processor.postProcessBeforeInitialization(new Object(), ""); }); /* 学到了什么 1. 实现了 PriorityOrdered 接口的优先级最高 2. 实现了 Ordered 接口与加了 @Order 注解的平级, 按数字升序 3. 其它的排在最后 */ } @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 注解的平级, 按数字升序
-
其它的排在最后
4) Bean 后处理器
演示1 - 后处理器作用
代码参考
/* bean 后处理器的作用 */ public class A04 { public static void main(String[] args) { // ⬇️GenericApplicationContext 是一个【干净】的容器 GenericApplicationContext context = new GenericApplicationContext(); // ⬇️用原始方法注册三个 bean 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); // @Autowired @Value context.registerBean(CommonAnnotationBeanPostProcessor.class); // @Resource @PostConstruct @PreDestroy ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory()); // ⬇️初始化容器 context.refresh(); // 执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例 System.out.println(context.getBean(Bean1.class)); // ⬇️销毁容器 context.close(); /* 学到了什么 a. @Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能 b. 这些扩展功能由 bean 后处理器来完成 */ } }
收获💡
-
@Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能,这些扩展功能由 bean 后处理器来完成
-
每个后处理器各自增强什么功能
-
AutowiredAnnotationBeanPostProcessor 解析 @Autowired 与 @Value
-
CommonAnnotationBeanPostProcessor 解析 @Resource、@PostConstruct、@PreDestroy
-
ConfigurationPropertiesBindingPostProcessor 解析 @ConfigurationProperties
-
-
另外 ContextAnnotationAutowireCandidateResolver 负责获取 @Value 的值,解析 @Qualifier、泛型、@Lazy 等
演示2 - @Autowired bean 后处理器运行分析
代码参考
// AutowiredAnnotationBeanPostProcessor 运行分析 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()); // @Value beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // ${} 的解析器 // 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor(); processor.setBeanFactory(beanFactory); Bean1 bean1 = new Bean1(); // System.out.println(bean1); // processor.postProcessProperties(null, bean1, "bean1"); // 执行依赖注入 @Autowired @Value // 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);// 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息 // System.out.println(metadata); // 2. 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值 // metadata.inject(bean1, "bean1", null); // System.out.println(bean1); // 3. 如何按类型查找值 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 方法进行基于类型的查找
5) BeanFactory 后处理器
演示1 - BeanFactory 后处理器的作用
代码参考
com.itheima.a05 包
-
ConfigurationClassPostProcessor 可以解析
-
@ComponentScan
-
@Bean
-
@Import
-
@ImportResource
-
-
MapperScannerConfigurer 可以解析
-
Mapper 接口
-
收获💡
-
@ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能
-
这些扩展功能由不同的 BeanFactory 后处理器来完成,其实主要就是补充了一些 bean 定义
演示2 - 模拟解析 @ComponentScan
代码参考
public class ComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override // context.refresh 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); // com.itheima.a05.component -> classpath*:com/itheima/a05/component/**/*.class 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) { // System.out.println(resource); MetadataReader reader = factory.getMetadataReader(resource); // System.out.println("类名:" + reader.getClassMetadata().getClassName()); AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata(); // System.out.println("是否加了 @Component:" + annotationMetadata.hasAnnotation(Component.class.getName())); // System.out.println("是否加了 @Component 派生:" + annotationMetadata.hasMetaAnnotation(Component.class.getName())); 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(); } } }
主要流程:
1.执行refresh方法的时候 通过注解元数据(AnnotationMetadata)获取直接或间接标注的注解信息,判断当前bean上的conponentscan注解扫描的包路径
2.根据resource接口提供的方法就可以通过通配符获取包路径下的所有class类
3.查看哪些类添加了componet注解和派生注解,添加了注解的类就去生成beandefinition
4.将beandefinition注册到bean工厂中
收获💡
-
Spring 操作元数据的工具类 CachingMetadataReaderFactory
-
通过注解元数据(AnnotationMetadata)获取直接或间接标注的注解信息
-
通过类元数据(ClassMetadata)获取类名,AnnotationBeanNameGenerator 生成 bean 名
-
解析元数据是基于 ASM 技术