mirror of https://github.com/longtai-cn/hippo4j
Bruceyan/issue#1092 (#1102)
* refactor: Extension module * refactor: Update packageNames and classNames, mark ServiceLoader deprecated. * fix: remove some unused fields. * method does not override or implement a method from a supertype * fix: Modify some field names, add scoped target object filtering.pull/1116/head
parent
72aa732688
commit
275a8bfb92
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension;
|
||||
|
||||
/**
|
||||
* Top level interface of extension-point.
|
||||
*/
|
||||
public interface IExtension {
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension;
|
||||
|
||||
/**
|
||||
* Top level interface of extension-point request obj.
|
||||
*/
|
||||
public interface IExtensionRequest {
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.annotation;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
@Component
|
||||
public @interface Realization {
|
||||
|
||||
String code() default "DEFAULT_CODE";
|
||||
|
||||
String name() default "DEFAULT_NAME";
|
||||
|
||||
int order() default 0;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.config;
|
||||
|
||||
import cn.hippo4j.common.extension.IExtension;
|
||||
import cn.hippo4j.common.extension.annotation.Realization;
|
||||
import cn.hippo4j.common.extension.support.ExtensionRegistry;
|
||||
import cn.hippo4j.common.toolkit.ClassUtil;
|
||||
import org.springframework.aop.scope.ScopedProxyUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Extension register bootstrap
|
||||
*/
|
||||
public class ExtensionRegisterBootstrap implements ApplicationContextAware, ApplicationRunner {
|
||||
|
||||
private ExtensionRegistry registry = ExtensionRegistry.getInstance();
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
applicationContext.getBeansWithAnnotation(Realization.class)
|
||||
.entrySet().stream()
|
||||
.filter(entry -> !filterClass(entry.getKey(), entry.getValue()))
|
||||
.forEach(entry -> registry.register((IExtension) entry.getValue()));
|
||||
}
|
||||
|
||||
private boolean filterClass(String beanName, Object bean) {
|
||||
return bean.getClass().isAssignableFrom(IExtension.class) ||
|
||||
ScopedProxyUtils.isScopedTarget(beanName) ||
|
||||
!(bean instanceof IExtension);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.reducer;
|
||||
|
||||
import cn.hippo4j.common.extension.IExtension;
|
||||
import cn.hippo4j.common.extension.support.ReduceType;
|
||||
import cn.hippo4j.common.toolkit.CollectionUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* All-match extension reduce policy.
|
||||
*/
|
||||
public class AllMatch<Element> extends Reducer<Element, Boolean> {
|
||||
|
||||
@Getter
|
||||
private final Predicate<Element> predicate;
|
||||
|
||||
public AllMatch(@NonNull Predicate<Element> predicate) {
|
||||
Objects.requireNonNull(predicate);
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean reduce() {
|
||||
if (CollectionUtil.isEmpty(realizations)) {
|
||||
return false;
|
||||
} else {
|
||||
for (IExtension realization : realizations) {
|
||||
if (!predicate.test(getCallback().apply(realization))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReduceType reducerType() {
|
||||
return ReduceType.ALL;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.reducer;
|
||||
|
||||
import cn.hippo4j.common.extension.IExtension;
|
||||
import cn.hippo4j.common.extension.support.ReduceType;
|
||||
import cn.hippo4j.common.toolkit.CollectionUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Any-match extension reduce policy.
|
||||
*/
|
||||
public class AnyMatch<Element> extends Reducer<Element, Boolean> {
|
||||
|
||||
@Getter
|
||||
private final Predicate<Element> predicate;
|
||||
|
||||
public AnyMatch(@NonNull Predicate<Element> predicate) {
|
||||
Objects.requireNonNull(predicate);
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean reduce() {
|
||||
if (CollectionUtil.isEmpty(realizations)) {
|
||||
return false;
|
||||
}
|
||||
for (IExtension extension : realizations) {
|
||||
if (predicate.test(getCallback().apply(extension))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReduceType reducerType() {
|
||||
return ReduceType.FIRST;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.reducer;
|
||||
|
||||
import cn.hippo4j.common.extension.IExtension;
|
||||
import cn.hippo4j.common.extension.support.ReduceType;
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* First-of extension reduce policy.
|
||||
*/
|
||||
public class FirstOf<Element> extends Reducer<Element, Element> {
|
||||
|
||||
private Predicate<Element> predicate;
|
||||
|
||||
public FirstOf(@NonNull Predicate<Element> predicate) {
|
||||
Objects.requireNonNull(predicate);
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReduceType reducerType() {
|
||||
return ReduceType.FIRST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element reduce() {
|
||||
for (IExtension extension : realizations) {
|
||||
Element element = getCallback().apply(extension);
|
||||
if (null == predicate || predicate.test(element)) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.reducer;
|
||||
|
||||
import cn.hippo4j.common.extension.support.ReduceType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class None<Element> extends Reducer<Element, List<Element>> {
|
||||
|
||||
@Override
|
||||
public ReduceType reducerType() {
|
||||
return ReduceType.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Element> reduce() {
|
||||
return realizations.stream().map(getCallback()).collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.reducer;
|
||||
|
||||
import cn.hippo4j.common.extension.IExtension;
|
||||
import cn.hippo4j.common.extension.IExtensionRequest;
|
||||
import cn.hippo4j.common.extension.support.ExtensionCallback;
|
||||
import cn.hippo4j.common.extension.support.ReduceType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class Reducer<Element, Result> {
|
||||
|
||||
@Getter
|
||||
private Result result;
|
||||
|
||||
@Setter
|
||||
protected IExtensionRequest request;
|
||||
|
||||
@Setter
|
||||
protected List<IExtension> realizations;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
private ExtensionCallback<IExtension, Element> callback;
|
||||
|
||||
public abstract Result reduce();
|
||||
|
||||
public abstract ReduceType reducerType();
|
||||
|
||||
public String reduceName() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.reducer;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public class Reducers {
|
||||
|
||||
/**
|
||||
* No reduce policy needed.
|
||||
*
|
||||
* @return None type reducer
|
||||
*/
|
||||
public static <E> Reducer<E, List<E>> none() {
|
||||
return new None<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a FirstOf Reducer.
|
||||
*
|
||||
* @param predicate the condition predicate.
|
||||
* @return FirstOf Policy Reducer.
|
||||
*/
|
||||
public static <E> Reducer<E, E> firstOf(@NonNull Predicate<E> predicate) {
|
||||
return new FirstOf<>(predicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a FirstOf Not-null Reducer.
|
||||
*
|
||||
* @return FirstOf Not-null Policy Reducer.
|
||||
*/
|
||||
public static <E> Reducer<E, E> firstOfNotNull() {
|
||||
return new FirstOf<>(Objects::nonNull);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a AnyMatch Reducer.
|
||||
*
|
||||
* @param predicate the condition predicate.
|
||||
* @return AnyMatch Policy Reducer.
|
||||
*/
|
||||
public static <E> Reducer<E, Boolean> anyMatch(Predicate<E> predicate) {
|
||||
return new AnyMatch<>(predicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a AllMatch Reducer
|
||||
*
|
||||
* @param predicate the condition predicate.
|
||||
* @return AllMatch Policy Reducer.
|
||||
*/
|
||||
public static <E> Reducer<E, Boolean> allMatch(@NonNull Predicate<E> predicate) {
|
||||
return new AllMatch<>(predicate);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.support;
|
||||
|
||||
import cn.hippo4j.common.extension.config.ExtensionRegisterBootstrap;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class ExtensionAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ExtensionRegisterBootstrap bootstrap() {
|
||||
return new ExtensionRegisterBootstrap();
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.support;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Callback function of extension invocation.
|
||||
* @param <T>
|
||||
* @param <R>
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ExtensionCallback<T, R> extends Function<T, R> {
|
||||
|
||||
R apply(T extension);
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.support;
|
||||
|
||||
import cn.hippo4j.common.extension.IExtension;
|
||||
import cn.hippo4j.common.extension.reducer.Reducer;
|
||||
import cn.hippo4j.common.extension.reducer.Reducers;
|
||||
import cn.hippo4j.common.toolkit.Assert;
|
||||
import cn.hippo4j.common.toolkit.CollectionUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Extension point invoker.
|
||||
*
|
||||
* Providing extension-point invocation ability that supports the use of reducing policy.
|
||||
*/
|
||||
public class ExtensionInvoker {
|
||||
|
||||
private static final ExtensionRegistry registry = ExtensionRegistry.getInstance();
|
||||
|
||||
public static <T extends IExtension, E> List<E> reduceExecute(Class<T> targetClz,
|
||||
ExtensionCallback<T, E> callback) {
|
||||
return reduceExecute(targetClz, callback, Reducers.none());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends IExtension, E, R> R reduceExecute(Class<T> targetClz,
|
||||
ExtensionCallback<T, E> callback,
|
||||
Reducer<E, R> reducer) {
|
||||
Assert.isTrue(IExtension.class.isAssignableFrom(targetClz),
|
||||
"can not execute extension point. please implement base extension interface(" + IExtension.class.getName() + ") first.");
|
||||
|
||||
List<IExtension> realizations = registry.find(targetClz);
|
||||
if (CollectionUtil.isEmpty(realizations)) {
|
||||
realizations = new ArrayList<>(ServiceLoaderRegistry.getSingletonServiceInstances(targetClz));
|
||||
}
|
||||
Assert.notEmpty(realizations, "can not find any extension realizations with interface: " + targetClz.getName());
|
||||
|
||||
reducer.setRealizations(realizations);
|
||||
reducer.setCallback((ExtensionCallback<IExtension, E>) callback);
|
||||
return reducer.reduce();
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.support;
|
||||
|
||||
import cn.hippo4j.common.extension.IExtension;
|
||||
import cn.hippo4j.common.extension.annotation.Realization;
|
||||
import cn.hippo4j.common.toolkit.CollectionUtil;
|
||||
import cn.hippo4j.common.toolkit.logtracing.LogMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Extension registry
|
||||
*/
|
||||
@Slf4j
|
||||
public class ExtensionRegistry implements IExtensionRegistry {
|
||||
|
||||
private final Map<Class<? extends IExtension>, List<IExtension>> registry = new ConcurrentHashMap<>();
|
||||
|
||||
private static ExtensionRegistry INSTANCE;
|
||||
|
||||
private ExtensionRegistry() {
|
||||
}
|
||||
|
||||
public static ExtensionRegistry getInstance() {
|
||||
if (null == INSTANCE) {
|
||||
synchronized (ExtensionRegistry.class) {
|
||||
if (null == INSTANCE) {
|
||||
INSTANCE = new ExtensionRegistry();
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void register(IExtension realization) {
|
||||
|
||||
Class<?> implClass = realization.getClass();
|
||||
if (AopUtils.isAopProxy(implClass)) {
|
||||
implClass = ClassUtils.getUserClass(implClass);
|
||||
}
|
||||
Realization annotation = implClass.getAnnotation(Realization.class);
|
||||
|
||||
Class<?>[] interfaces = implClass.getInterfaces();
|
||||
|
||||
for (Class<?> intf : interfaces) {
|
||||
if (IExtension.class.isAssignableFrom(intf)) {
|
||||
this.register((Class<IExtension>) intf, realization);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void register(Class<? extends IExtension> extension, IExtension realization) {
|
||||
if (!registry.containsKey(extension) || CollectionUtil.isEmpty(registry.get(extension))) {
|
||||
List<IExtension> realizations = new ArrayList<>();
|
||||
realizations.add(realization);
|
||||
registry.put(extension, realizations);
|
||||
} else {
|
||||
if (registry.get(extension).contains(realization)) {
|
||||
log.warn(LogMessage.getInstance()
|
||||
.kv("realizationClassName", realization.getClass().getName())
|
||||
.msg("Extension realization already registered, skip."));
|
||||
}
|
||||
List<IExtension> realizations = registry.get(extension);
|
||||
realizations.add(realization);
|
||||
registry.put(extension, realizations);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IExtension> find(Class<? extends IExtension> extension) {
|
||||
return registry.get(extension);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.support;
|
||||
|
||||
import cn.hippo4j.common.extension.IExtension;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IExtensionRegistry {
|
||||
|
||||
void register(IExtension realization);
|
||||
|
||||
List<IExtension> find(Class<? extends IExtension> extension);
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.support;
|
||||
|
||||
public enum ReduceType {
|
||||
|
||||
NONE,
|
||||
ALL,
|
||||
FIRST,
|
||||
UNKNOWN
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.toolkit;
|
||||
|
||||
/**
|
||||
* Class Util.
|
||||
*/
|
||||
public class ClassUtil {
|
||||
|
||||
/**
|
||||
* get class loader
|
||||
*
|
||||
* @param clazz
|
||||
* @return class loader
|
||||
*/
|
||||
public static ClassLoader getClassLoader(Class<?> clazz) {
|
||||
ClassLoader cl = null;
|
||||
try {
|
||||
cl = Thread.currentThread().getContextClassLoader();
|
||||
} catch (Throwable ex) {
|
||||
// Cannot access thread context ClassLoader - falling back to system class loader...
|
||||
}
|
||||
if (cl == null) {
|
||||
// No thread context class loader -> use class loader of this class.
|
||||
cl = clazz.getClassLoader();
|
||||
if (cl == null) {
|
||||
// getClassLoader() returning null indicates the bootstrap ClassLoader
|
||||
try {
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
} catch (Throwable ex) {
|
||||
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cl;
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.hippo4j.common.extension.support.ExtensionAutoConfiguration
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension;
|
||||
|
||||
import cn.hippo4j.common.extension.anymatch.AnyMatchExtImplA;
|
||||
import cn.hippo4j.common.extension.anymatch.AnyMatchExtImplB;
|
||||
import cn.hippo4j.common.extension.anymatch.IAnyMatchExtension;
|
||||
import cn.hippo4j.common.extension.firstof.FirstOfExtImplA;
|
||||
import cn.hippo4j.common.extension.firstof.FirstOfExtImplB;
|
||||
import cn.hippo4j.common.extension.firstof.IFirstOfExtension;
|
||||
import cn.hippo4j.common.extension.reducer.Reducers;
|
||||
import cn.hippo4j.common.extension.spi.IOldSpi;
|
||||
import cn.hippo4j.common.extension.support.ExtensionInvoker;
|
||||
import cn.hippo4j.common.extension.support.ExtensionRegistry;
|
||||
import cn.hippo4j.common.extension.support.ServiceLoaderRegistry;
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ExtensionInvokerTest {
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ExtensionRegistry.getInstance().register(new FirstOfExtImplA());
|
||||
ExtensionRegistry.getInstance().register(new FirstOfExtImplB());
|
||||
ExtensionRegistry.getInstance().register(new AnyMatchExtImplA());
|
||||
ExtensionRegistry.getInstance().register(new AnyMatchExtImplB());
|
||||
|
||||
ServiceLoaderRegistry.register(IOldSpi.class);
|
||||
}
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
Integer arg = 20;
|
||||
// first-of
|
||||
Integer res1 = ExtensionInvoker.reduceExecute(IFirstOfExtension.class, (ext) -> ext.foo(arg),
|
||||
Reducers.firstOfNotNull());
|
||||
assertEquals(arg, res1);
|
||||
|
||||
// any-match
|
||||
Boolean res2 = ExtensionInvoker.reduceExecute(IAnyMatchExtension.class, (ext) -> ext.foo(arg),
|
||||
Reducers.anyMatch(Objects::nonNull));
|
||||
assertTrue(res2);
|
||||
|
||||
// none
|
||||
List<Integer> res3 = ExtensionInvoker.reduceExecute(IFirstOfExtension.class, (ext) -> ext.foo(arg));
|
||||
assertArrayEquals(res3.toArray(new Integer[0]), Lists.newArrayList(null, arg).toArray());
|
||||
|
||||
// all-match
|
||||
Boolean res4 = ExtensionInvoker.reduceExecute(IAnyMatchExtension.class, (ext) -> ext.foo(arg),
|
||||
Reducers.allMatch(Objects::nonNull));
|
||||
assertTrue(res4);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_spi_old() {
|
||||
Boolean res1 = ExtensionInvoker.reduceExecute(IOldSpi.class, IOldSpi::foo, Reducers.firstOfNotNull());
|
||||
assertTrue(res1);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.anymatch;
|
||||
|
||||
import cn.hippo4j.common.extension.annotation.Realization;
|
||||
|
||||
@Realization
|
||||
public class AnyMatchExtImplA implements IAnyMatchExtension {
|
||||
|
||||
@Override
|
||||
public Integer foo(Integer arg) {
|
||||
return arg > 0 ? arg : null;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.anymatch;
|
||||
|
||||
import cn.hippo4j.common.extension.annotation.Realization;
|
||||
|
||||
@Realization
|
||||
public class AnyMatchExtImplB implements IAnyMatchExtension {
|
||||
|
||||
@Override
|
||||
public Integer foo(Integer arg) {
|
||||
return arg > 0 ? arg : null;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.anymatch;
|
||||
|
||||
import cn.hippo4j.common.extension.IExtension;
|
||||
|
||||
public interface IAnyMatchExtension extends IExtension {
|
||||
|
||||
Integer foo(Integer arg);
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.firstof;
|
||||
|
||||
import cn.hippo4j.common.extension.annotation.Realization;
|
||||
|
||||
@Realization
|
||||
public class FirstOfExtImplA implements IFirstOfExtension {
|
||||
|
||||
@Override
|
||||
public Integer foo(Integer arg) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.firstof;
|
||||
|
||||
import cn.hippo4j.common.extension.annotation.Realization;
|
||||
|
||||
@Realization
|
||||
public class FirstOfExtImplB implements IFirstOfExtension {
|
||||
|
||||
@Override
|
||||
public Integer foo(Integer arg) {
|
||||
return arg;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.firstof;
|
||||
|
||||
import cn.hippo4j.common.extension.IExtension;
|
||||
|
||||
public interface IFirstOfExtension extends IExtension {
|
||||
|
||||
Integer foo(Integer arg);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.spi;
|
||||
|
||||
import cn.hippo4j.common.extension.IExtension;
|
||||
|
||||
public interface IOldSpi extends IExtension {
|
||||
|
||||
Boolean foo();
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.extension.spi;
|
||||
|
||||
public class IOldSpiImplA implements IOldSpi {
|
||||
|
||||
@Override
|
||||
public Boolean foo() {
|
||||
System.out.println(this.getClass().getName());
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
cn.hippo4j.common.extension.spi.IOldSpiImplA
|
Loading…
Reference in new issue