@TOC# Spring系列
记录在程序走的每一步___auth:huf


拨开云雾见天日 守得云开见月明

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();//保存ClassbeanDefinition.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 {//获取该实现类BeanPostProcessorBeanPostProcessor instance = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();//在初始化过程中 它仅仅是把相关实例保存到内存List中 在此处并无调用;请注意;beanPostProcessorList.add(instance);} catch (Exception e) {e.printStackTrace();}}// 解析scopeif (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 该步骤执行完后 返回主流程 开始执行instanceSingletonBeanprivate 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 用于创建FileURL resource = classLoader.getResource(compomentScanPath);//利用URL 创建File 文件File file = new File(resource.getFile());//是否是目录if (file.isDirectory()) {//获取目录下面所有FilesFile[] files = file.listFiles();if(files.length>0){//获取到File后; 遍历for (File f : files) {//获取 Class的 路径 :E:\Users\Administrator\hufSpring\target\classes\com\huf\service\StudentService.classString 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原理篇(2)--BeanPostProcessor or BeanDefinition or Aware or InitializingBean相关推荐

  1. Spring 原理篇

    文章目录 1.1框架简介 1.2 Spring 概述 1.3 环境配置 1.4 环境测试 SpringTest 2.1 控制反转(IOC) 2.1.1 ApplicationContext 的主要实现 ...

  2. Spring原理篇(12)--架构整合流程;该篇章讲解Spring在整合架构的时候的思路;

    @TOC# Spring系列 记录在程序走的每一步___auth:huf 该篇章讲解架构整合的思路: 讲解该篇章主要是为了将之前的知识点进行一个串联: 有很多接口 我仅仅是介绍了它们的使用:并没有实战 ...

  3. Spring 事务原理篇:@EnableTransactionManagement注解底层原理分析技巧,就算你看不懂源码,也要学会这个技巧!

    前言 学习了关于Spring AOP原理以及事务的基础知识后,今天咱们来聊聊Spring在底层是如何操作事务的.如果阅读到此文章,并且对Spring AOP原理不太了解的话,建议先阅读下本人的这篇文章 ...

  4. Spring原理-IOC控制反转

    spring相关文章 Spring原理-IOC控制反转 Spring框架七大核心模块 Spring Beans原理–bean生命周期 一.Spring概述 1. 定义 Spring是一个轻量级Java ...

  5. MyBatis整合Spring原理分析

    目录 MyBatis整合Spring原理分析 MapperScan的秘密 简单总结 假如不结合Spring框架,我们使用MyBatis时的一个典型使用方式如下: public class UserDa ...

  6. 面试大厂不看这两份Java面试核心知识点原理篇+框架篇,有个屁用?食屎啦泥?

    前言 面试在即,Java知识点很凌乱? 别急,有本套书在呢! 除了原理,还有框架! ★ 精细讲解JVM原理.Java基础.并发编程.数据结构和算法.网络与负载均衡 ★ 深入挖掘数据库与分布式事务.分布 ...

  7. Spring原理(二)--循环依赖原理

    此篇文章建立在已经了解bean创建原理之上,若不了解,请先阅读本人上一篇文章 Spring原理(一)–IOC原理 1 场景 @Component public class X {@AutowiredY ...

  8. Spring原理学习系列之三:Spring AOP原理(从源码层面分析)-------上部

    引言 本文是Spring原理分析的第三篇博文,主要阐述Spring AOP相关概念,同时从源码层面分析AOP实现原理.对于AOP原理的理解有利于加深对Spring框架的深入理解.同时我也希望可以探究S ...

  9. Spring原理/SpringMVC原理/IOC/AOP原理

    Spring原理/SpringMVC原理/IOC/AOP原理 我的微型IOC框架实现 我的微型IOC框架实现 当你打开这本书的时候我要告诉你的第一句话就是认真把前言读完,因为前言概括的本书的大纲以及思 ...

最新文章

  1. Cisco交换机与路由器的密码恢复_路由交换
  2. SQL GROUP BY 语句
  3. 互联网时代的云服务器四大功能
  4. 计算机操作日志文件,查看电脑操作记录(LastActivityView)
  5. 使用Gradle的maven-publish插件发布快照
  6. zookeeper 密码_阿里资深JAVA架构带你深度剖析dubbo和zookeeper关系
  7. GBT19056精要
  8. java定时每小时_java 定时任务,每日运行和每小时运行。
  9. Visual Studio Ultimate 2013(VS2013旗舰版 下载地址及哈希校验)
  10. [2001年写的小说]星际争霸之外传
  11. Linux进阶 | 2万字总结最详细的Docker的安装、底层隔离机制和简单使用!建议收藏,持续更新❤
  12. springboot+英语在线学习系统 毕业设计-附源码211714
  13. php的strtoupper,关于PHP的strtoupper函数
  14. Tet3在前脑神经元中对抗焦虑
  15. Python学习基础笔记三十二——正则表达式
  16. Hi3516D V300功能介绍
  17. 曹操梦中杀人应该是可信的
  18. 加班奖金终于发下来了!3060显卡自费包邮送!
  19. 修改Discuz! X2标题、底部和Archiver页面的版权信息
  20. easy-captcha实现验证码功能

热门文章

  1. 钟艳明2019年个人诗集
  2. 朗润国际期货招商:日本“伯南克”和他的MIT校友
  3. Failed to start docker.service: Unit not found(Docker服务起不来)
  4. 龙芯3B处理器—地址映射以及路由地址分布与配置
  5. win7连接wifi显示有限的访问权限,没有有效的IP配置,无法上网问题的解决办法
  6. 什么是模板缓冲(Stencil Buffer)
  7. 宏基acer aod257上网本安装使用xp,windows7心得
  8. 利用ffmpeg将微信speex格式转为wav或mp3
  9. 深入理解:js标签中的type=“text/JavaScript“,表示什么意思
  10. windows安装mactype启用mac字体渲染