文章目录
- 1. Spring的基本功能
- 2. 容器启动+ 容器启动,即创建容器对象并赋予配置对象
- 3. BeanDefinition扫描
- 4. Bean的生命周期
- 5. 单例Bean与多例Bean
- 6. 依赖注入
- 7. AOP
- 8. Aware 回调
- 9. 初始化
- 10. BeanPostProcessor
- 附录:
1. Spring的基本功能
2. 容器启动+ 容器启动,即创建容器对象并赋予配置对象
// 自定义的 IOC 容器对象
GyhApplicationContext gyhApplicationContext =
new GyhApplicationContext(AppConfig.class);
3. BeanDefinition扫描
- 对于基于注解的方式,会在构造方法中扫描 @ConponentScan 的 value 值对应其下的所有类对应的
.class
文件(存在于out
文件夹下) - 将 扫描到的bean信息(Class, scope)封装至
BeanDefinition
对象中并由 一个 Map (beanDefinitionMap) 保存beanName ---> BeanDefinition
4. Bean的生命周期
在 createBean
中:
- 利用 Bean 的空构造器通过反射创建
- 设置对象属性(伴随着依赖注入)
- 执行前置处理器
- 执行初始化方法
- 执行后置处理器
- 调用使用
- 执行 destory 方法
5. 单例Bean与多例Bean
- 对于
单例Bean
是在初始化容器时(扫描过程中)创建并由 一个 Map(singletonObjects)管理 beanName —> beanInstance - 对于
多例Bean
是在 getBean() 方法中实时创建的
6. 依赖注入
- 在 createBean 方法中,扫描所有 bean 被 @Autowire 标注的属性为其注入容器中的 bean
- 若当前容器中还没有所依赖bean,则会创建该bean,然后再注入
7. AOP
- spring是基于
动态代理
- 初始化后,通过动态代理生成实现了指定接口的代理类
- 使用了AOP对应的 bean 会被代理类的对象所替换
8. Aware 回调
- 对应自定义的bean的类实现了Spring中指定的 Aware接口。可以在创建 bean 的过程中被检索到,并在定制的顺序中执行 Aware接口中定义的方法(即调用bean中实现的Aware接口的方法)
9. 初始化
- 是spring的Aware接口中的一种,spring会检索实现了
InitializationBean
接口的 Bean。在创建这些bean是会调用其实现的afterPropertiesSet
方法
10. BeanPostProcessor
- 后置处理器,也是Aware回调接口中的一种,其定义的前置与后置方法会被用在所有bean的创建过程中
附录:
GyhApplicationContext
package com.gyh.spring;
import com.gyh.service.UserService;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Gao YongHao
* @version 1.0
* 模拟Spring的javaConfig的容器启动方式
*/
public class GyhApplicationContext {
private Class<?> configClass;
// 用于保存Bean对象的信息(class 对象, 作用域信息)
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap =
new ConcurrentHashMap<>();
// 用于保存单例的对象
private ConcurrentHashMap<String, Object> singletonObjects =
new ConcurrentHashMap<>();
// 用于保存 BeanPostProcessor 的集合
private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
public GyhApplicationContext(Class<?> configClass) {
this.configClass = configClass;
// 扫描,单例的对象被直接创建,多例的对象在使用时创建
if (configClass.isAnnotationPresent(ComponentScan.class)) {
ComponentScan annotation = configClass.getAnnotation(ComponentScan.class);
String packagePath = annotation.value(); // 扫描路径 "com.gyh.service"
packagePath = packagePath.replace(".", "/");
// 在 out 文件夹中定位 .class 文件的路径
ClassLoader classLoader = GyhApplicationContext.class.getClassLoader();
URL resource = classLoader.getResource(packagePath);
File file = new File(resource.getFile());
// System.out.println(file);
// 如果是文件夹
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
String absolutePath = f.getAbsolutePath();
// 筛选出 .class 结尾的字节码文件
if (absolutePath.endsWith(".class")) {
String loadClassPath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
loadClassPath = loadClassPath.replace("\\", ".");
// loadClassPath == "com\gyh\service\UserService"
// System.out.println(loadClassPath);
try {
// 利用类加载器加载指定文件夹下的 .class 文件
Class<?> aClass = classLoader.loadClass(loadClassPath);
// 查看是否有标注 Bean 对应的的注解
if (aClass.isAnnotationPresent(Component.class)) {
// 扫描出实现了 BeanPostProcessor 的 bean,将其实例化对象放置于 集合 中
if (BeanPostProcessor.class.isAssignableFrom(aClass)) {
beanPostProcessors.add((BeanPostProcessor) aClass.newInstance());
}
// 设置的Bean名称(若为""或null)则设置为首字母小写的类名
String beanName = aClass.getAnnotation(Component.class).value();
if ("".equals(beanName)) {
beanName = aClass.getSimpleName().substring(0, 1).toLowerCase() + aClass.getSimpleName().substring(1);
}
// 创建保存Bean信息的对象
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType(aClass); // 该对象类型
if (aClass.isAnnotationPresent(Scope.class)) {
Scope annotation1 = aClass.getAnnotation(Scope.class);
String value = annotation1.value();
beanDefinition.setScope(value);
} else { // 默认是单例的
beanDefinition.setScope("Singleton");
}
// 放置于 beanDefinitionMap 中管理
beanDefinitionMap.put(beanName, beanDefinition);
}
// 填充单例对象
for (Map.Entry<String, BeanDefinition> s : beanDefinitionMap.entrySet()) {
BeanDefinition value = s.getValue();
if (value.getScope().equals("Singleton")) {
// 存有依赖注入的单例对象生成
singletonObjects.put(s.getKey(), createBean(s.getKey(), value));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* 创建Bean对象,
*
* @param beanName bean 对象名称
* @param beanDefinition bean 对象的信息
* @return
*/
public Object createBean(String beanName, BeanDefinition beanDefinition) {
Class<?> type = beanDefinition.getType();
Object o = null;
try {
o = type.getConstructor().newInstance();
// 依赖注入
// 遍历属性对属性进行依赖注入
for (Field f : type.getDeclaredFields()) {
if (f.isAnnotationPresent(Autowired.class)) {
f.setAccessible(true); // 关闭访问权限
// 将容器中管理的bean注入到该属性中(可能先于当前类创建,也可能后于当前类创建)
f.set(o, getBean(beanName, type));
}
}
// 回调机制,查看当前的Bean是否实现了指定的接口
// 如果实现则执行相关方法(BeanPostProcessor即是如此实现)
if (o instanceof BeanNameAware) {
((BeanNameAware) o).setBeanName(beanName);
}
for(BeanPostProcessor b:beanPostProcessors){
b.beforePostProcess(beanName, o);
}
// 初始化也使用回调实现
// 基于AOP会在后置处理器中创建 bean 的动态代理对象,并封装切面逻辑
for(BeanPostProcessor b:beanPostProcessors){
b.afterPostProcess(beanName, o);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return o;
}
/**
* 用于返回 Bean 对象的方法
*
* @param beanName Bean 的名称
* @param clazz Bean 对应的 Class 对象
* @param <T>
* @return
*/
public <T> T getBean(String beanName, Class<T> clazz) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) {
throw new NullPointerException();
} else {
String scope = beanDefinition.getScope();
if (scope.equals("Singleton")) {
// 从单例池中获取对象
Object o = singletonObjects.get(beanName);
if (o == null) { // 对应依赖注入时可能会用到
o = createBean(beanName, beanDefinition);
singletonObjects.put(beanName, o); // 放入单例池中
}
return (T) o;
} else { // 多例则实时创建
Object o = null;
try {
o = beanDefinition.getType().newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return (T) o;
}
}
}
}