浅谈Spring IOC (IOC模型)

Posted HUTEROX

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈Spring IOC (IOC模型)相关的知识,希望对你有一定的参考价值。

前言

关于目前我们先解读关于Spring的IOC部分,这个也是个大头。下面是某个大佬的文章,不过这里并不是说查看人家的文章,而是通过自己的理解实现一个简单的IOC容器,后面再将其“标准化”和Spring对接实现对Spring的拓展。当然我们现在这边还是容器部分的实现。这部分实现了,那个后面的不就自然而然嘛。

(我本人没有深入去了解,我们先根据自己的理解去实现一个我们自己理解的IOC,然后再去对比修正)

单纯的通过文章目录 不难发现其实关于 这部分的实现大致还是三大块

  1. 对XML的解析读取(前面的BeanDefinition我认为其实还是对Bean怎么在XML当中自动存储进行初始化定义)
  2. 对读取到的 XML 文件解析得到对象
  3. 通过对象进行组装,实现相应的模式(例如功单例模式,多例模式,包括后面的AOP面向切面也是在这部分后面)

现在我们大致应该是知道了一个流程,这个流程其实和先前的谋篇文章的思路有点类似。

Java Dome(AOP模式回顾小Dome)

其实这里也是使用到了我们类似的一个模式

那么这里为了规范我们自己去简单规划一下,还是大体分三个部分。

说明

BeanDaulft

首先是 BeanDaulft 这个是对Java Bean 进行一个简单的初始化,如何对一个类进行存储定义。这里考虑到文章的篇幅和简单实现,所以我们这次不是通过 XML 去实现,而是通过 peropriter 配置文件去实现,对我们这边容器进行定义

BeanFactory

这个玩意主要就是读取配置文件当中的玩意,之后我们把配置文件当中的内容组合在一块,也就是通过java反射和内省(Class.forname(),Introspector)我们读取到IO流然后组装。

BuilderBean

这个其实是对前面的那两个玩意进行调配其实,也就是我们获取一个搞定好的BeanFactory,之后我们通过BeanFactory进行对象的创建。这个非常重要,因为如果我们想要实现单例模式,或者多例模式我们就必须得到一个BeanFactory然后对其进行封装。

对比Spring操作

通过我们说明我们大致明白了每一个包所充当的功能角色。那么具体实现的结果其实大致会和前面那篇文章 实现 AOP 的类似

package day07;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

public class AOPDomeTest 
    public static void main(String[] args) 

        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("day07/bean.properties");
        try 
            BeanFactory beanFactory = new BeanFactory(new InputStreamReader(in,"utf8"));
            SendAgentFindHouse sendAgentFindHouse = (SendAgentFindHouse) beanFactory.getBean("bean.SendAgentFindHouse");
            BuyHouse buyHouse = (BuyHouse) sendAgentFindHouse.SendAgent();
            buyHouse.buyHouse();

         catch (UnsupportedEncodingException e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        
    
    


这个是那个AOP最终调用的代码 你会发现一个神奇的玩意叫做:

beanFactory.getBean("bean.SendAgentFindHouse");

之后你再对比Spring最原始使用xml注解实现的getBean() 的调用

这里Spring通过上下文 Context 来获取了我们的配置文件,这个配置文件放了这个东西

我通过id Hello 我就是获取了 com.huterox.pojo.Hello 这个Class 然后通过反射去做,只不过前面是那个通过

懂了吧,你再看看我先前的项目结构(这些都是防在 day07这个包下面的(至于是不是第七天学的我就不知道了,有点遗憾的是那个源代码找不到了,不然我不会去再一遍))

OK 那么现在我们通过对比 Spring 最原始的一个操作之一 搞清楚了我们这个几个包到底要做啥。那么我们就实际动动小手

我们这边为了先简便一点,我们就先把 properites 文件命名为 Application 毕竟我们今天没有上下文支持。

大概长这样,目前(不着急,咱们还是要慢慢优化滴)

那么首先我们这个还是比较原始滴,在我们自己定义一个类的时候要写你想要对应的ID 和所在包名的类

也就是先前那种写法

后面我在通过注解的方式来实现,还是比较简单滴。

V0.001 初步模型

OK那么现在我们开始来探讨一下先如何实现那个获取配置文件,然后就拿到我们生成的对象的操作。

效果

行,咱们先来看看结果

首先咱们是在 Test包下面创建了一个Hello类

这里咱们还是先探讨最简单的模式,假设我们只需要简单的去让它创建一个对象。先不需要去给具体的对象值(当然这个其实也是用反射的厉害之处,管你是不是公开的,私有的我可以给你搞出来)

这个时候你可能有点迷糊,这玩意我直接new不香吗。首先我们搞清楚咱们的需求,如果我们是自己写的项目,那当然每一个包都可以管理的好好的。但是如果这是一个大型项目,我们必然需要一个机制来统一管理我们所有的类,也可说是 “中央集权” 那么为什么要用反射呢。要知道直接 new 的效率可比反射高多了(具体可以查看这篇文章(Java反射和new效率对比)这不是我写的),很简单为了拓展未知业务,为了方便统一处理。通过这个我可以让我的核心组件知道可以使用由别人创建的类,举个例子就是 Spring。

实现

说了那么多咱们来看看大概的实现,由于是最简单的版本,所以嘛,超级简单的。

咱们这里不像那个 Spring 需要那么多过滤之类的(我敢打赌 Spring 对 XML 的支持代码都得一大堆)咱们就直接获取配置文件就可以。

而且 咱们现在还没有用到注解,而且不需要实现某些模式,所以直接搞。那么这里就用到了两个类实现。

由上而下:

package BeanDaulft;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.Properties;

public class BeanReader 
    private InputStreamReader inputStreamReader;
    private Properties properties = new Properties();
    public BeanReader()
    public BeanReader(InputStreamReader in) throws IOException 
        this.inputStreamReader = in;
        properties.load(in);
    

    public Properties GetBeanReader()
        return properties;
    

    public Properties GetBeanReader(String FileName) throws IOException 
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(FileName);
        properties.load(new InputStreamReader(in,"utf8"));
        return properties;
    


package BeanFactory;

import BeanDaulft.BeanReader;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;

public class BeanMake 
    private Properties prop;
    private BeanReader beanReader;

    public BeanMake(String Path) throws IOException 
        beanReader = new BeanReader();
        Properties properties = beanReader.GetBeanReader(Path);
        this.prop = properties;

    

    public BeanMake(Properties prop)
        this.prop = prop;
    

    public Object getBean(String name) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException 

        Class<?> beanClass = Class.forName(prop.getProperty(name));
        Object bean = beanClass.getConstructor().newInstance();
        return bean;
    


接下来就是调用嘛

package Test;

public class Hello 
    public void SayHello()
        System.out.println("博主真真帅");
    


Hello = Test.Hello
package Test;

import BeanFactory.BeanMake;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

public class Test 
    public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException 
        BeanMake beanMake = new BeanMake("Application.properties");
        Hello hello = (Hello) beanMake.getBean("Hello");
        hello.SayHello();
    


没错,现在我们就相当于有了一个容器。

至于 先前 Spring 老是扯皮的 IOC 反转控制 ,其实也是这个,所谓反转,其实就是依赖转移,我们通过 BeanFactroy去创建我们的对象

而不是直接 new 一个 ,好处是方面拓展。那么看完这个咱们就可以再去好好看看Spring源码了~

总结

这个呢,其实还只是我自己的理解,不太清楚对不对。不过慢慢纠正嘛,我这个就是单纯的看了看目录,思维导图加上自己的Spring 的一个体验 觉得应该是这样的。那么之后就是 在未来将 开设
Spring 源码研读,JAVA JVM 学习以及 Go 语言专栏。
那么今天暂时到这里,后面我再看看然后验证猜想对不对,实现实现咱们这个小Dome。
最最后 就是那个 关于 WhiteHole 博客社区的源码,这个项目还在开发当中,等能够上线了在推送GitHub,主要是现在缺一个后台管理的前端模板,这个我后面找找。然后就快期末了时间不太够~

以上是关于浅谈Spring IOC (IOC模型)的主要内容,如果未能解决你的问题,请参考以下文章

Spring---浅谈IOC

Spring之IOC

Spring之IoC

[转帖]浅谈IOC--说清楚IOC是什么

[死磕 Spring 4/43] --- IOC 之 获取验证模型

[死磕 Spring 17/43] --- IOC 之从单例缓存中获取单例 bean