Spring原理篇--BeanPostProcessor or BeanDefinition or Aware or InitializingBean
Posted 喜欢编码的老胡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring原理篇--BeanPostProcessor or BeanDefinition or Aware or InitializingBean相关的知识,希望对你有一定的参考价值。
@TOC# Spring系列
记录在程序走的每一步___auth:huf
最近在复习Spring核心原理; 顺手记录;
Spring关健实现 简化版
以下实现均为简化版本;有助于帮助记忆; 该版本代码有部分缺陷 例如:相互依赖…本章节不会记录相互依赖是怎么解决的; 之后会有专门的章节讲解其细节;主要描述Spring大致是怎么实现的 BeanDefinition 与 BeanPostProcessor 又是什么; 之后会一步一步引导读者理解Spring原理.并且记住.
以下代码有详细注释: 关健代码已经全部展示; (源码下载): 该篇章极为重要;如果想很好的理解后续Spring底层原理 一定要理解透彻该篇章;
package huf_spring;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* 模拟SPring启动主类:
* ps: Spring中使用了大量反射; 进行类注解 属性 进行 功能性的区分;
* 1:主类主要做了以下几件事
* 1): 获取到配置文件;从配置文件中;获取到扫描路径(类的扫描路径);然后得到文件; 然后对其目录进行挨个扫描 得到相对应的class;
* 2): 在初始化每个Bean的时候 会执行Aware回调 进行属性的注入;
* 3): 在Aware回调之后 进入 BeanPostProcesscor List. 开始循环调用 该实现类的前置方法:postProcessBeforeInitialization
* 4): 实例化对象的创建; 这时候是真实对象; 但是一旦进入了postProcessAfterInitialization 方法;
* (控制方案 可以有 事务 等等注解进行控制) 如果有 就会转变为代理对象; 如果没有 就返回创建的真实对象;
* 5): InitializingBean 是初始化接口 使用该接口 把该接口放到容器中去; 不能保证它的执行顺序就是排在第一位;注意;
*
* auth:huf
*/
public class HufApplicationContext {
//beanDefinitionMap 存放的是所有扫描到的Bean 的class信息
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
//singletonObjects 单例池 存放着所有扫描到的 <单例> 对象 且是非懒加载对象 也就是@Lazy 标注的对象;如果使用配置文件可以在配置文件中设置
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>();
//beanPostProcessorList 存放着所有处理器的List 该处理器 会在实例化前后进行循环调用. 从而达到初始化前 初始化 初始化后的效果;
//也是AOP切面的主要实现途径;
private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<BeanPostProcessor>();
//test main方法 new出该对象 注入Class文件 第一个大步骤
public HufApplicationContext(Class configClazz) {
//扫描 传入为AppConfig.class;
scam(configClazz);
/**
* 实例化非懒加载单例bean:
* 1. 实例化
* 2. 属性填充
* 3. Aware回调
* 4. 初始化
* 5. 添加到单例池
*/
instanceSingletonBean();
}
//一
private void scam(Class configClazz) {
//获取到扫描类上的注解 获取到要扫描的类 目录路径
ComponentScan componentScanAnnotation = (ComponentScan) configClazz.getAnnotation(ComponentScan.class);
//获取到 "com.huf.service"
String compomentScanPath = componentScanAnnotation.value();
//第一个大步骤 2)
List<Class> classList = getBeanClasses(compomentScanPath);
if(null!=classList && classList.size()>0){
for (Class clazz : classList) {
//判断是否被注解; 注解也有很多; 这里仅模仿流程
if (clazz.isAnnotationPresent(Service.class)) {
//被扫描注解注视到 或者是配置文件配置到. 那么 就开始封装 BeanDefinition; 自行到BeanDefinition 查看该类用处;
BeanDefinition beanDefinition = new BeanDefinition();
//保存Class
beanDefinition.setBeanClass(clazz);
Service service = (Service) clazz.getAnnotation(Service.class);
//获取该Service 名字 实际上 Spring有自动扫描 自动生成名字的一套方案 在以前XML文件定义的形式 有id 可以定义Bean的名字.
String beanName = service.value();
//判断类是否实现了BeanPostProcessor接口 假设实现;
if(BeanPostProcessor.class.isAssignableFrom(clazz)){
try {
//获取该实现类BeanPostProcessor
BeanPostProcessor instance = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
//在初始化过程中 它仅仅是把相关实例保存到内存List中 在此处并无调用;请注意;
beanPostProcessorList.add(instance);
} catch (Exception e) {
e.printStackTrace();
}
}
// 解析scope
if (clazz.isAnnotationPresent(Scope.class)) {
Scope scope = (Scope) clazz.getAnnotation(Scope.class);
String scopeValue = scope.value();
if (ScopeEnum.singleton.name().equals(scopeValue)) {
beanDefinition.setScope(ScopeEnum.singleton);
} else {
beanDefinition.setScope(ScopeEnum.prototype);
}
} else {
beanDefinition.setScope(ScopeEnum.singleton);
}
//保存BeanDefinition 使用的Map集合 后续用于创建对象;
beanDefinitionMap.put(beanName,beanDefinition);
}
}
System.out.println("");
}
}
//二 获取该目录下面的所有Class 该步骤执行完后 返回主流程 开始执行instanceSingletonBean
private List<Class> getBeanClasses(String compomentScanPath) {
//创建List 用于返回
List<Class> beanClasses = new ArrayList<Class>();
//拿到主类的ClassLoader 用于获取URL路径
ClassLoader classLoader = HufApplicationContext.class.getClassLoader();
//"com.huf.service" 替换为 "com/huf/service"
compomentScanPath = compomentScanPath.replace(".","/");
//获得URL 用于创建File
URL resource = classLoader.getResource(compomentScanPath);
//利用URL 创建File 文件
File file = new File(resource.getFile());
//是否是目录
if (file.isDirectory()) {
//获取目录下面所有Files
File[] files = file.listFiles();
if(files.length>0){
//获取到File后; 遍历
for (File f : files) {
//获取 Class的 路径 :E:\\Users\\Administrator\\hufSpring\\target\\classes\\com\\huf\\service\\StudentService.class
String fileName = f.getAbsolutePath();
if (fileName.endsWith(".class")) {
//截取名字;
String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
className = className.replace("\\\\", ".");
try {
//通过名字拿到相对应的Clazz;
Class<?> clazz = classLoader.loadClass(className);
//加入集合 尾部返回;
beanClasses.add(clazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
return beanClasses;
}
//三
private void instanceSingletonBean() {
//遍历beanDefinitionMap 得到beanDefinition集合;
for (String beanName : beanDefinitionMap.keySet()) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition.getScope().equals(ScopeEnum.singleton)) {
//如果该类是单例类 就开始创建;
Object bean = doCreateBean(beanName, beanDefinition);
singletonObjects.put(beanName, bean);
}
}
}
private Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
//通过BeanDefinition获取Class;
Class beanClass = beanDefinition.getBeanClass();
try {
// 获取构建对象;
Constructor declaredConstructor = beanClass.getDeclaredConstructor();
//得到实例化对象
Object instance = declaredConstructor.newInstance();
// 拿到当前对象的每个属性;
// 这里举个例子 Autowired 简化;
Field[] fields = beanClass.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
String fieldName = field.getName();
Object bean = getBean(fieldName);
field.setAccessible(true);
field.set(instance, bean);
}
}
// Aware回调
if (instance instanceof BeanNameAware) {
((BeanNameAware)instance).setBeanName(beanName);
}
//beanPostProcessorList 提取到所有 处理器 这是 在初始化前 调用该方法; 重要
for (BeanPostProcessor beanPostProcessor: beanPostProcessorList) {
beanPostProcessor.postProcessBeforeInitialization(beanName, instance);
}
// 初始化
if (instance instanceof InitializingBean) {
((InitializingBean)instance).afterPropertiesSet();
}
//beanPostProcessorList 提取到所有 处理器 这是 在初始化后 调用该方法; 重要
for (BeanPostProcessor beanPostProcessor: beanPostProcessorList) {
//这里很关键 代理对象就是在这里创建的. 我们有一个StudentPostProcessor 类;
instance = beanPostProcessor.postProcessAfterInitialization(beanName, instance);
}
return instance;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public Object getBean(String beanName) {
if (singletonObjects.containsKey(beanName)) {
return singletonObjects.get(beanName);
} else {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
return doCreateBean(beanName, beanDefinition);
}
}
}
package huf_spring;
/**
* 该类是主要 目的是为了保存类的相关信息;
* ps : 是类的相关信息; 它是 Spring定义类的基石; 非常非常重要!
* 在实际情况下 当spring容器启动的时候会去调用ConfigurationClassPostProcessor这个bean工厂的后置处理器完成扫描;
* 当扫描到的Class文件 里面有很多信息需要保存 例如 class中的 scope、lazy,等等信息; 它的信息不止以下几个属性;
* BeanDefinition 是 Spring 设计出来保存这些信息的;
*
* auth:huf
*/
public class BeanDefinition {
private Class beanClass;
private ScopeEnum scope;
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
public ScopeEnum getScope() {
return scope;
}
public void setScope(ScopeEnum scope) {
this.scope = scope;
}
}
package huf_spring;
/**
* 后置处理器; 它主要作用于在Bean的初始化前 初始化后
* 该接口用于Bean的初始化
* 是Spring IOC容器给我们提供的一个扩展接口
* auth:huf
*/
public interface BeanPostProcessor {
//Bean初始化前
Object postProcessBeforeInitialization(String beanName, Object bean);
//Bean初始化后;
Object postProcessAfterInitialization(String beanName, Object bean);
}
package com.huf.service;
import huf_spring.BeanPostProcessor;
import huf_spring.Service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* StudentService 实现 BeanPostProcessor 类
* 在一开始就Bean初始化的时候就已经实例化 加载进入了 List<BeanPostProcessor> 中等待调用
* 这个地方仅仅使用类扫描后 使用的方法是 BeanPostProcessor.class.isAssignableFrom(clazz) 就得到了这个类的实例;
* 具体请看 hufApplicationContext
* auth:huf
*/
@Service("hufPostProcessor")
public class HufPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(String beanName, Object bean) {
System.out.println("前置方法执行:"+beanName);
return bean;
}
public Object postProcessAfterInitialization(String beanName, final Object bean1) {
System.out.println("后置方法执行:"+beanName);
//开始创建动态代理 这里为了方便直接使用JDK代理; 因为JDK代理 是使用接口代理的;
Object proxyInstance = null;
if(beanName.equals("teacherService")){
proxyInstance = Proxy.newProxyInstance(HufPostProcessor.class.getClassLoader(), bean1.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("切入点:test方法");
method.invoke(bean1,args);
System.out.println("切入点:test之后");
return null;
}
});
return proxyInstance;
}
return proxyInstance!=null?proxyInstance:bean1;
}
}
以下为运行结果集:
总结
至此; BeanPostProcessor or BeanDefinition or Aware or InitializingBean 以及Bean的详细创建过程 已经全部模拟完毕; 感兴趣的小伙伴 可以 (源码下载):环境只需要一个JDK1.8 其他任何包都不用加;
以上是关于Spring原理篇--BeanPostProcessor or BeanDefinition or Aware or InitializingBean的主要内容,如果未能解决你的问题,请参考以下文章