- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在Dubbo中有Filter使用,对于Filter来说我们会遇到这样的问题,Filter自身有很多的实现,我们希望某种条件下使用A实现,另外情况下使用B实现,这个时候我们前面介绍@SPI和@Adaptive就不能满足我们要求了,这个时候我们就需要使用@Activate。 Activate注解表示一个扩展是否被激活(使用),可以放在类定义和方法上,Dubbo中用它在扩展类定义上,表示这个扩展实现激活条件和时机. @Activate注解标注在扩展实现类上,有 group、value 以及 order 三个属性,三个属性作用如下 SPI在扩展类加载时候, loadClass() 方法会对 @Activate的注解类进行扫描,其中会将包含 @Activate 注解的实现类缓存到 cachedActivates 一个Map集合中,Key为扩展名,Value为@Activate注解; 。 使用cachedActivates这个集合的地方是 getActivateExtension() ,关于此方法有4个重载函数,核心方法包含三个重要参数,URL中包含了配置信息,Values是配置中指定的扩展名,Group标签,下面是getActivateExtension的核心逻辑,首先就是获取默认的扩展集合,其次将扩获取到扩展类放到一个有序的集合中,按照顺序添加自定义扩展类的实现. 欢迎大家点点关注,点点赞. 前言
如何使用
@SPI
public
interface ActivateDemo
{
/**
* 测试
* @param msg
* @return
*/
String test (String msg)
;
}
@Activate
(group = {
"default"
})
public
class DefaultActivateDemoImpl implements ActivateDemo
{
@Override
public String test (String msg)
{
return
msg;
}
}
@Activate
(group = {
"groupA"
,
"groupB"
})
public
class ComposeGroupActivateDemoImpl implements ActivateDemo
{
@Override
public String test (String msg)
{
return
msg;
}
}
@Activate
(order =
1
, group = {
"order"
})
public
class Order1ActivateDemoImpl implements ActivateDemo
{
@Override
public String test (String msg)
{
return
msg;
}
}
@Activate
(order =
2
, group = {
"order"
})
public
class Order2ActivateDemoImpl implements ActivateDemo
{
@Override
public String test (String msg)
{
return
msg;
}
}
@Activate
(value = {
"value"
}, group = {
"group"
})
public
class ValueAndGroupActivateDemoImpl implements ActivateDemo
{
@Override
public String test (String msg)
{
return
msg;
}
}
public static void main (String[] args)
{
ExtensionLoader<ActivateDemo> loader = ExtensionLoader.getExtensionLoader(ActivateDemo
. class )
;
URL url = URL.valueOf(
"test://localhost/test"
);
List<ActivateDemo> list = loader.getActivateExtension(url,
new
String[]{},
"order"
);
System.out.println(list.size());
list.forEach(item -> System.out.println(item.getClass()));
}
public static void main (String[] args)
{
ExtensionLoader<ActivateDemo> loader = ExtensionLoader.getExtensionLoader(ActivateDemo
. class )
;
URL url = URL.valueOf(
"test://localhost/test"
);
//注意这里要使用url接收,不能直接url.addParameter()
url = url.addParameter(
"value"
,
"test"
);
List<ActivateDemo> list = loader.getActivateExtension(url,
new
String[]{
"order1"
,
"default"
},
"group"
);
System.out.println(list.size());
list.forEach(item -> System.out.println(item.getClass()));
}
源码分析
@Documented
@Retention
(RetentionPolicy.RUNTIME)
@Target
({ElementType.TYPE, ElementType.METHOD})
public
@interface
Activate {
String[] group()
default
{};
String[] value()
default
{};
@Deprecated
String[] before()
default
{};
@Deprecated
String[] after()
default
{};
int order () default 0
;
}
private void loadClass (Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
boolean overridden) throws NoSuchMethodException
{
if
(!type.isAssignableFrom(clazz)) {
throw
new
IllegalStateException(
"Error occurred when loading extension class (interface: "
+
type +
", class line: "
+ clazz.getName() +
"), class "
+ clazz.getName() +
" is not subtype of interface."
);
}
//判断类是否加载Adaptive注解
if
(clazz.isAnnotationPresent(Adaptive
. class ))
{
cacheAdaptiveClass(clazz, overridden);
//是否是扩展类,是的话就加入 cachedWrapperClasses 属性
}
else
if
(isWrapperClass(clazz)) {
cacheWrapperClass(clazz);
}
else
{
//检测是否有默认构造起
clazz.getConstructor();
if
(StringUtils.isEmpty(name)) {
//未配置扩展名,自动生成,主要用于兼容java SPI的配置。
name = findAnnotationName(clazz);
if
(name.length() ==
0
) {
throw
new
IllegalStateException(
"No such extension name for the class "
+ clazz.getName() +
" in the config "
+ resourceURL);
}
}
// 获得扩展名,可以是数组,有多个拓扩展名。
String[] names = NAME_SEPARATOR.split(name);
if
(ArrayUtils.isNotEmpty(names)) {
//如果是自动激活的实现类,则加入到缓存
cacheActivateClass(clazz, names[
0
]);
for
(String n : names) {
//存储Class到名字的映射关系
cacheName(clazz, n);
//存储名字到Class的映射关系
saveInExtensionClass(extensionClasses, clazz, n, overridden);
}
}
}
}
public List<T> getActivateExtension (URL url, String key)
{
return
getActivateExtension(url, key,
null
);
}
public List<T> getActivateExtension (URL url, String[] values)
{
return
getActivateExtension(url, values,
null
);
}
public List<T> getActivateExtension (URL url, String key, String group)
{
String value = url.getParameter(key);
return
getActivateExtension(url, StringUtils.isEmpty(value) ?
null
: COMMA_SPLIT_PATTERN.split(value), group);
}
public List<T> getActivateExtension (URL url, String[] values, String group)
{
List<T> activateExtensions =
new
ArrayList<>();
// solve the bug of using @SPI's wrapper method to report a null pointer exception.
// TreeMap进行排序
TreeMap<Class, T> activateExtensionsMap =
new
TreeMap<>(ActivateComparator.COMPARATOR);
Set<String> loadedNames =
new
HashSet<>();
//传入的数组包装成为set
Set<String> names = CollectionUtils.ofSet(values);
//包装好的数据中判断不含"-default""
if
(!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
//获取所有的加载类型
getExtensionClasses();
//cachedActivate 存储被@Activate修饰类型
for
(Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
String name = entry.getKey();
Object activate = entry.getValue();
String[] activateGroup, activateValue;
//兼容老的逻辑
if
(activate
instanceof
Activate) {
activateGroup = ((Activate) activate).group();
activateValue = ((Activate) activate).value();
}
else
if
(activate
instanceof
com.alibaba.dubbo.common.extension.Activate) {
activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
}
else
{
continue
;
}
//判断group是否匹配
if
(isMatchGroup(group, activateGroup)
//没有出现在values配置中的,即为默认激活的扩展实现
&& !names.contains(name)
//通过"-"明确指定不激活该扩展实现
&& !names.contains(REMOVE_VALUE_PREFIX + name)
//检测URL中是否出现了指定的Key
&& isActive(activateValue, url)
//去重判断
&& !loadedNames.contains(name)) {
//筛入treeMap中
activateExtensionsMap.put(getExtensionClass(name), getExtension(name));
loadedNames.add(name);
}
}
if
(!activateExtensionsMap.isEmpty()) {
activateExtensions.addAll(activateExtensionsMap.values());
}
}
List<T> loadedExtensions =
new
ArrayList<>();
for
(String name : names) {
//排除对应扩展名 不包含以-开始 以及 一+name
if
(!name.startsWith(REMOVE_VALUE_PREFIX)
&& !names.contains(REMOVE_VALUE_PREFIX + name)) {
if
(!loadedNames.contains(name)) {
if
(DEFAULT_KEY.equals(name)) {
if
(!loadedExtensions.isEmpty()) {
activateExtensions.addAll(
0
, loadedExtensions);
loadedExtensions.clear();
}
}
else
{
//获取对应名字扩展
loadedExtensions.add(getExtension(name));
}
loadedNames.add(name);
}
else
{
// If getExtension(name) exists, getExtensionClass(name) must exist, so there is no null pointer processing here.
String simpleName = getExtensionClass(name).getSimpleName();
logger.warn(
"Catch duplicated filter, ExtensionLoader will ignore one of them. Please check. Filter Name: "
+ name +
". Ignored Class Name: "
+ simpleName);
}
}
}
if
(!loadedExtensions.isEmpty()) {
activateExtensions.addAll(loadedExtensions);
}
return
activateExtensions;
}
结束
最后此篇关于Dubbo-Activate实现原理的文章就讲到这里了,如果你想了解更多关于Dubbo-Activate实现原理的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
本文全面深入地探讨了Docker容器通信技术,从基础概念、网络模型、核心组件到实战应用。详细介绍了不同网络模式及其实现,提供了容器通信的技术细节和实用案例,旨在为专业从业者提供深入的技术洞见和实
📒博客首页:崇尚学技术的科班人 🍣今天给大家带来的文章是《Dubbo快速上手 -- 带你了解Dubbo使用、原理》🍣 🍣希望各位小伙伴们能够耐心的读完这篇文章🍣 🙏博主也在学习阶段,如若发
一、写在前面 我们经常使用npm install ,但是你是否思考过它内部的原理是什么? 1、执行npm install 它背后帮助我们完成了什么操作? 2、我们会发现还有一个成为package-lo
Base64 Base64 是什么?是将字节流转换成可打印字符、将可打印字符转换为字节流的一种算法。Base64 使用 64 个可打印字符来表示转换后的数据。 准确的来说,Base64 不算
目录 协程定义 生成器和yield语义 Future类 IOLoop类 coroutine函数装饰器 总结 tornado中的
切片,这是一个在go语言中引入的新的理念。它有一些特征如下: 对数组抽象 数组长度不固定 可追加元素 切片容量可增大 容量大小成片增加 我们先把上面的理念整理在这
文章来源:https://sourl.cn/HpZHvy 引 言 本文主要论述的是“RPC 实现原理”,那么首先明确一个问题什么是 RPC 呢?RPC 是 Remote Procedure Call
源码地址(包含所有与springmvc相关的,静态文件路径设置,request请求入参接受,返回值处理converter设置等等): spring-framework/WebMvcConfigurat
请通过简单的java类向我展示一个依赖注入(inject)原理的小例子虽然我已经了解了spring,但是如果我需要用简单的java类术语来解释它,那么你能通过一个简单的例子向我展示一下吗?提前致谢。
1、背景 我们平常使用手机和电脑上网,需要访问公网上的网络资源,如逛淘宝和刷视频,那么手机和电脑是怎么知道去哪里去拿到这个网络资源来下载到本地的呢? 就比如我去食堂拿吃的,我需要
大家好,我是飞哥! 现在 iptables 这个工具的应用似乎是越来越广了。不仅仅是在传统的防火墙、NAT 等功能出现,在今天流行的的 Docker、Kubernets、Istio 项目中也经
本篇涉及到的所有接口在公开文档中均无,需要下载 GitHub 上的源码,自己创建私有类的文档。 npm run generateDocumentation -- --private yarn gene
我最近在很多代码中注意到人们将硬编码的配置(如端口号等)值放在类/方法的深处,使其难以找到,也无法配置。 这是否违反了 SOLID 原则?如果不是,我是否可以向我的团队成员引用另一个“原则”来说明为什
我是 C#、WPF 和 MVVM 模式的新手。很抱歉这篇很长的帖子,我试图设定我所有的理解点(或不理解点)。 在研究了很多关于 WPF 提供的命令机制和 MVVM 模式的文本之后,我在弄清楚如何使用这
可比较的 jQuery 函数 $.post("/example/handler", {foo: 1, bar: 2}); 将创建一个带有 post 参数 foo=1&bar=2 的请求。鉴于 $htt
如果Django不使用“延迟查询执行”原则,主要问题是什么? q = Entry.objects.filter(headline__startswith="What") q = q.filter(
我今天发现.NET框架在做计算时遵循BODMAS操作顺序。即计算按以下顺序进行: 括号 订单 部门 乘法 添加 减法 但是我四处搜索并找不到任何文档确认 .NET 绝对 遵循此原则,是否有此类文档?如
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等方面的建议的问题。您可以编辑问题,以便用事实和引用来回答它。 关闭
API 回顾 在创建 Viewer 时可以直接指定 影像供给器(ImageryProvider),官方提供了一个非常简单的例子,即离屏例子(搜 offline): new Cesium.Viewer(
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be
我是一名优秀的程序员,十分优秀!