QuickStart

oldratlee edited this page Mar 1, 2013 · 19 revisions

示例

Cooma功能示例的Demo。

  1. 获得扩展 =================================

示例的扩展点是Car,有两个扩展点实现RacingCarSportCar

  1. 接口类

package com.alibaba.demo.cooma;

import com.alibaba.cooma.Extension;

@Extension
public interface Car {
    void run();
}
  1. 实现类

package com.alibaba.demo.cooma;

public class RacingCar implements Car {
    public void run() {
        System.out.println("RacingCar Running...");
    }
}
package com.alibaba.demo.cooma;

public class SportCar implements Car {
    public void run() {
        System.out.println("SportCar Running...");
    }
}
  1. 扩展点配置文件

在类路径的META-INF/extensions/添加配置文件 com.alibaba.demo.cooma.Car(文件名是接口的全限定名,即包括包名的接口名)。
给出扩展点实现的名称和实现类的信息。

内容:

racing=com.alibaba.demo.cooma.RacingCar
sport=com.alibaba.demo.cooma.SportCar
  1. Main代码

ExtensionLoader<Car> extensionLoader = ExtensionLoader.getExtensionLoader(Car.class);

Car racingCar = extensionLoader.getExtension("racing"); // 获取指定名的扩展实例
racingCar.run();

Car sportCar = extensionLoader.getExtension("sport"); // 获取指定名的扩展实例
sportCar.run();

上面代码的运行结果,如下:

RacingCar Running...
SportCar Running...

说明

ExtensionLoader维护扩展点实现实例的 单例,即getExtension方法对于同一个扩展点实现名返回的实例是同一个。
# 后面会说到Wrapper,当使用Wrapper功能时,getExtension方法返回的是Wrapper实例。

实现的代码中和Cooma相关的内容是:

  1. 扩展点接口上要加上@Extension注解。如果没有此注解ExtensionLoader调用会出异常,拒绝管理。
  2. 在类路径的META-INF/extensions/添加配置文件 com.alibaba.demo.cooma.Car(文件名是接口的全限定名),给出扩展点实现的名称和实现类的信息。

这个使用方式可以通过扩展点实现名获得 单个接口的指定实现。实现的项目中往往会有多个扩展点配合。这样就需要扩展点中引用其它的扩展点,即注入相关的扩展点。在说明这个功能前,说明一下扩展点的“自适应实例(Adaptive Instance)”的功能。

  1. 自适应实例(Adaptive Instance) =================================

自适应实例是一个代理。在调用扩展点接口上的方法时,才决定真正要调用的哪个扩展点。
# “延迟”决策。

在方法调用时,要调用的哪个扩展点的信息来自于调用时的方法参数,在方法参数加上@Adaptive注解来标识。

如何从方法参数上提取到要“要调用的哪个扩展点”?@Adaptive注释有属性extractor,用于指定“提取要调用的哪个扩展点”的实现。缺省使用MapSourceExtractor,要求方法实现Map接口。

  1. 接口类

package com.alibaba.demo.cooma.car;

import com.alibaba.cooma.Adaptive;
import com.alibaba.cooma.Extension;

import java.util.Map;

/**
 * @author Jerry Lee(oldratlee<at>gmail<dot>com)
 */
@Extension
public interface Car {
    void run(@Adaptive("car") Map<String, String> config);
}
  1. 实现类

package com.alibaba.demo.cooma;

public class RacingCar implements Car {
    public void run(Map<String, String> config) { // 方法上多了一个Config参数
        System.out.println("RacingCar Running...");
    }
}
package com.alibaba.demo.cooma;

public class SportCar implements Car {
    public void run(Map<String, String> config) { // 方法上多了一个Config参数
        System.out.println("SportCar Running...");
    }
}
  1. 扩展点配置文件

和上一个示例相同。

  1. Main代码

ExtensionLoader<Car> extensionLoader = ExtensionLoader.getExtensionLoader(Car.class);
Car adaptive = extensionLoader.getAdaptiveInstance(); // 得到扩展点的Adaptive Instance

adaptive.run(Utils.kv2Map("car", "racing")); // 通过car key指定的Car本身使用哪个实现。

adaptive.run(Utils.kv2Map("car", "sport")); // 通过car key指定的Car本身使用哪个实现。

adaptive.run(Utils.kv2Map("k1", "v1")); // 没有car key,使用缺省的扩展点实现 

上面代码的运行结果,如下:

RacingCar Running...
SportCar Running...
RacingCar Running...

说明

使用Adaptive Instance,会从config方法参数(Map类型)中获得要调用哪个扩展点的信息。
这样要使用扩展点的地方只要统一持有的Adaptive Instance即可。
由调用者通过config方法参数由决定。

实现的代码中和Cooma相关的内容是:

  1. 加上config方法参数。

  2. 方法参数上加上@Adaptive注解。

  3. 扩展点接口的上的@Extension上可以指定缺省的扩展点实现。

  4. 注入相关的扩展点 =================================

前面提到,实现的项目中往往会有多个扩展点配合。这样就需要扩展点中引用其它的扩展点,即注入相关的扩展点。
# 扩展点的IOC

准备了2个扩展点,CarWheelCar引用了Wheel扩展点。

  1. 接口类

Car接口和上一个示例相同。

package com.alibaba.demo.cooma.car;

import com.alibaba.cooma.Adaptive;
import com.alibaba.cooma.Extension;

@Extension("rubber")
public interface Wheel {
    void roll(@Adaptive("wheel") Map<String, String> config);
}
  1. 实现类

Car的实例类:

package com.alibaba.demo.cooma;

public class RacingCar implements Car {

    private Wheel wheel;

    public void setWheel(Wheel wheel) { // 需要的其它扩展点的set方法,注入的即是Wheel扩展点的Adaptive Instance
        this.wheel = wheel;
    }

    public void run(Map<String, String> config) {
        wheel.roll(config);
        System.out.println("RacingCar Running...");
    }
}
package com.alibaba.demo.cooma;

public class SportCar implements Car {

    private Wheel wheel;

    public void setWheel(Wheel wheel) { // 需要的其它扩展点的set方法,注入的即是Wheel扩展点的Adaptive Instance
        this.wheel = wheel;
    }

    public void run(Map<String, String> config) {
        wheel.roll(config);
        System.out.println("SportCar Running...");
    }
}

新加上Wheel的实现类。

package com.alibaba.demo.cooma;

public class RubberWheel implements Wheel {
    public void roll(Map<String, String> config) {
        System.out.println("RubberWheel rolling...");
    }
}
package com.alibaba.demo.cooma;

public class WoodWheel implements Wheel {
    public void roll(Map<String, String> config) {
        System.out.println("WoodWheel rolling...");
    }
}
  1. 扩展点配置文件

新加Wheel的配置文件,在类路径的META-INF/extensions/添加文件 com.alibaba.demo.cooma.Car

rubber=com.alibaba.demo.cooma.wheel.impl.RubberWheel
wood=com.alibaba.demo.cooma.wheel.impl.WoodWheel
  1. Main代码

ExtensionLoader<Car> extensionLoader = ExtensionLoader.getExtensionLoader(Car.class);

Car racingCar = extensionLoader.getExtension("racing");
racingCar.run(Utils.kv2Map("wheel", "wood")); // 通过wheel Key指定要哪种轮子

System.out.println("=================================");

Car sportCar = extensionLoader.getExtension("sport");
sportCar.run(Utils.kv2Map("k1", "v1")); // 缺省使用RubberWheel

System.out.println("=================================");

Car adaptiveInstance = extensionLoader.getAdaptiveInstance();
// 通过car key指定的Car本身使用哪个实现,通过wheel Key指定要哪种轮子(下层扩展)
adaptiveInstance.run(Utils.kv2Map("car", "racing", "wheel", "wood")); 

上面代码的运行结果,如下:

WoodWheel rolling...
RacingCar Running...
=================================
RubberWheel rolling...
SportCar Running...
=================================
WoodWheel rolling...
RacingCar Running...

说明

  1. 扩展点需要依赖其它扩展点,则在实现类上加上依赖的扩展点的set方法,Cooma注入依赖扩展点的Adaptive Instance。

  2. 扩展点的Wrapper =================================

一个扩展点会一些公共逻辑,所有的扩展点都需要执行。Cooma以扩展点Wrapper的方式来解决这个问题。
# 扩展点的AOP

使用扩展点的Wrapper给上面的Car.run方法的调用次数计数。

  1. Wrapper实现 ==================
package com.alibaba.demo.cooma;

public class CarRunCountWrapper implements Car {
    Car car;
    AtomicInteger counter = new AtomicInteger();

    public CarRunCountWrapper(Car car) { // 提供拷贝构造函数的实现,会识别为扩展点Wrapper
        this.car = car;
    }

    public void run(Map<String, String> config) {
        car.run(config);

        counter.incrementAndGet();
        System.out.println("Run time: " + counter);
    }
}
  1. 扩展点配置文件

扩展点配置文件com.alibaba.demo.cooma.Car加上一行:

+run_counter=com.alibaba.demo.cooma.car.impl.CarRunCountWrapper

注意:开头的+表示后面的Class是Wrapper。

  1. Main代码

ExtensionLoader<Car> extensionLoader = ExtensionLoader.getExtensionLoader(Car.class);

Car countedSportCar = extensionLoader.getExtension("sport", Arrays.asList("run_counter"));
countedSportCar.run(Utils.kv2Map("k1", "v1")); // 缺省使用RubberWheel

System.out.println("=================================");

Car countedAdaptiveInstance = extensionLoader.getAdaptiveInstance(Arrays.asList("run_counter"));
countedAdaptiveInstance.run(Utils.kv2Map("car", "racing")); // 通过car key指定的Car本身使用哪个实现。

运行结果,如下:

RubberWheel rolling...
SportCar Running...
Run time: 1
=================================
RubberWheel rolling...
RacingCar Running...
Run time: 1

Demo代码

在Cooma的代码工程有Demo类:CarDemo.java

更多内容

参见用户指南

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.