2021SC@SDUSC
storm代码阅读(三)
2021SC@SDUSC
TopologyBuilder中一些接口的实现
ConfigGetter
ConfigGetter是定义在TopologyBuilder.java中的一个类,它实现了ComponentConfigurationDeclarer接口,并且继承自BaseConfigurationDeclarer类。
ConfigGetter作用:设置程序中的配置项,覆盖默认的配置项,且配置项的格式为为JSON(本质上是改变对应ComponentCommon对象中json_conf的值)。
具体代码如下:
protected class ConfigGetter<T extends ComponentConfigurationDeclarer> extends BaseConfigurationDeclarer<T> {
String id;
public ConfigGetter(String id) {
this.id = id;
}
@SuppressWarnings("unchecked")
@Override
public T addConfigurations(Map<String, Object> conf) {
if (conf != null) {
if (conf.containsKey(Config.TOPOLOGY_KRYO_REGISTER)) {
throw new IllegalArgumentException("Cannot set serializations for a component using fluent API");
}
if (!conf.isEmpty()) {
String currConf = commons.get(id).get_json_conf();
commons.get(id).set_json_conf(mergeIntoJson(parseJson(currConf), conf));
}
}
return (T) this;
}
/**
* return the current component configuration.
*
* @return the current configuration.
*/
@Override
public Map<String, Object> getComponentConfiguration() {
return parseJson(commons.get(id).get_json_conf());
}
@Override
public T addResources(Map<String, Double> resources) {
if (resources != null && !resources.isEmpty()) {
String currConf = commons.get(id).get_json_conf();
Map<String, Object> conf = parseJson(currConf);
Map<String, Double> currentResources =
(Map<String, Double>) conf.computeIfAbsent(Config.TOPOLOGY_COMPONENT_RESOURCES_MAP, (k) -> new HashMap<>());
currentResources.putAll(resources);
commons.get(id).set_json_conf(JSONValue.toJSONString(conf));
}
return (T) this;
}
@SuppressWarnings("unchecked")
@Override
public T addResource(String resourceName, Number resourceValue) {
Map<String, Object> componentConf = parseJson(commons.get(id).get_json_conf());
Map<String, Double> resourcesMap = (Map<String, Double>) componentConf.computeIfAbsent(
Config.TOPOLOGY_COMPONENT_RESOURCES_MAP, (k) -> new HashMap<>());
resourcesMap.put(resourceName, resourceValue.doubleValue());
return addConfiguration(Config.TOPOLOGY_COMPONENT_RESOURCES_MAP, resourcesMap);
}
@SuppressWarnings("unchecked")
@Override
public T addSharedMemory(SharedMemory request) {
SharedMemory found = sharedMemory.get(request.get_name());
if (found != null && !found.equals(request)) {
throw new IllegalArgumentException("Cannot have multiple different shared memory regions with the same name");
}
sharedMemory.put(request.get_name(), request);
Set<String> mems = componentToSharedMemory.computeIfAbsent(id, (k) -> new HashSet<>());
mems.add(request.get_name());
return (T) this;
}
}
其中id代表组件的唯一标识符。在通常的非事务流处理中不能设定组件的序列化方法,只能使用系统默认的序列化方法。ConfigGetter会根据新设置的配置项覆盖组件默认的配置项,最终,配置项会被序列化为JSON格式。
SpoutGetter
SpoutGetter实现了基本上和CinfigGetter相同的功能,唯一的不同是Spout不需要对输入进行声明。
具体代码如下:
protected class SpoutGetter extends ConfigGetter<SpoutDeclarer> implements SpoutDeclarer {
public SpoutGetter(String id) {
super(id);
}
}
BoltGetter
BoltGetter继承自ConfigGetter实现了对于Bolt组建的配置定制,还实现了BoltDeclarer接口,并重载了BoltDeclarer(InputDeclarer)中各种分组方式(如:fieldsGrouping、shuffleGrouping),分组方式的实现本质上是在_commons中通过对用的boltId找到对应的ComponentCommon对象,对inputs属性进行设置。
具体代码如下:
protected class BoltGetter extends ConfigGetter<BoltDeclarer> implements BoltDeclarer {
private String boltId;
public BoltGetter(String boltId) {
super(boltId);
this.boltId = boltId;
}
public BoltDeclarer fieldsGrouping(String componentId, Fields fields) {
return fieldsGrouping(componentId, Utils.DEFAULT_STREAM_ID, fields);
}
public BoltDeclarer fieldsGrouping(String componentId, String streamId, Fields fields) {
return grouping(componentId, streamId, Grouping.fields(fields.toList()));
}
public BoltDeclarer globalGrouping(String componentId) {
return globalGrouping(componentId, Utils.DEFAULT_STREAM_ID);
}
public BoltDeclarer globalGrouping(String componentId, String streamId) {
return grouping(componentId, streamId, Grouping.fields(new ArrayList<String>()));
}
public BoltDeclarer shuffleGrouping(String componentId) {
return shuffleGrouping(componentId, Utils.DEFAULT_STREAM_ID);
}
public BoltDeclarer shuffleGrouping(String componentId, String streamId) {
return grouping(componentId, streamId, Grouping.shuffle(new NullStruct()));
}
public BoltDeclarer localOrShuffleGrouping(String componentId) {
return localOrShuffleGrouping(componentId, Utils.DEFAULT_STREAM_ID);
}
public BoltDeclarer localOrShuffleGrouping(String componentId, String streamId) {
return grouping(componentId, streamId, Grouping.local_or_shuffle(new NullStruct()));
}
public BoltDeclarer noneGrouping(String componentId) {
return noneGrouping(componentId, Utils.DEFAULT_STREAM_ID);
}
public BoltDeclarer noneGrouping(String componentId, String streamId) {
return grouping(componentId, streamId, Grouping.none(new NullStruct()));
}
public BoltDeclarer allGrouping(String componentId) {
return allGrouping(componentId, Utils.DEFAULT_STREAM_ID);
}
public BoltDeclarer allGrouping(String componentId, String streamId) {
return grouping(componentId, streamId, Grouping.all(new NullStruct()));
}
public BoltDeclarer directGrouping(String componentId) {
return directGrouping(componentId, Utils.DEFAULT_STREAM_ID);
}
public BoltDeclarer directGrouping(String componentId, String streamId) {
return grouping(componentId, streamId, Grouping.direct(new NullStruct()));
}
private BoltDeclarer grouping(String componentId, String streamId, Grouping grouping) {
commons.get(boltId).put_to_inputs(new GlobalStreamId(componentId, streamId), grouping);
return this;
}
@Override
public BoltDeclarer grouping(GlobalStreamId id, Grouping grouping) {
return grouping(id.get_componentId(), id.get_streamId(), grouping);
}
@Override
public BoltDeclarer partialKeyGrouping(String componentId, Fields fields) {
return customGrouping(componentId, new PartialKeyGrouping(fields));
}
@Override
public BoltDeclarer partialKeyGrouping(String componentId, String streamId, Fields fields) {
return customGrouping(componentId, streamId, new PartialKeyGrouping(fields));
}
@Override
public BoltDeclarer customGrouping(String componentId, CustomStreamGrouping grouping) {
return customGrouping(componentId, Utils.DEFAULT_STREAM_ID, grouping);
}
由于分组方法较多且类似,这里以fieldsGrouping为例进行分析。
第二行定义的boltId变量用于保存Bolt组件的唯一标识符。
接下来的BoltGetter为构造函数,调用了ConfigGetter的构造函数实现配置项的定制功能。
接下来定义了fieldsGrouping及其重载方法,参数包括componentId、 streamId和 fields(用来分组的字段名列表),如果没有指定的streamId将默认使用default作为streamId。
下面的BoltDeclarer grouping是InputDeclarer接口最主要的实现方法。输入含义为:按照grouping参数定义的分组方式,将参数componentId指定的组件中以streamId定义的流放在本组件的输入定义中。其中方法最后一行的return this返回this指针可以通过函数级联的方式为本组件添加更多的输入。
紧接着是该方法的一个重要重载,输入为GlobalStreamId和分组方式。