pico container 入门介绍

pico container 相比spring而言是一个轻量级的IOC容器。它重点在于实现组件(component)的实例化(instance)和管理组件间的依赖(inject)。

本文基于版本号2.15

基本使用

MutablePicoContainer pico = new DefaultPicoContainer();
pico.addComponent(ArrayList.class); 
List list = pico.getComponent(ArrayList.class);

pico你可以看作是一个hashTable, 你向其中添加了一个key为java.util.ArrayList的class对象,value为ComponentAdapter(用来生产key所指示的对象)的元素。然后再通过key去取出这样的一个实例。


依赖注入

看一个图,如下,绿色表示类,黄色表示接口,箭头由A指向B,表示A依赖B(Dependency)。
Peeleable表示“可剥皮的”,Peeler表示“剥皮机”,Juicer表示“榨汁器”。从现实意义上来讲,图中所示的依赖关系是自然合理的。
在这里插入图片描述
用代码来表示,如下

// 可剥皮的
public interface Peelable { 
  // 剥皮
  void peel(); 
}
// 苹果是可剥皮的一种水果
public class Apple implements Peelable { 
  public void peel() { } 
}
// 剥皮机
public class Peeler implements Startable {
  private final Peelable peelable;
  // 剥皮机,依赖一个可剥皮的物品(如苹果)
  public Peeler(Peelable peelable) {
    this.peelable = peelable;
  }
  // 剥皮机开始工作,就代表苹果要剥皮
  public void start() { 
	peelable.peel();
  }
  public void stop() { } 
}
//榨汁器
public class Juicer {
  private final Peelable peelable;
  private final Peeler peeler;
  // 榨汁器,依赖于一个可剥皮的水果和一个剥皮器
  public Juicer(Peelable peelable, Peeler peeler) {
    this.peelable = peelable; 
    this.peeler = peeler; 
  } 
}

不使用容器,来获取一个Juicer可能如下所示:

Peelable peelable = new Apple();
Peeler peeler = new Peeler(peelable);
Juicer juicer = new Juicer(peelable, peeler);
return juicer;

使用 pico container,如下所示,与上面的效果是等价的。

MutablePicoContainer pico = new DefaultPicoContainer();
pico.addComponent(Apple.class);
pico.addComponent(Juicer.class);
pico.addComponent(Peeler.class);

Juicer juicer = (Juicer) pico.getComponent(Juicer.class);

容器继承

构造容器的时候,可以指定一个父容器参数,如MutablePicoContainer y = new DefaultPicoContainer( x ); , 子容器(或注册在子容器里的组件)可以“看见”注册到父容器里的组件,反之不可。

看一个栗子

    @Test
    public void test(){
        // 容器继承,子容器的组件初始化时,如果依赖父容器中的组件,是可成立的,反之不可
        MutablePicoContainer x = new DefaultPicoContainer();
        MutablePicoContainer y = new DefaultPicoContainer( x );
        MutablePicoContainer z = new DefaultPicoContainer( y );
        // Assemble components
        x.addComponent(Apple.class);
        y.addComponent(Juicer.class);
        z.addComponent(Peeler.class);
        // Instantiate components
        Peeler peeler = z.getComponent(Peeler.class);
        System.out.println(peeler);
        // WON'T WORK! peeler will be null
        // x是最顶层容器,其内只有Apple组件,没有Peeler组件
        peeler = x.getComponent(Peeler.class);
        System.out.println(peeler);
        // WON'T WORK! This will throw an exception
        // 因为Juicer的构造函数依赖一个Peeler和一个Peelable
        // y容器可以看到x父容器中的Apple作为Peelable,
        // 但是看不到z子容器中的Peeler,所以抛出异常
        Juicer juicer =  y.getComponent(Juicer.class);
        System.out.println(juicer);
    }

生命周期

  1. 如果自定义组件(Component)实现了Startable接口(有两个方法start,stop), 且注册到了容器(Container)中,则container.start()时,组件的start方法就会执行;container.stop()时,组件的stop方法就会执行。

  2. 结合上一节提到的父子容器,生命周期也存在父子传递。即父容器执行start方法后,子容器会跟着执行start方法,递归下去;父容器执行stop方法后,子容器先stop, 父容器再stop,一直到最顶层容器。呈现出深度遍历优先的特点。start是递归深入,stop是递归回退。原文(见参考)中的start是广度优先,stop是深度优先的描述是错误的。

     @Test
        public void testLifeCycle3() {
            // 需要Caching
            MutablePicoContainer A  = new DefaultPicoContainer(new Caching());
            A.addComponent(StartA.class);
    
            MutablePicoContainer B  = new DefaultPicoContainer(new Caching(), A);
            B.addComponent(StartB.class);
    
            MutablePicoContainer C = new DefaultPicoContainer(new Caching(), A);
            C.addComponent(StartC.class);
    
            A.addComponent("B", B);
            A.addComponent("C", C);
    
            MutablePicoContainer D = new DefaultPicoContainer(new Caching(), B);
            D.addComponent(StartD.class);
            B.addComponent("D",D);
    
            MutablePicoContainer E = new DefaultPicoContainer(new Caching(), C);
            E.addComponent(StartE.class);
            C.addComponent("E",E);
    
            MutablePicoContainer F = new DefaultPicoContainer(new Caching(), A);
            F.addComponent(StartF.class);
            A.addComponent("F",F);
    
            A.start();
            A.stop();
        }
    

    在这里插入图片描述
    start时,路径是 A->B->D->C->E->F。
    stop时,路径是 F->E->C->D->B->A,正好相反。

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值