小傅哥手撸spring-ioc部分学习 bugstack.cn/
创建简单的bean容器
什么是容器
官方文档是这么定义的
The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans
Spring IOC容器就是一个org.springframework.context.ApplicationContext的实例化对象,容器负责了实例化,配置以及装配一个bean。
小傅哥在设计中说到凡是可以存放数据的具体数据结构实现,都可以称之为容器。例如:ArrayList、LinkedList、HashSet 等,Spring这里适合HashMap。
简单的spring 容器功能
最简单的Spring Bean容器实现,需要Bean的定义、注册、获取三个基本步骤;
定义:BeanDefinition(bean__BeanDefinition)目前没有config,只存放Object的bean信息
注册:hashmap存放bean的信息(BeanDefinition放入容器)
获取:通过key获取bean(BeanDefinition__Bean)
类图
职责:
BenDefinition:pojo的bean抽象,目前只有Object的属性
BeanFactory: bean的容器
为什么要不直接注册pojo,而使用BenDefinition
spring封装管理你所创建的对象,封装后的对象叫bean,bean扩展了你的对象,你所创建的对象的所有属性和方法是bean中的一个子集。spring所有的功能都是围绕这个bean展开的,这个bean在spring中具体的名字就是BeanDefinition。 Spring 中通常以这两种方式定义一个 Bean:面向资源(XML、Properties)、面向注解
BeanDefinition 主要包含一下信息:
- Bean的类名(class 属性)
- Bean行为配置类,如作用域、自动绑定模式、生命周期回调等
- 其他Bean引用
- 配置设置,比如Bean属性
流程图
实现 Bean 的定义、注册、获取
功能描述
定义
1.BeanDefinition 属性Object 改成Class
注册
1.把 BeanDefinition 注册到容器中
获取
1.考虑单例对象二次从缓存获取
2.获取失败返回异常
3.class的实例化(需要获取BeanDefinition)
模板模式
定义
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
封装不变部分,扩展可变部分,更好的复用和拓展。
AbstractBeanFactory定义getBean的流程,定义一些钩子函数,就是上面所说的算法的骨架。
子类DefaultListableBeanFactory 负责获取BeanDefinition,实现抽象方法getBeanDefinition
子类AbstractAutowireCapableBeanFactory负责实例化bean,实现抽象方法createBean
类图
职责划分
BeanDefinition的注册
接口定义BeanDefinitionRegistry、BeanDefinition
Bean的获取
BeanFactory
单例的获取与注册
SingletonBeanRegistry 和 DefaultSingletonBeanRegistry
模板模式定义获取bean的流程
AbstractBeanFactory
负责class的实例化
AbstractAutowireCapableBeanFactory(使用反射)
注册BeanDefinition与获取BeanDefinition的实现
DefaultListableBeanFactory
getBean流程中的异常
实例化class 和getBeanDefinition()会报异常 BeansException
流程图
对象实例化策略
功能描述
Spring支持以下三种方法实例化Bean
- 构造方法
- 通过静态工厂方法
- 通过实例工厂方法
本节内容实现构造方法,无参和有参(有参的筛选构造器的逻辑有待完善)
实例化方法
@Slf4j
public class ApiTest {
@Test
public void test_newInstance() throws IllegalAccessException,
InstantiationException {
Class<User> aClass = User.class;
//实例化默认构造方法,User必须无参构造函数,否则将抛异常
//newInstance方法就是大家所说的反射。事实上Class的newInstance方法内部调用Constructor的newInstance方法。
User user = aClass.newInstance();
log.info("User newInstance:{}", user);
}
@Test
public void test_constructor() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<User> aClass = User.class;
// 取得指定带int和String参数构造函数,该方法是私有构造private
Constructor<User> declaredConstructor = aClass.getDeclaredConstructor(int.class, String.class);
//由于是private必须设置可访问
declaredConstructor.setAccessible(true);
User user = declaredConstructor.newInstance(11, "黑猫");
log.info("User DeclaredConstructor:{}", user);
//获取带String参数的public构造函数
Constructor<User> constructor = aClass.getConstructor(String.class);
User user2 = constructor.newInstance("黑猫2");
log.info("User Constructor:{}", user2);
}
//在 Spring 内部有两个字节码提升的框架,ASM(过于底层,直接操作字节码)和 CGLIB(相对于前者更加简便)
@Test
public void test_cglib(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(User.class);
enhancer.setCallback(new NoOp() {
@Override
public int hashCode() {
return super.hashCode();
}
});
Object obj = enhancer.create(new Class[]{String.class}, new Object[]{"黑猫"});
log.info("cglib:{}",obj);
}
}
public class User {
private int age;
private String name;
public User() {
super();
}
public User(String name) {
super();
this.name = name;
}
/**
* 私有构造
*
* @param age
* @param name
*/
private User(int age, String name) {
super();
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
类图
流程图
注入属性和依赖对象
功能描述
依赖注入,类中的属性填充,包括基础属性和对象属性
根据官网介绍,依赖注入主要分为两种方式
- 构造函数注入
- Setter方法注入,通过反射调用set方法
类图
BeanReference:bean的引用
PropertyValues:属性集合
PropertyValue:属性
流程图
资源加载器解析文件并注册
功能描述
Spring 中通常以这两种方式定义一个 Bean:面向资源(XML、Properties)、面向注解。本章把bean的定义放在Xml里面,解析完xml变成BeanDefinition,并且注册到BeanFactory
类图
流程图
应用上下文
功能描述
对BeanFactory的功能拓展
ApplicationContext,整合DefaultListableBeanFactory和XmlBeanDefitionReader,拓展BeanFactory的功能
对Bean的拓展
BeanFactoryPostProcessor
在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制。在Context的refresh中执行BeanFactoryPostProcessor的接口
BeanPostProcessor
BeanPostProcessor 是在 Bean对象实例化之后修改Bean对象,也可以替换 Bean对象。
在Context的refresh中注册BeanPostProcessor的接口,放入BeanFactory,在bean初始化方法中调用。
类图
流程图
初始化和销毁方法
功能描述
本章节实现bean初始化和销毁回调的前2种实现
Bean初始化回调
- 实现
InitializingBean接口 - 使用Bean标签中的
init-method属性 - 使用
@PostConstruct注解
bean的销毁回调
- 实现
DisposableBean接口 - 使用Bean标签中的
destroy-method属性 - 使用
@PreDestroy注解
类图
流程图
Aware 感知容器对象
功能描述
所有的Aware接口都是为了能让我们拿到容器中相关的资源,
比如BeanNameAware,可以让我们拿到Bean的名称,ApplicationContextAware 可以让我们拿到整个容器,
BeanFactoryAware,可以让我们拿到BeanFactory,BeanClassLoaderAware 可以让我们拿到容器的类加载器。
类图
流程图
对象作用域和 FactoryBean
功能描述
对象作用域:单例和原型;一个单例的bean意味着,这个bean只会容器创建一次,一个原型的bean意味着,每次我们使用时都会重新创建这个bean。
FactoryBean是容器的拓展点,主要用来定制化Bean的创建逻辑,当我们实例化一个Bean的逻辑很复杂的时候,使用FactoryBean是很必要的,这样可以规避我们去使用冗长的XML配置。有些三方包可以用这个方法注入spring,@Bean也是基于FactoryBean的。
类图
流程图
容器事件和事件监听器
功能描述
Spring中的事件监听机制的简单实现