理解Spring:IOC的原理及手动实现
Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。也是几乎所有Java工作者必须要掌握的框架之一,其优秀的设计思想以及其代码实现上的艺术也是我们需要掌握的。
要学习Spring,除了在我们的项目中使用之外,也需要对它的源码进行研读,但是Spring的实现涵盖的知识很多,在加上其中的类的数量也是非常的多,在我们阅读源码时可能会在几十个类之间穿插阅读,很有可能一不小心就导致思维混乱。
有鉴于此,我这里先对Spring中的几个重要的模块进行一个手动的简易实现,一是熟悉这些模块的原理,同时也是仿造Spring中的结构来对后面阅读源码打下基础。
IOC(Inversion of Control)
Inversion of Control即控制反转,其意思是将我们之前由客户端代码来创建的对象交由IOC容器来进行控制,对象的创建,初始化以及后面的管理都由IOC完成。
IOC的好处
解耦:IOC的出现解决了类与类之间的耦合,我们在Web开发的Servlet时代,如果一个Servlet需要依赖另一个类的某些实现,那么我们需要在当前类对依赖的类进行创建和初始化,如果其他类也依赖了这个类,那也需要进行创建和初始化,而交给了IOC来管理的话,那么在需要的时候只需向IOC进行申请,而不需要重复的创建和初始化。当然,IOC也允许每次都重新创建一个新的对象。
方便与AOP进行配合:AOP也是一个使用十分频繁的功能,通过IOC可以十分方便的与AOP进行配合。
IOC中设计的设计模式
工厂模式。IOC容器来负责创建管理类实例对象,在需要时向IOC进行申请,从IOC中获取。所以IOC容器也称为bean工厂。
工厂模式是一种比较简单易懂的设计模式,这里就不在介绍了,如果有需要的可以看看工厂模式。
IOC的手动实现
Bean定义
IOC的主要的功能便是对Bean进行管理,包括创建、初始化、管理以及销毁的工作。首先我们面对的问题就是我们怎么让IOC能够创建一个Bean?为了创建Bean我们需要提供一些什么?
如何创建Bean
在不手动通过new关键字创建的情况下创建类实例的对象方法有两种:
- 反射:通过反射的方法可以创建类的实例:clazz.getClass().newInstance();。
- 工厂模式:工厂模式可以让我们在不接触实例类的情况下创建出实例。
public class PersonFactory{
public Person getPerson(){
return new Person();
}
}
为了创建Bean我们需要提供什么
通过分析上面的两种方法可以轻松得出答案。
对于反射的方式我们仅需提供实例的Class对象。
对于工厂方法我们需要提供的就是创建该类的工厂名(factoryName)和方法名(methodName);
除了创建bean还需要做些什么
IOC容器是对bean的整个生命周期进行管理,除了创建之外还需要对bean进行初始化,以及不需要时对bean进行销毁的工作(如释放资源等)。所以我们还需要提供初始化和销毁等操作。
到这里创建bean需要的基本分析完了,看类图:
Bean工厂
Bean的定义解决了,但是这个bean定义以及创建好的Bean实例放在哪里呢,我们需要一个统一的地方来存放这些东西以方便我们要用的时候方便取。
我们定义一个Bean工厂来存放bean,在需要的时候从bean工厂中取即可,bean工厂对外提供的也仅仅是一个获取bean的方法即可,由于bean的类型不定,所以返回值定位Object。
注册Bean定义
到了现在我们有了创建bean的Bean定义,有了存放和管理bean的Bean工厂,现在需要考虑的是怎么来联系这两个类,我们还需要另外一个接口,接口的功能是让我们能注册和获取bean定义,这里我们通过beanName来区分不同的bean。参考:深究Spring中Bean的生命周期
代码实现
到这里我们实现一个简易的IOC容器的需要的东西基本准备完成了,看下基本类图:
基本代码实现:
DefaultBeanDefinition:
public class DefaultBeanDefinition implements BeanDefinition{
private Class<?> clazz;
private String beanFactoryName;
private String createBeanMethodName;
private String staticCreateBeanMethodName;
private String beanInitMethodName;
private String beanDestoryMethodName;
private boolean isSingleton;
// setter
public void setSingleton(boolean singleton) {
isSingleton = singleton;
}
@Override
public Class<?> getBeanClass() {
return this.clazz;
}
@Override
public String getBeanFactory() {
return this.beanFactoryName;
}
@Override
public String getCreateBeanMethod() {
return this.createBeanMethodName;
}
@Override
public String getStaticCreateBeanMethod() {
return this.staticCreateBeanMethodName;
}
@Override
public String getBeanInitMethodName() {
return this.beanInitMethodName;
}
@Override
public String getBeanDestoryMethodName() {
return this.beanDestoryMethodName;
}
@Override
public String getScope() {
return this.isSingleton?BeanDefinition.SINGLETION :BeanDefinition.PROTOTYPE;
}
@Override
public boolean isSingleton() {
return this.isSingleton;
}
@Override
public boolean isPrototype() {
return !this.isSingleton;
}
}
DefaultBeanFactory:
public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Closeable {
private Log log = LogFactory.getLog(this.getClass());
//ConcurrentHashMap应对并发环境
private Map<String, BeanDefinition> bdMap = new ConcurrentHashMap<>();
private Map<String, Object> beanMap = new ConcurrentHashMap<>();
@Override
public void register(BeanDefinition bd, String beanName) {
Assert.assertNotNull("beanName不能为空 beanName", beanName);
Assert.assertNotNull("BeanDefinition不能为空", bd);
if(bdMap.containsKey(beanName)){
log.info("[" + beanName + "]已经存在");
}
if(!bd.validate()){
log.info("BeanDefinition不合法");
}
if(!bdMap.containsKey(beanName)){
bdMap.put(beanName, bd);
}
}
@Override
public boolean containsBeanDefinition(String beanName) {
return bdMap.containsKey(beanName);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) {
if(!bdMap.containsKey(beanName)){
log.info("[" + beanName + "]不存在");
}
return bdMap.get(beanName);
}
public Object doGetBean(String beanName) throws InstantiationException, IllegalAccessException {
if(!beanMap.containsKey(beanName)){
log.info("[" + beanName + "]不存在");
}
Object instance = beanMap.get(beanName);
if(instance != null){
return instance;
}
//不存在则进行创建
if(!this.bdMap.containsKey(beanName)){
log.info("不存在名为:[" + beanName + "]的bean定义");
}
BeanDefinition bd = this.bdMap.get(beanName);
Class<?> beanClass = bd.getBeanClass();
if(beanClass != null){
instance = createBeanByConstruct(beanClass);
if(instance == null){
instance = createBeanByStaticFactoryMethod(bd);
}
}else if(instance == null && StringUtils.isNotBlank(bd.getStaticCreateBeanMethod())){
instance = createBeanByFactoryMethod(bd);
}
this.doInit(bd, instance);
if(instance != null && bd.isSingleton()){
beanMap.put(beanName, instance);
}
return instance;
}
private void doInit(BeanDefinition bd, Object instance) {
Class<?> beanClass = instance.getClass();
if(StringUtils.isNotBlank(bd.getBeanInitMethodName())){
try {
Method method = beanClass.getMethod(bd.getBeanInitMethodName(), null);
method.invoke(instance, null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 构造方法创建实例
* @param beanClass
* @return
*/
private Object createBeanByConstruct(Class<?> beanClass) {
Object instance = null;
try {
instance = beanClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
/**
* 普通工厂方法创建实例
* @param bd
* @return
*/
private Object createBeanByFactoryMethod(BeanDefinition bd) {
Object instance = null;
try {
//获取工厂类
Object factory = doGetBean(bd.getBeanFactory());
//获取创建实例的方法
Method method = factory.getClass().getMethod(bd.getCreateBeanMethod());
//执行方法
instance = method.invoke(factory, null);
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
/**
* 静态方法创建实例
* @param bd
* @return
*/
private Object createBeanByStaticFactoryMethod(BeanDefinition bd) {
Object instance = null;
try {
Class<?> beanClass = bd.getBeanClass();
//获取创建实例的方法
Method method = beanClass.getMethod(bd.getStaticCreateBeanMethod());
instance = method.invoke(beanClass, null);
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
@Override
public Object getBean(String beanName) {
if(!beanMap.containsKey(beanName)){
log.info("[" + beanName + "]不存在");
}
return beanMap.get(beanName);
}
@Override
public void close() throws IOException {
Set<Map.Entry<String, BeanDefinition>> entries = bdMap.entrySet();
for(Map.Entry<String, BeanDefinition> entry: entries){
BeanDefinition value = entry.getValue();
String destoryMethodName = value.getBeanDestoryMethodName();
try {
Method method = value.getBeanClass().getMethod(destoryMethodName, null);
method.invoke(value.getBeanClass(), null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
简单测试一下:实例bean:
public class User {
private String name;
private int age;
//getter setter
public void init(){
System.out.println("init...");
}
public void destory(){
System.out.println("destory...");
}
}
工厂类:
public class TestFactory {
public Object createMethod(){
return new User();
}
public static Object staticCreateMethod(){
return new User();
}
}
测试类:
public class MySpringTest {
static DefaultBeanFactory factory = new DefaultBeanFactory();
@Test
public void test() throws IllegalAccessException, InstantiationException {
DefaultBeanDefinition bd = new DefaultBeanDefinition();
bd.setClazz(User.class);
bd.setSingleton(true);
bd.setBeanFactoryName("TestFactory");
bd.setCreateBeanMethodName("createMethod");
bd.setStaticCreateBeanMethodName("staticCreateMethod");
bd.setBeanInitMethodName("init");
factory.register(bd, "user");
System.out.println(factory.doGetBean("user"));
}
}
小结
一个简易的容器就这样实现了,当然我们这里只是具备了基本的功能,实际上还差的远,比如带参数的bean的实例化等功能。但是IOC的基本原理已经表达出来了,后面我们只需在这个基础上添加新的功能即可。
理解Spring:IOC的原理及手动实现的更多相关文章
- 深入理解Spring IOC工作原理
为什么会出现spring,spring出现解决了什么问题? 1.分析普通多层架构存在的问题 JSP->Servlet->Service->Dao 层与层之间的依赖很强,属于耦合而且是 ...
- 通俗化理解Spring3 IoC的原理和主要组件(spring系列知识二总结)
♣什么是IoC? ♣通俗化理解IoC原理 ♣IoC好处 ♣工厂模式 ♣IoC的主要组件 ♣IoC的应用实例 ♣附:实例代码 1.什么是IoC(控制反转)? Spring3框架的核心是实现控制反转(Io ...
- Spring系列之IOC的原理及手动实现
目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 导语 Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架.也是几乎所有J ...
- Spring IOC设计原理解析:本文乃学习整理参考而来
Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. I ...
- Spring框架系列(6) - Spring IOC实现原理详解之IOC体系结构设计
在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解.本文将帮助你站在设计者的角度去看IOC最顶层的结构设计.@pdai Spring框架系列(6) - Spring IOC实现原理详解 ...
- Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程
上文,我们看了IOC设计要点和设计结构:紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的. ...
- Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)
上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ...
- spring ioc aop 原理
spring ioc aop 原理 spring ioc aop 的原理 spring的IoC容器是spring的核心,spring AOP是spring框架的重要组成部分. 在传统的程序设计中,当调 ...
- Spring IoC底层原理
-------------------siwuxie095 Spring IoC 底层原理 1.IoC 即 Invers ...
- Java工厂模式解耦 —— 理解Spring IOC
Java工厂模式解耦 -- 理解Spring IOC 最近看到一个很好的思想来理解Spring IOC,故记录下来. 资源获取方式 主动式:(要什么资源都自己创建) 被动式:(资源的获取不是我们创建, ...
随机推荐
- 多线程-2.线程创建方式和Thread类
线程的创建方式 1.继承Thread类,重写run方法,示例如下: 1 class PrimeThread extends Thread { 2 long minPrime; 3 PrimeThrea ...
- restful 与 webapi 详解
restful 什么是API API全称Aplication Programming Itererface即应用程序编程接口, 我们在开发应用程序时经常用到.API作为接口,用来"连接&qu ...
- 矩阵旋转-Eigen应用(QTCreator编辑器)
* { font-family: "Tibetan Machine Uni", "sans-serif", STFangSong; outline: none ...
- 【Azure 环境】基于Azure搭建企业级内部站点, 配置私有域名访问的详细教程 (含演示动画)
前言 在Azure中,可以通过App Service快速部署,构建自定义站点(PaaS服务).默认情况下,这些站点被访问URL都是面向公网,通过公网进行解析.为了最好的安全保障,是否可以有一种功能实现 ...
- Mac OSX系统homebrew update Fetching failed问题解决方案
1. brew update error (i) 问题出现及现象描述 昨天换了台电脑,有些软件需要重新安装或更新一下,遇到了下面的问题 cv@xys-MacBook-Pro ~ % brew upda ...
- [Qt] Librecad 源码分析
libraries jwwlib libdxfrw:一个免费的C++库,用于读写文本格式或二进制格式的DXF文件(C++ library to read and write DXF/DWG files ...
- linux操作系统优化系列-RAID不同阵列模式的选择
背景 笔者所在的某通信运营商某大数据项目由于应用面临瓶颈需要扩充服务器设备,当初上这个项目的时候,服务器上线前的工作(配置raid,安装操作系统,Infiniband网络调试,系统漏洞安全加固)都是我 ...
- 详解Linux中的cat文本输出命令用法
作系统 > LINUX > 详解Linux中的cat文本输出命令用法 Linux命令手册 发布时间:2016-01-14 14:14:35 作者:张映 我要评论 这篇 ...
- 通用PE u盘装Ghost Win7系统教程
通用PE u盘装Ghost Win7系统教程 导读 通用pe工具箱是现在最老牌的的U盘装系统和维护电脑的专用工具之一,一键式制作.操作简单便捷,几乎100%支持所有U盘,不再为装机烦恼们,抓紧时间下载 ...
- 转载 https://www.cnblogs.com/bobo-pcb/p/11708459.html
https://www.cnblogs.com/bobo-pcb/p/11708459.html #### 1 用VMware 15.0+win10企业版 1次安装成功 20200124 2 不要用v ...