目录
1、BeanFactory 与 ApplicationContext 的区别
3、根据通配符获取资源(ResourcePatternResolver)
5、发送事件(ApplicationEventPublisher)
1、容器接口
BeanFactory 接口,典型功能有:
getBean
ApplicationContext 接口,是 BeanFactory 的子接口。它扩展了 BeanFactory 接口的功能,如:
国际化
通配符方式获取一组 Resource 资源
整合 Environment 环境(能通过它获取各种来源的配置信息)
事件发布与监听,实现组件之间的解耦
1、BeanFactory 与 ApplicationContext 的区别
到底什么是 BeanFactory?
它是 ApplicationContext 的父接口
它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能,【组合】是指 ApplicationContext 的一个重要成员变量就是 BeanFactory
BeanFactory 能干点啥?
表面上只有 getBean
实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能,都由它的实现类提供
例子中通过反射查看了它的成员变量 singletonObjects,内部包含了所有的单例 bean
@SpringBootApplication
public class SpringbootMybatisApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootMybatisApplication.class, args);
Field singletonObjects = null;
try {
singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
singletonObjects.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
map.forEach((k,v) -> {
if(k.contains("component")){
System.out.println(k+"=="+v);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
- ApplicationContext 比 BeanFactory 多点啥?
ApplicationContext 组合并扩展了 BeanFactory 的功能
国际化、通配符方式获取一组 Resource 资源、整合 Environment 环境、事件发布与监听
新学一种代码之间解耦途径,事件解耦
2、国际化(MessageSource)
System.out.println(context.getMessage("hi",null, Locale.CHINA));
System.out.println(context.getMessage("hi",null, Locale.ENGLISH));
#国际化
spring.messages.basename=i18n.messages
spring.messages.encoding=utf-8
- ApplicationContext 中 MessageSource bean 的名字固定为 messageSource
- 使用 SpringBoot 时,国际化文件名固定为 messages
- 空的 messages.properties 也必须存在
3、根据通配符获取资源(ResourcePatternResolver)
//classpath表示到类路径下找
//Resource[] resources = context.getResources("classpath:application.properties");
//加 * 可以获取jar中的文件
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
for (Resource resource : resources) {
System.out.println(resource);
}
4、获取配置信息(EnvironmentCapable)
//不区分大小写,可以获取系统配置信息,或者配置文件中的信息
System.out.println(context.getEnvironment().getProperty("java_home"));
System.out.println(context.getEnvironment().getProperty("spring.messages.encoding"));
5、发送事件(ApplicationEventPublisher)
// context.publishEvent(new MyEvent(context));
context.getBean(Component1.class).register();
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
@Component
public class Component1 {
@Autowired
private ApplicationEventPublisher publisher;
public void register(){
System.out.println("用户注册");
publisher.publishEvent(new MyEvent(this));
}
}
@Component
public class Component2 {
@EventListener
public void listen(MyEvent event){
System.out.println(event);
System.out.println("发送短信");
}
}
2、容器实现
1、BeanFactory的实现
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 添加一些常用的后处理器(给bean工厂添加后处理器)
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
//建立后处理器与beanFactory的联系
// BeanFactory 后处理器主要功能,补充了一些 bean 定义,解析 @Bean
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
//后处理器是按顺序执行的,通过选择器改变后处理器的顺序
//他们都实现了 Order 接口,通过getOrder 方法,值越小优先级越高
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
.sorted(beanFactory.getDependencyComparator()).forEach(beanPostProcessor -> {
System.err.println(">>>>>>"+beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
//准备好所有单例(提前创建),默认延迟创建
beanFactory.preInstantiateSingletons();
for (String name : beanFactory.getBeanDefinitionNames()) {
System.err.println(name);
}
System.err.println("====================");
System.err.println(beanFactory.getBean(Bean1.class).getBean2());
/*
a. beanFactory 不会做的事
1. 不会主动调用 BeanFactory 后处理器
2. 不会主动添加 Bean 后处理器
3. 不会主动初始化单例
4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }
b. bean 后处理器会有排序的逻辑
*/
System.out.println("================");
System.out.println(beanFactory.getBean(Bean1.class).getIner());
}
@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();
}
}
static class Bean1{
public Bean1() {
System.out.println("bean1初始化");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2(){
return bean2;
}
// @Autowired
@Resource(name = "bean4")
private Iner bean3;
public Iner getIner(){
return bean3;
}
}
static class Bean2{
public Bean2() {
System.out.println("bean2初始化");
}
}
interface Iner{
}
static class Bean3 implements Iner{
public Bean3() {
System.out.println("bean3初始化");
}
}
static class Bean4 implements Iner{
public Bean4() {
System.out.println("bean4初始化");
}
}
}
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的实现
public class TestApplication {
public static void main(String[] args) {
test4();
// DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// System.err.println("------读取之前------");
// for (String name : beanFactory.getBeanDefinitionNames()) {
// System.out.println(name);
// }
//
// System.err.println("------读取之后------");
// XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
// for (String name : beanFactory.getBeanDefinitionNames()) {
// System.err.println(name);
// }
}
//基于 classpath 下 xml 格式的配置文件来创建
private static void test1(){
ClassPathXmlApplicationContext context
= new ClassPathXmlApplicationContext("b01.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(">>>>>"+name);
}
System.err.println(context.getBean(Bean2.class).getBean1());
}
//基于磁盘路径下 xml 格式的配置文件来创建
public static void test2(){
FileSystemXmlApplicationContext context
= new FileSystemXmlApplicationContext("D:\\IntelliJ IDEA\\test\\springboot-mybatis\\src\\main\\resources\\b01.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(">>>>>"+name);
}
System.err.println(context.getBean(Bean2.class).getBean1());
}
//基于 java 配置类来创建
public static void test3(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(">>>>>"+name);
}
System.err.println(context.getBean(Bean2.class).getBean1());
}
//基于 java 配置类来创建, 用于 web 环境
public static void test4(){
AnnotationConfigServletWebServerApplicationContext context
= new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
}
@Configuration
static class WebConfig{
//tomcat的webServer服务器
@Bean
public ServletWebServerFactory servletWebServerFactory(){
return new TomcatServletWebServerFactory();
}
//dispatcher
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
//给dispatcher一个路径注册到tomcat服务器
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet){
return new DispatcherServletRegistrationBean(dispatcherServlet,"/");
}
//控制器
@Bean("/hello")
public Controller controller(){
return (request, response) -> {
response.getWriter().println("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;
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="bean1" class="com.springboot.springbootmybatis.TestApplication.Bean1"/>
<bean id="bean2" class="com.springboot.springbootmybatis.TestApplication.Bean2">
<property name="bean1" ref="bean1" />
</bean>
<!--加入了一些后处理器-->
<context:annotation-config />
</beans>
常见的 ApplicationContext 容器实现
内嵌容器、DispatcherServlet 的创建方法、作用
3、Bean的生命周期
1、Bean的生命周期
一个受 Spring 管理的 bean,生命周期主要阶段有
创建:根据 bean 的构造方法或者工厂方法来创建 bean 实例对象
依赖注入:根据 @Autowired,@Value 或其它一些手段,为 bean 的成员变量填充值、建立关系
初始化:回调各种 Aware 接口,调用对象的各种初始化方法
销毁:在容器关闭时,会销毁所有单例对象(即调用它们的销毁方法)
prototype 对象也能够销毁,不过需要容器这边主动调用
@SpringBootApplication
public class Day3Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Day3Application.class, args);
context.close();
}
}
@Component
public class LifeCycleBean {
public LifeCycleBean(){
System.err.println("构造。。。");
}
@Autowired
public void autowire(@Value("${JAVA_HOME}") String home){
System.err.println("依赖注入:"+home);
}
@PostConstruct
public void init(){
System.err.println("初始化。。。");
}
@PreDestroy
public void destory(){
System.err.println("销毁。。。");
}
}
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
System.err.println("<<<<<< 销毁之前执行, 如 @PreDestroy");
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
System.err.println("<<<<<< 实例化之前执行, 这里返回的对象会替换掉原本的 bean");
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
System.err.println("<<<<<< 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段");
// return false;
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
System.err.println("<<<<<< 依赖注入阶段执行, 如 @Autowired、@Value、@Resource");
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
System.err.println("<<<<<< 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
System.err.println("<<<<<< 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强");
return bean;
}
}
创建前后的增强
postProcessBeforeInstantiation
这里返回的对象若不为 null 会替换掉原本的 bean,并且仅会走 postProcessAfterInitialization 流程
postProcessAfterInstantiation
这里如果返回 false 会跳过依赖注入阶段
依赖注入前的增强
postProcessProperties
如 @Autowired、@Value、@Resource
初始化前后的增强
postProcessBeforeInitialization
这里返回的对象会替换掉原本的 bean
如 @PostConstruct、@ConfigurationProperties
postProcessAfterInitialization
这里返回的对象会替换掉原本的 bean
如代理增强
销毁之前的增强
postProcessBeforeDestruction
如 @PreDestroy
2、模板方法设计模式
public class TestMethodTemplate {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public void inject(Object bean) {
System.out.println("解析 @Autowired");
}
});
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
beanFactory.getBean();
}
static class MyBeanFactory{
private List<BeanPostProcessor> processorList = new ArrayList<>();
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor){
processorList.add(beanPostProcessor);
}
public void getBean(){
Object bean = new Object();
System.err.println("构造:"+bean);
System.err.println("依赖注入:"+bean);
for (BeanPostProcessor beanPostProcessor : processorList) {
beanPostProcessor.inject(bean);
}
System.err.println("初始化:"+bean);
}
}
//将不确定的部分抽象成接口
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<>(List.of(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后处理器
作用:为bean生命周期各个阶段提供扩展
public class DayApplication {
public static void main(String[] args) {
//GenericApplicationContext 是一个【干净】的容器
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1",Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
context.registerBean("bean4",Bean4.class);
//@Value中值的获取
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);//@Autowired @Value(依赖注入)
//@Resource(依赖注入) @PostConstruct(初始化前) @PreDestroy(销毁前)
context.registerBean(CommonAnnotationBeanPostProcessor.class);
//完成属性的绑定(初始化前)
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
//初始化容器
context.refresh();//执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例
System.err.println(context.getBean(Bean4.class));
//销毁容器
context.close();
}
}
public class Bean1 {
private Bean2 bean2;
@Autowired
private void setBean2(Bean2 bean2){
this.bean2 = bean2;
System.err.println("@Autowired生效:"+bean2);
}
private Bean3 bean3;
@Resource
public void setBean3(Bean3 bean3){
this.bean3 = bean3;
System.err.println("@Resource生效:"+bean3);
}
private String home;
@Autowired
private void setHome(@Value("${JAVA_HOME}") String home){
this.home = home;
System.err.println("Value生效:"+home);
}
@PostConstruct
public void init(){
System.err.println("初始化。。。");
}
@PreDestroy
public void destory(){
System.err.println("销毁。。。");
}
@Override
public String toString() {
return "Bean1{" +
"bean2=" + bean2 +
", bean3=" + bean3 +
", home='" + home + '\'' +
'}';
}
}
@ConfigurationProperties(prefix = "java")
public class Bean4 {
private String home;
private String version;
public String getHome() {
return home;
}
public void setHome(String home) {
this.home = home;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@Override
public String toString() {
return ">>>>>Bean4{" +
"home='" + home + '\'' +
", version='" + version + '\'' +
'}';
}
}
@Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能,这些扩展功能由 bean 后处理器来完成
每个后处理器各自增强什么功能
AutowiredAnnotationBeanPostProcessor 解析 @Autowired 与 @Value
CommonAnnotationBeanPostProcessor 解析 @Resource、@PostConstruct、@PreDestroy
ConfigurationPropertiesBindingPostProcessor 解析 @ConfigurationProperties
另外 ContextAnnotationAutowireCandidateResolver 负责获取 @Value 的值,解析 @Qualifier、泛型、@Lazy 等
@Autowired bean 后处理器运行分析
// AutowiredAnnotationBeanPostProcessor 运行分析
public class MyAutowired {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean2",new Bean2());// 任务是个成品的bean,不会走创建过程,依赖注入,初始化
beanFactory.registerSingleton("bean3",new Bean3());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());// @Value
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
System.out.println(">>>>>>"+bean1);
processor.postProcessProperties(null,bean1,"bean1");
System.out.println(">>>>>>"+bean1);
}
}
调用方式:
Bean1 bean1 = new Bean1();
// System.out.println(">>>>>>"+bean1);
// processor.postProcessProperties(null,bean1,"bean1");
// System.out.println(">>>>>>"+bean1);
Method method = processor.getClass().getDeclaredMethod("findAutowiringMetadata", String.class,Class.class, PropertyValues.class);
method.setAccessible(true);
// 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息
InjectionMetadata metadata = (InjectionMetadata) method.invoke(processor, "bean1", bean1.getClass(), null);
// 2. 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值
metadata.inject(bean1,"bean1",null);
System.out.println(">>>>>>"+bean1);
InjectionMetadata中的属性:
// AutowiredAnnotationBeanPostProcessor 运行分析
public class MyAutowired {
public static void main(String[] args) throws Throwable {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean2",new Bean2());// 任务是个成品的bean,不会走创建过程,依赖注入,初始化
beanFactory.registerSingleton("bean3",new Bean3());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());// @Value
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 method = processor.getClass().getDeclaredMethod("findAutowiringMetadata", String.class,Class.class, PropertyValues.class);
// method.setAccessible(true);
// // 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息
// InjectionMetadata metadata = (InjectionMetadata) method.invoke(processor, "bean1", bean1.getClass(), null);
// 2. 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值
// metadata.inject(bean1,"bean1",null);
// System.out.println(">>>>>>"+bean1);
Field bean3 = bean1.getClass().getDeclaredField("bean3");
//ctrl+p 可显示需要的参数,将属性、方法封装到 DependencyDescriptor中
DependencyDescriptor dd1 = new DependencyDescriptor(bean3,false);
//找到要注入的对象
Object o1 = beanFactory.doResolveDependency(dd1, null, null, null);
System.err.println(o1);
Method setBean2 = bean1.getClass().getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 =
new DependencyDescriptor(new MethodParameter(setBean2,0),false);
Object o2 = beanFactory.doResolveDependency(dd2, null, null, null);
System.err.println(o2);
Method setHome = bean1.getClass().getDeclaredMethod("setHome", String.class);
DependencyDescriptor dd3 =
new DependencyDescriptor(new MethodParameter(setHome,0),false);
Object o3 = beanFactory.doResolveDependency(dd3, null, null, null);
System.err.println(o3);
}
}
AutowiredAnnotationBeanPostProcessor.findAutowiringMetadata 用来获取某个 bean 上加了 @Value @Autowired 的成员变量,方法参数的信息,表示为 InjectionMetadata
InjectionMetadata 可以完成依赖注入
InjectionMetadata 内部根据成员变量,方法参数封装为 DependencyDescriptor 类型
有了 DependencyDescriptor,就可以利用 beanFactory.doResolveDependency 方法进行基于类型的查找
5、BeanFactory后处理器
@SpringBootApplication
public class Day5Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config",Config.class);
//可解析 @ComponentScan @Bean @Import @ImportResource
context.registerBean(ConfigurationClassPostProcessor.class);
// @MapperScanner
context.registerBean(MapperScannerConfigurer.class,beanDefinition -> {
beanDefinition.getPropertyValues().add("basePackage","com.springboot.springbootmybatis.day5.mapper");
});
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.err.println(name);
}
context.close();
}
}
@Configuration
@ComponentScan("com.springboot.springbootmybatis.day5.component")
public class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
@Bean(initMethod = "init")
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/my");
dataSource.setUsername("root");
dataSource.setPassword("mysql");
return dataSource;
}
/* @Bean
public MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory) {
MapperFactoryBean<Mapper1> factory = new MapperFactoryBean<>(Mapper1.class);
factory.setSqlSessionFactory(sqlSessionFactory);
return factory;
}
@Bean
public MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory) {
MapperFactoryBean<Mapper2> factory = new MapperFactoryBean<>(Mapper2.class);
factory.setSqlSessionFactory(sqlSessionFactory);
return factory;
}*/
}
ConfigurationClassPostProcessor 可以解析
@ComponentScan
@Bean
@Import
@ImportResource
MapperScannerConfigurer 可以解析
Mapper 接口
@ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能
这些扩展功能由不同的 BeanFactory 后处理器来完成,其实主要就是补充了一些 bean 定义
1、工厂后处理器的模拟实现——@ComponentScan
public class MyPostProcessor implements BeanFactoryPostProcessor {
@Override //context.refresh()时调用
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
try{
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if(componentScan != null){
for (String basePackage : componentScan.basePackages()) {
// com.itheima.a05.component -> classpath*:com/itheima/a05/component/**/*.class
String path = basePackage.replace(".","/")+"/**/*.class";
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
MetadataReader reader = factory.getMetadataReader(resource);
// System.err.println("类的的信息:"+reader.getClassMetadata().getClassName());
// System.out.println("是否加了 @Componet:"+reader.getAnnotationMetadata().hasAnnotation(Component.class.getName()));
//间接加了,@Controller 上用了 @Component
// System.out.println("是否加了 @Componet 派生:"+reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName()));
if(reader.getAnnotationMetadata().hasAnnotation(Component.class.getName())
|| reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName())){
AbstractBeanDefinition beanDefinition
= BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
if(configurableListableBeanFactory instanceof DefaultListableBeanFactory){
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
String name = generator.generateBeanName(beanDefinition, beanFactory);
beanFactory.registerBeanDefinition(name,beanDefinition);
}
}
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
Spring 操作元数据的工具类 CachingMetadataReaderFactory
通过注解元数据(AnnotationMetadata)获取直接或间接标注的注解信息
通过类元数据(ClassMetadata)获取类名,AnnotationBeanNameGenerator 生成 bean 名
解析元数据是基于 ASM 技术
2、工厂后处理器的模拟实现——@Bean
public class MyBeanPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
try{
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/springboot/springbootmybatis/day5/Config.class"));
Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata method : methods) {
System.err.println(method.getMethodName());
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
builder.setFactoryMethodOnBean(method.getMethodName(),"config");
//对于构造、工厂方法的参数自动装配用 AUTOWIRE_CONSTRUCTOR
builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
//解析@Bean的属性:@Bean(initMethod = "init")
String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
if(initMethod.length() > 0){
builder.setInitMethodName(initMethod);
}
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
if(configurableListableBeanFactory instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
beanFactory.registerBeanDefinition(method.getMethodName(),beanDefinition);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
3、工厂后处理器的模拟实现——@MapperScan
public class MyMapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:com/springboot/springbootmybatis/day5/**/*.class");
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
MetadataReader reader = factory.getMetadataReader(resource);
ClassMetadata metadata = reader.getClassMetadata();
//判断是否为接口
if (metadata.isInterface()) {
AbstractBeanDefinition beanDefinition
= BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
.addConstructorArgValue(metadata.getClassName())
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
.getBeanDefinition();
//给每个mapper生成对应的名字
AbstractBeanDefinition beanDefinition2
= BeanDefinitionBuilder.genericBeanDefinition(metadata.getClassName()).getBeanDefinition();
String beanName = generator.generateBeanName(beanDefinition2, beanFactory);
beanFactory.registerBeanDefinition(beanName,beanDefinition);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
Mapper 接口被 Spring 管理的本质:实际是被作为 MapperFactoryBean 注册到容器中
Spring 的诡异做法,根据接口生成的 BeanDefinition 仅为根据接口名生成 bean 名
6、Aware接口
public class Day6Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
/*
有些功能用 @Autowired 就能实现啊, 为啥还要用 Aware 接口呢
简单地说:
a. @Autowired 的解析需要用到 bean 后处理器, 属于扩展功能
b. 而 Aware 接口属于内置功能, 不加任何扩展, Spring 就能识别
某些情况下, 扩展功能会失效, 而内置功能不会失效
下面例子:你会发现用 Aware 注入 ApplicationContext 成功, 而 @Autowired 注入 ApplicationContext 失败
*/
context.registerBean("mybean",MyBean.class);
context.refresh();
context.close();
}
}
public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {
@Override
public void setBeanName(String s) {
System.err.println("当前bean "+this+" 的名称:"+s);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.err.println("当前bean "+this+" 的容器:"+applicationContext);
}
@Override
public void afterPropertiesSet() throws Exception {
System.err.println("当前bean "+this+" 初始化。。。");
}
@Autowired
public void doAuto(ApplicationContext applicationContext){
System.err.println(">>>>当前bean "+this+" 的容器:"+applicationContext);
}
@PostConstruct
public void init(){
System.err.println(">>>>当前bean "+this+" 初始化。。。");
}
}
Aware 接口提供了一种【内置】 的注入手段,例如
BeanNameAware 注入 bean 的名字
BeanFactoryAware 注入 BeanFactory 容器
ApplicationContextAware 注入 ApplicationContext 容器
EmbeddedValueResolverAware 注入 ${} 解析器
InitializingBean 接口提供了一种【内置】的初始化手段
对比
内置的注入和初始化不受扩展功能的影响,总会被执行
而扩展功能受某些情况影响可能会失效
因此 Spring 框架内部的类常用内置注入和初始化
配置类 @Autowired 失效分析
@Configuration
public class MyConfig1 {
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
System.err.println("注入 ApplicationContext");
}
@PostConstruct
public void init() {
System.err.println("初始化");
}
@Bean // beanFactory 后处理器
public BeanFactoryPostProcessor processor1() {
return beanFactory -> {
System.err.println("执行 processor1");
};
}
}
加后处理器之前: 加了之后:
Java 配置类不包含 BeanFactoryPostProcessor 的情况 :
Java 配置类包含 BeanFactoryPostProcessor 的情况,因此要创建其中的 BeanFactoryPostProcessor 必须提前创建 Java 配置类,而此时的 BeanPostProcessor 还未准备好,导致 @Autowired 等注解失效
解决方法:
用内置依赖注入和初始化取代扩展依赖注入和初始化
用静态工厂方法代替实例工厂方法,避免工厂对象提前被创建
7、初始化与销毁
//初始化和销毁的执行顺序
@SpringBootApplication
public class Day7Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Day7Application.class, args);
context.close();
}
@Bean(initMethod = "init3")
public Bean1 bean1(){
return new Bean1();
}
@Bean(destroyMethod = "destroy3")
public Bean2 bean2() {
return new Bean2();
}
}
public class Bean1 implements InitializingBean {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
@PostConstruct
public void init1() {
System.err.println("初始化1");
}
@Override
public void afterPropertiesSet() throws Exception {
System.err.println("初始化2");
}
public void init3() {
System.err.println("初始化3");
}
}
public class Bean2 implements DisposableBean {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
@PreDestroy
public void destroy1() {
System.err.println("销毁1");
}
@Override
public void destroy() throws Exception {
System.err.println("销毁2");
}
public void destroy3() {
System.err.println("销毁3");
}
}
Spring 提供了多种初始化手段,除了 @PostConstruct,@Bean(initMethod) 之外,还可以实现 InitializingBean 接口来进行初始化,如果同一个 bean 用了以上手段声明了 3 个初始化方法,那么它们的执行顺序是
@PostConstruct 标注的初始化方法
InitializingBean 接口的初始化方法
@Bean(initMethod) 指定的初始化方法
与初始化类似,Spring 也提供了多种销毁手段,执行顺序为
@PreDestroy 标注的销毁方法
DisposableBean 接口的销毁方法
@Bean(destroyMethod) 指定的销毁方法
8、Scope
@RestController
public class MyController {
@Lazy
@Autowired
private BeanForRequest beanForRequest;
@Lazy
@Autowired
private BeanForSession beanForSession;
@Lazy
@Autowired
private BeanForApplication beanForApplication;
@GetMapping(value = "/test", produces = "text/html")
public String test(HttpServletRequest request, HttpSession session) {
ServletContext sc = request.getServletContext();
String sb = "<ul>" +
"<li>" + "request :" + beanForRequest + "</li>" +
"<li>" + "session :" + beanForSession + "</li>" +
"<li>" + "application :" + beanForApplication + "</li>" +
"</ul>";
return sb;
}
}
@Scope("request")
@Component
public class BeanForRequest {
@PreDestroy
public void destroy() {
System.err.println("request 销毁");
}
}
@Scope("session")
@Component
public class BeanForSession {
@PreDestroy
public void destroy() {
System.err.println("session 销毁");
}
}
@Scope("application")
@Component
public class BeanForApplication {
@PreDestroy
public void destroy() {
System.err.println("application 销毁");
}
}
在当前版本的 Spring 和 Spring Boot 程序中,支持五种 Scope
singleton,容器启动时创建(未设置延迟),容器关闭时销毁
prototype,每次使用时创建,不会自动销毁,需要调用 DefaultListableBeanFactory.destroyBean(bean) 销毁
request,每次请求用到此 bean 时创建,请求结束时销毁
session,每个会话用到此 bean 时创建,会话结束时销毁
application,web 容器用到此 bean 时创建,容器停止时销毁
有些文章提到有 globalSession 这一 Scope,也是陈旧的说法,目前 Spring 中已废弃
singleton 注入其它 scope 失效
以单例注入多例为例
@ComponentScan("com.springboot.springbootmybatis.day9")
public class Day9Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Day9Application.class);
E e = context.getBean(E.class);
System.err.println(">>>"+e.getF1().getClass());
System.err.println(">>>"+e.getF1());
System.err.println(">>>"+e.getF1());
System.err.println("\n>>>"+e.getF2().getClass());
System.err.println(">>>"+e.getF2());
System.err.println(">>>"+e.getF2());
System.err.println("\n>>>"+e.getF3().getClass());
System.err.println(">>>"+e.getF3());
System.err.println(">>>"+e.getF3());
System.err.println("\n>>>"+e.getF4().getClass());
System.err.println(">>>"+e.getF4());
System.err.println(">>>"+e.getF4());
}
}
@Component
public class E {
@Lazy
@Autowired
private F1 f1;
@Autowired
private F2 f2;
@Autowired
private ObjectFactory<F3> f3;
@Autowired
private ApplicationContext context;
public F1 getF1() {
return f1;
}
public F2 getF2() {
return f2;
}
public F3 getF3() {
return f3.getObject();
}
public F4 getF4() {
return context.getBean(F4.class);
}
}
原因:对于单例对象来讲,依赖注入仅发生了一次,后续再没有用到多例的 F,因此 E 用的始终是第一次依赖注入的 F
解决:
仍然使用 @Lazy 生成代理
代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的 f 对象
注意:
@Lazy 加在也可以加在成员变量上,但加在 set 方法上的目的是可以观察输出,加在成员变量上就不行了
@Autowired 加在 set 方法的目的类似
单例注入其它 scope 的四种解决方法
@Lazy
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
ObjectFactory
ApplicationContext
解决方法虽然不同,但理念上殊途同归: 都是推迟其它 scope bean 的获取