目录

导语

Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。也是几乎所有Java工作者必须要掌握的框架之一,其优秀的设计思想以及其代码实现上的艺术也是我们需要掌握的。要学习Spring,除了在我们的项目中使用之外,也需要对它的源码进行研读,但是Spring的实现涵盖的知识很多,在加上其中的类的数量也是非常的多,在我们阅读源码时可能会在几十个类之间穿插阅读,很有可能一不小心就导致思维混乱。有鉴于此,我这里先对Spring中的几个重要的模块进行一个手动的简易实现,一是熟悉这些模块的原理,同时也是仿造Spring中的结构来对后面阅读源码打下基础。

IOC(Inversion of Control)

Inversion of Control即控制反转,其意思是将我们之前由客户端代码来创建的对象交由IOC容器来进行控制,对象的创建,初始化以及后面的管理都由IOC完成。

IOC的好处

  1. 解耦:IOC的出现解决了类于类之间的耦合,我们在Web开发的Servlet时代,如果一个Servlet需要依赖另一个类的某些实现,那么我们需要在当前类对依赖的类进行创建和初始化,如果其他类也依赖了这个类,那也需要进行创建和初始化,而交给了IOC来管理的话,那么在需要的时候只需向IOC进行申请,而不需要重复的创建和初始化。当然,IOC也允许每次都重新创建一个新的对象。
  2. 方便与AOP进行配合:AOP也是一个使用十分频繁的功能,通过IOC可以十分方便的与AOP进行配合。

IOC中设计的设计模式

工厂模式。IOC容器来负责创建管理类实例对象,在需要时向IOC进行申请,从IOC中获取。所以IOC容器也称为bean工厂。

工厂模式是一种比较简单易懂的设计模式,这里就不在介绍了,如果有需要的可以看看这个:工厂模式

IOC的手动实现

Bean定义

IOC的主要的功能便是对Bean进行管理,包括创建、初始化、管理以及销魂的工作。首先我们面对的问题就是我们怎么让IOC能够创建一个Bean?为了创建Bean我们需要提供一些什么?

如何创建Bean

在不手动通过new关键字创建的情况下创建类实例的对象方法有两种:

  1. 反射:通过反射的方法可以创建类的实例:clazz.getClass().newInstance();
  2. 工厂模式:工厂模式可以让我们在不接触实例类的情况下创建出实例。
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。

代码实现

到这里我们实现一个简易的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的原理及手动实现的更多相关文章

  1. Spring系列之DI的原理及手动实现

    目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 前言 在上一章中,我们介绍和简单实现了容器的部分功能,但是这里还留下了很多的问题.比如我们在构造bean实例的时 ...

  2. Spring系列之AOP的原理及手动实现

    目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 引入 到目前为止,我们已经完成了简易的IOC和DI的功能,虽然相比如Spring来说肯定是非常简陋的,但是毕竟我 ...

  3. 理解Spring:IOC的原理及手动实现

    Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架.也是几乎所有Java工作者必须要掌握的框架之一,其优秀的设计思想以及其代码实现上的艺术也是我们需要掌握的. ...

  4. Spring系列-SpringBase+IOC

    Spring 一.前言 Thinking is more important than learning 本文主要讲述spring 以及它的 IOC原理 代码地址:https://gitee.com/ ...

  5. Spring系列(1)--IOC 和 DI

    IOC 和 DI IOC 原理 xml 配置文件配置 bean dom4j 读取配置文件 工厂设计模式 反射机制创建对象 applicationContext.xml 配置文件,该配置文件名可自定义: ...

  6. Spring系列之IOC容器

    一.概述 IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化.定位.配置应用程序中的对象及建立这些对象之间的依赖.应用程序无需直接在代码中new 相关的对象,应用程序由IOC容器进行组装.在S ...

  7. Spring系列之手写一个SpringMVC

    目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 Spring系列之AOP的原理及手动实现 Spring系列之手写注解与配置文件的解析 引言 在前面的几个章节中我 ...

  8. Spring系列之手写注解与配置文件的解析

    目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 Spring系列之AOP的原理及手动实现 引入 在前面我们已经完成了IOC,DI,AOP的实现,基本的功能都已经 ...

  9. 通俗化理解Spring3 IoC的原理和主要组件(spring系列知识二总结)

    ♣什么是IoC? ♣通俗化理解IoC原理 ♣IoC好处 ♣工厂模式 ♣IoC的主要组件 ♣IoC的应用实例 ♣附:实例代码 1.什么是IoC(控制反转)? Spring3框架的核心是实现控制反转(Io ...

随机推荐

  1. HDU6011

    巨香蕉牛奶猪皮怪的坑人,刚开始想错了,我先建了一个结构体储存每个字母的价值和数量,然后全部情况列出来进行计算,就是一次挪动一个字符看总之的变化,但是我原来错在了每次挪动的是全部相同的那一个字符,后来只 ...

  2. loadtxt函数

    numpy.loadtxt numpy.loadtxt(fname, dtype=<type 'float'>, comments='#', delimiter=None, convert ...

  3. C#学习笔记14——TRACE、DEBUG和TRACESOURCE的使用以及日志设计

    Trace.Debug和TraceSource的使用以及日志设计   .NET Framework 命名空间 System.Diagnostics 包含用于跟踪执行流程的 Trace.Debug 和 ...

  4. Startls Back 引起的 win10升级之后的闪屏问题

    win10 更新之后出现闪频问题. 有人说是和startls back 有关,需要卸载startls back, 但是进入安全模式下显示此 程序无法打开,无法卸载. 后来看到有人更新到startls ...

  5. 87、代码适配IphoneX

    一.APP在iphoneX运行后不能占满,上下都有多余的边 解决方法:把旧的image.xcassets中的LaunchImage删掉,重新创建并在Images.xcassets中为iPhone X添 ...

  6. ajax动态刷新的元素,导致绑定事件失效

    jquery事件绑定有2种方式: 1,普通事件绑定: $('元素').click(function(){}); 2, 事件代理或者叫事件委托 $('#chatPanelList').on('click ...

  7. Maven搭建SSH框架

    工具:Eclipse(Maven管理工具)+Tomcat+Mysql. 1.新建一个Maven工程(maven-archetype-webapp). 打开File ——>new——>Mav ...

  8. Exp4 恶意代码分析 20154320 李超

    恶意代码 概述 恶意代码是指故意编制或设置的.对网络或系统会产生威胁或潜在威胁的计算机代码.最常见的恶意代码有计算机病毒(简称病毒).特洛伊木马(简称木马).计算机蠕虫(简称蠕虫).后门.逻辑炸弹等. ...

  9. 【python-appium】Appium的一些坑问题错误解决 与 技巧集锦

    问题 1. error: Failed to start an Appium session, err was: Error: Requested a new session but one was ...

  10. Android开发者的Anko使用指南(一)之Intent

    使用Anko Intent帮助器可以添加如下依赖 dependencies { compile "org.jetbrains.anko:anko-commons:$anko_version& ...