美文网首页
架构学习之路(三)-- IOC

架构学习之路(三)-- IOC

作者: 魔改谢馒头 | 来源:发表于2018-08-24 18:39 被阅读0次

参考:
https://studygolang.com/articles/13783?fr=sidebar
https://studygolang.com/articles/7716
先写着,我现在吃不透原理
一、IOC
Ioc的思想就是解耦,只依赖容器而不依赖具体的类,当你的类有修改时,最多需要改动一下容器相关代码,业务代码并不受影响。
主要原理通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象,这种编程方式可以让对象在生成时才决定到底是哪一种对象。
我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。

golang的依赖注入原理

步骤如下:(golang不支持动态创建对象,所以需要先手动创建对象然后注入,java可以直接动态创建对象)

1.通过反射读取对象的依赖(golang是通过tag实现)
2.在容器中查找有无该对象实例
3.如果有该对象实例或者创建对象的工厂方法,则注入对象或使用工厂创建对象并注入
4.如果无该对象实例,则报错

代码实现
package di

import (
    "sync"
    "reflect"
    "fmt"
    "strings"
    "errors"
)

var (
    ErrFactoryNotFound = errors.New("factory not found")
)

type factory = func() (interface{}, error)
// 容器
type Container struct {
    sync.Mutex
    singletons map[string]interface{}
    factories  map[string]factory
}
// 容器实例化
func NewContainer() *Container {
    return &Container{
        singletons: make(map[string]interface{}),
        factories:  make(map[string]factory),
    }
}

// 注册单例对象
func (p *Container) SetSingleton(name string, singleton interface{}) {
    p.Lock()
    p.singletons[name] = singleton
    p.Unlock()
}

// 获取单例对象
func (p *Container) GetSingleton(name string) interface{} {
    return p.singletons[name]
}

// 获取实例对象
func (p *Container) GetPrototype(name string) (interface{}, error) {
    factory, ok := p.factories[name]
    if !ok {
        return nil, ErrFactoryNotFound
    }
    return factory()
}

// 设置实例对象工厂
func (p *Container) SetPrototype(name string, factory factory) {
    p.Lock()
    p.factories[name] = factory
    p.Unlock()
}

// 注入依赖
func (p *Container) Ensure(instance interface{}) error {
    elemType := reflect.TypeOf(instance).Elem()
    ele := reflect.ValueOf(instance).Elem()
    for i := 0; i < elemType.NumField(); i++ { // 遍历字段
        fieldType := elemType.Field(i)
        tag := fieldType.Tag.Get("di") // 获取tag
        diName := p.injectName(tag)
        if diName == "" {
            continue
        }
        var (
            diInstance interface{}
            err        error
        )
        if p.isSingleton(tag) {
            diInstance = p.GetSingleton(diName)
        }
        if p.isPrototype(tag) {
            diInstance, err = p.GetPrototype(diName)
        }
        if err != nil {
            return err
        }
        if diInstance == nil {
            return errors.New(diName + " dependency not found")
        }
        ele.Field(i).Set(reflect.ValueOf(diInstance))
    }
    return nil
}

// 获取需要注入的依赖名称
func (p *Container) injectName(tag string) string {
    tags := strings.Split(tag, ",")
    if len(tags) == 0 {
        return ""
    }
    return tags[0]
}

// 检测是否单例依赖
func (p *Container) isSingleton(tag string) bool {
    tags := strings.Split(tag, ",")
    for _, name := range tags {
        if name == "prototype" {
            return false
        }
    }
    return true
}

// 检测是否实例依赖
func (p *Container) isPrototype(tag string) bool {
    tags := strings.Split(tag, ",")
    for _, name := range tags {
        if name == "prototype" {
            return true
        }
    }
    return false
}

// 打印容器内部实例
func (p *Container) String() string {
    lines := make([]string, 0, len(p.singletons)+len(p.factories)+2)
    lines = append(lines, "singletons:")
    for name, item := range p.singletons {
        line := fmt.Sprintf("  %s: %x %s", name, &item, reflect.TypeOf(item).String())
        lines = append(lines, line)
    }
    lines = append(lines, "factories:")
    for name, item := range p.factories {
        line := fmt.Sprintf("  %s: %x %s", name, &item, reflect.TypeOf(item).String())
        lines = append(lines, line)
    }
    return strings.Join(lines, "\n")
}

相关文章

  • 架构学习之路(三)-- IOC

    参考:https://studygolang.com/articles/13783?fr=sidebarhttps...

  • 第二章 IoC容器概述

    IoC容器 Spring模块架构图-IoC容器 IoC容器处于Spring模块架构比较核心的地位,它向上层的AOP...

  • 论三年前

    三年前只要懂“三层架构”就可以说“精通分层架构”;现在则需要懂IOC(AutoFac等)、CodeFirst、la...

  • IOC

    架构 IOC容器 ------- spring容器(bean) -------- DefaultListenab...

  • Spring IOC

    IOC IOC 全名控制反转(Inverse of Control),它是一种编程原则(设计思想),它的设计和架构...

  • 架构之路

    1. 架构之路 (一) —— iOS原生系统架构(一)2. 架构之路 (二) —— APP架构分析(一)3. 架构...

  • spring之控制反转和依赖注入

    Spring学习(三)IOC控制反转与DI依赖注入

  • Android 架构师之路 目录

    Android 架构师之路 目录 Android 架构师之路1 UML图之用例图Android 架构师之路2 UM...

  • Spring IOC/DI

    Spring整体架构设计 Spring IOC容器: 在了解Spring IOC容器之前我们需要了解一些概念: 依...

  • Spring框架的理解

    一:IOC和DI的理解 在Java开发中,我们在写Service和Dao,Controller,进行MVC三层架构...

网友评论

      本文标题:架构学习之路(三)-- IOC

      本文链接:https://www.haomeiwen.com/subject/zakiiftx.html