();
59: for (int i = 0; i < names.size(); i++) {
60: String name = names.get(i);
61: if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX) && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) { // 判断非移除的
62: // 将配置的自定义在自动激活的拓展对象们前面。例如, ,则 DemoFilter 就会放在默认的过滤器前面。
63: if (Constants.DEFAULT_KEY.equals(name)) {
64: if (!usrs.isEmpty()) {
65: exts.addAll(0, usrs);
66: usrs.clear();
67: }
68: } else {
69: // 获得拓展对象
70: T ext = getExtension(name);
71: usrs.add(ext);
72: }
73: }
74: }
75: // 添加到结果集
76: if (!usrs.isEmpty()) {
77: exts.addAll(usrs);
78: }
79: return exts;
80: }
```
- 第 16 行:从 Dubbo URL 获得参数值。例如说,若 XML 配置 Service `` ,并且在获得 Filter 自动激活拓展时,此处就能解析到 `value=demo,demo2` 。另外,`value` 可以根据**逗号**拆分。
- 第 18 行:调用 `#getActivateExtension(url, values, group)` 方法,获得符合自动激活条件的拓展对象数组。
- 第 35 至 56 行:处理自动激活的拓展对象们。
- [`#isMatchGroup(group, groups)`](https://github.com/YunaiV/dubbo/blob/4a877ee283af70c3f6a19c3b8b8e6918696540e6/dubbo-common/src/main/java/com/alibaba/dubbo/common/extension/ExtensionLoader.java#L357-L378) 方法,匹配分组。
- [`#isActive(Activate, url)`](https://github.com/YunaiV/dubbo/blob/4a877ee283af70c3f6a19c3b8b8e6918696540e6/dubbo-common/src/main/java/com/alibaba/dubbo/common/extension/ExtensionLoader.java#L380-L403) 方法,是否激活,通过 Dubbo URL 中是否存在参数名为 [`@Activate.value](mailto:`@Activate.value)` ,并且参数值非空。
- 第 57 至 74 行:处理自定义配置的拓展对象们。
- 第 75 至 78 行:将 `usrs` 合并到 `exts` **尾部**。
- 🙂 代码比较简单,胖友直接看注释。
#### 4.6.2 ActivateComparator
[`com.alibaba.dubbo.common.extension.support.ActivateComparator`](https://github.com/YunaiV/dubbo/blob/4a877ee283af70c3f6a19c3b8b8e6918696540e6/dubbo-common/src/main/java/com/alibaba/dubbo/common/extension/support/ActivateComparator.java) ,自动激活拓展对象排序器。
- 🙂 代码比较简单,胖友直接看注释。
## 5. @SPI
[`com.alibaba.dubbo.common.extension.@SPI`](https://github.com/YunaiV/dubbo/blob/6b8e51ac55880a0f10a34f297d0869fcdbb42369/dubbo-common/src/main/java/com/alibaba/dubbo/common/extension/SPI.java) ,扩展点接口的标识。代码如下:
```
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
/**
* default extension name
*/
String value() default "";
}
```
- `value` ,默认拓展实现类的名字。例如,Protocol 拓展接口,代码如下:
```
@SPI("dubbo")
public interface Protocol {
// ... 省略代码
}
```
- 其中 `"dubbo"` 指的是 DubboProtocol ,Protocol 默认的拓展实现类。
## 6. @Adaptive
[`com.alibaba.dubbo.common.extension.@Adaptive`](https://github.com/YunaiV/dubbo/blob/6b8e51ac55880a0f10a34f297d0869fcdbb42369/dubbo-common/src/main/java/com/alibaba/dubbo/common/extension/Adaptive.java) ,自适应拓展信息的标记。代码如下:
```
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Adaptive {
/**
* Decide which target extension to be injected. The name of the target extension is decided by the parameter passed
* in the URL, and the parameter names are given by this method.
*
* If the specified parameters are not found from {@link URL}, then the default extension will be used for
* dependency injection (specified in its interface's {@link SPI}).
*
* For examples, given String[] {"key1", "key2"}
:
*
* - find parameter 'key1' in URL, use its value as the extension's name
* - try 'key2' for extension's name if 'key1' is not found (or its value is empty) in URL
* - use default extension if 'key2' doesn't appear either
* - otherwise, throw {@link IllegalStateException}
*
* If default extension's name is not give on interface's {@link SPI}, then a name is generated from interface's
* class name with the rule: divide classname from capital char into several parts, and separate the parts with
* dot '.', for example: for {@code com.alibaba.dubbo.xxx.YyyInvokerWrapper}, its default name is
* String[] {"yyy.invoker.wrapper"}
. This name will be used to search for parameter from URL.
*
* @return parameter key names in URL
*/
/**
* 从 {@link URL }的 Key 名,对应的 Value 作为要 Adapt 成的 Extension 名。
*
* 如果 {@link URL} 这些 Key 都没有 Value ,使用 缺省的扩展(在接口的{@link SPI}中设定的值)。
* 比如,String[] {"key1", "key2"}
,表示
*
* - 先在URL上找key1的Value作为要Adapt成的Extension名;
*
- key1没有Value,则使用key2的Value作为要Adapt成的Extension名。
*
- key2没有Value,使用缺省的扩展。
*
- 如果没有设定缺省扩展,则方法调用会抛出{@link IllegalStateException}。
*
*
* 如果不设置则缺省使用Extension接口类名的点分隔小写字串。
* 即对于Extension接口 {@code com.alibaba.dubbo.xxx.YyyInvokerWrapper} 的缺省值为 String[] {"yyy.invoker.wrapper"}
*
* @see SPI#value()
*/
String[] value() default {};
}
```
`@Adaptive` 注解,可添加**类**或**方法**上,分别代表了两种不同的使用方式。
> 友情提示:一个拓展接口,有且仅有一个 Adaptive 拓展实现类。
- 第一种,标记在**类**上,代表**手动实现**它是一个拓展接口的 Adaptive 拓展实现类。目前 Dubbo 项目里,只有 ExtensionFactory 拓展的实现类 AdaptiveExtensionFactory 有这么用。详细解析见 [「8.1 AdaptiveExtensionFactory」](http://svip.iocoder.cn/Dubbo/spi/#) 。
- 第二种,标记在拓展接口的方法上,代表自动生成代码实现该接口的 Adaptive 拓展实现类。
- `value `,从 Dubbo URL 获取参数中,使用键名( Key ),获取键值。该值为真正的拓展名。
- 自适应拓展实现类,会获取拓展名对应的**真正**的拓展对象。通过该对象,执行真正的逻辑。
- 可以设置**多个**键名( Key ),顺序获取直到**有值**。若最终获取不到,使用**默认拓展名**。
- 在 [「4.5.4 createAdaptiveExtensionClassCode」](http://svip.iocoder.cn/Dubbo/spi/#) 详细解析。
## 7. @Activate
[`com.alibaba.dubbo.common.extension.@Activate`](https://github.com/YunaiV/dubbo/blob/6b8e51ac55880a0f10a34f297d0869fcdbb42369/dubbo-common/src/main/java/com/alibaba/dubbo/common/extension/Activate.java) ,自动激活条件的标记。代码如下:
```
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Activate {
/**
* Activate the current extension when one of the groups matches. The group passed into
* {@link ExtensionLoader#getActivateExtension(URL, String, String)} will be used for matching.
*
* @return group names to match
* @see ExtensionLoader#getActivateExtension(URL, String, String)
*/
/**
* Group过滤条件。
*
* 包含{@link ExtensionLoader#getActivateExtension}的group参数给的值,则返回扩展。
*
* 如没有Group设置,则不过滤。
*/
String[] group() default {};
/**
* Activate the current extension when the specified keys appear in the URL's parameters.
*
* For example, given @Activate("cache, validation")
, the current extension will be return only when
* there's either cache
or validation
key appeared in the URL's parameters.
*
*
* @return URL parameter keys
* @see ExtensionLoader#getActivateExtension(URL, String)
* @see ExtensionLoader#getActivateExtension(URL, String, String)
*/
/**
* Key过滤条件。包含{@link ExtensionLoader#getActivateExtension}的URL的参数Key中有,则返回扩展。
*
* 示例:
* 注解的值 @Activate("cache,validatioin")
,
* 则{@link ExtensionLoader#getActivateExtension}的URL的参数有cache
Key,或是validatioin
则返回扩展。
*
* 如没有设置,则不过滤。
*/
String[] value() default {};
/**
* Relative ordering info, optional
*
* @return extension list which should be put before the current one
*/
/**
* 排序信息,可以不提供。
*/
String[] before() default {};
/**
* Relative ordering info, optional
*
* @return extension list which should be put after the current one
*/
/**
* 排序信息,可以不提供。
*/
String[] after() default {};
/**
* Absolute ordering info, optional
*
* @return absolute ordering info
*/
/**
* 排序信息,可以不提供。
*/
int order() default 0;
}
```
- 对于可以被框架中自动激活加载扩展,`@Activate`用于配置扩展被自动激活加载条件。比如,Filter 扩展,有多个实现,使用 `@Activate`的扩展可以根据条件被自动加载。
- 这块的例子,可以看下 [《Dubbo 开发指南 —— 扩展点加载》「扩展点自动激活」](http://svip.iocoder.cn/Dubbo/spi/#) 文档提供的。
- 🙂 分成过滤条件和排序信息**两类属性**,胖友看下代码里的注释。
- 在 [「4.6 获得激活的拓展对象数组」](http://svip.iocoder.cn/Dubbo/spi/#) 详细解析。
## 8. ExtensionFactory
[`com.alibaba.dubbo.common.extension.ExtensionFactory`](http://svip.iocoder.cn/Dubbo/spi/) ,拓展工厂接口。代码如下:
```
/**
* ExtensionFactory
*
* 拓展工厂接口
*/
@SPI
public interface ExtensionFactory {
/**
* Get extension.
*
* 获得拓展对象
*
* @param type object type. 拓展接口
* @param name object name. 拓展名
* @return object instance. 拓展对象
*/
T getExtension(Class type, String name);
}
```
- ExtensionFactory 自身也是拓展接口,基于 Dubbo SPI 加载具体拓展实现类。
- `#getExtension(type, name)` 方法,在 [「4.4.3 injectExtension」](http://svip.iocoder.cn/Dubbo/spi/#) 中,获得拓展对象,向创建的拓展对象**注入依赖属性**。在实际代码中,我们可以看到不仅仅获得的是拓展对象,也可以是 Spring 中的 Bean 对象。
- ExtensionFactory 子类类图如下:[![ExtensionFactory 类图](http://static2.iocoder.cn/images/Dubbo/2018_03_04/06.png)](http://static2.iocoder.cn/images/Dubbo/2018_03_04/06.png)ExtensionFactory 类图
### 8.1 AdaptiveExtensionFactory
[`com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory`](https://github.com/YunaiV/dubbo/blob/4a877ee283af70c3f6a19c3b8b8e6918696540e6/dubbo-common/src/main/java/com/alibaba/dubbo/common/extension/factory/AdaptiveExtensionFactory.java) ,自适应 ExtensionFactory 拓展实现类。代码如下:
```
1: @Adaptive
2: public class AdaptiveExtensionFactory implements ExtensionFactory {
3:
4: /**
5: * ExtensionFactory 拓展对象集合
6: */
7: private final List factories;
8:
9: public AdaptiveExtensionFactory() {
10: // 使用 ExtensionLoader 加载拓展对象实现类。
11: ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
12: List list = new ArrayList();
13: for (String name : loader.getSupportedExtensions()) {
14: list.add(loader.getExtension(name));
15: }
16: factories = Collections.unmodifiableList(list);
17: }
18:
19: public T getExtension(Class type, String name) {
20: // 遍历工厂数组,直到获得到属性
21: for (ExtensionFactory factory : factories) {
22: T extension = factory.getExtension(type, name);
23: if (extension != null) {
24: return extension;
25: }
26: }
27: return null;
28: }
29:
30: }
```
- `@Adaptive` 注解,为 ExtensionFactory 的**自适应**拓展实现类。
- **构造**方法,使用 ExtensionLoader 加载 ExtensionFactory 拓展对象的实现类。若胖友没自己实现 ExtensionFactory 的情况下,`factories` 为 SpiExtensionFactory 和 SpringExtensionFactory 。
- `#getExtension(type, name)` 方法,遍历 `factories` ,调用其 `#getExtension(type, name)` 方法,直到获得到属性值。
### 8.2 SpiExtensionFactory
[`com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory`](https://github.com/YunaiV/dubbo/blob/4a877ee283af70c3f6a19c3b8b8e6918696540e6/dubbo-common/src/main/java/com/alibaba/dubbo/common/extension/factory/SpiExtensionFactory.java) ,SPI ExtensionFactory 拓展实现类。代码如下:
```
public class SpiExtensionFactory implements ExtensionFactory {
/**
* 获得拓展对象
*
* @param type object type. 拓展接口
* @param name object name. 拓展名
* @param 泛型
* @return 拓展对象
*/
public T getExtension(Class type, String name) {
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { // 校验是 @SPI
// 加载拓展接口对应的 ExtensionLoader 对象
ExtensionLoader loader = ExtensionLoader.getExtensionLoader(type);
// 加载拓展对象
if (!loader.getSupportedExtensions().isEmpty()) {
return loader.getAdaptiveExtension();
}
}
return null;
}
}
```
### 8.3 SpringExtensionFactory
[`com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory`](http://svip.iocoder.cn/Dubbo/spi/SpringExtensionFactory) ,Spring ExtensionFactory 拓展实现类。代码如下:
```
public class SpringExtensionFactory implements ExtensionFactory {
/**
* Spring Context 集合
*/
private static final Set contexts = new ConcurrentHashSet();
public static void addApplicationContext(ApplicationContext context) {
contexts.add(context);
}
public static void removeApplicationContext(ApplicationContext context) {
contexts.remove(context);
}
@Override
@SuppressWarnings("unchecked")
public T getExtension(Class type, String name) {
for (ApplicationContext context : contexts) {
if (context.containsBean(name)) {
// 获得属性
Object bean = context.getBean(name);
// 判断类型
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
return null;
}
}
```
- `#getExtension(type, name)` 方法,遍历 `contexts` ,调用其 `ApplicationContext#getBean(name)` 方法,获得 Bean 对象,直到成功并且值类型正确。
#### 8.3.1 例子
DemoFilter 是笔者实现的 Filter 拓展实现类,代码如下:
```
public class DemoFilter implements Filter {
private DemoDAO demoDAO;
@Override
public Result invoke(Invoker> invoker, Invocation invocation) throws RpcException {
return invoker.invoke(invocation);
}
public DemoFilter setDemoDAO(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
return this;
}
}
```
- DemoDAO ,笔者在 Spring 中声明对应的 Bean 对象。
```
```
- 在 [「4.4.3 injectExtension」](http://svip.iocoder.cn/Dubbo/spi/#) 中,会调用 `#setDemoDAO(demo)` 方法,将 DemoFilter 依赖的属性 `demoDAO` 注入。