001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.core.spi;
017
018import io.jboot.utils.AnnotationUtil;
019import io.jboot.utils.ClassScanner;
020import io.jboot.utils.ClassUtil;
021import io.jboot.utils.StrUtil;
022
023import java.util.Iterator;
024import java.util.List;
025import java.util.Objects;
026import java.util.ServiceLoader;
027
028/**
029 * SPI 扩展加载器
030 * <p>
031 * 使用方法:
032 * <p>
033 * 第一步:编写支持扩展点的类,例如MyJbootRpc extends Jbootrpc。
034 * 第二步:给该类添加上注解 JbootSpi, 例如 @JbootSpi("myrpc") MyJbootRpc extends Jbootrpc ...
035 * 第三步:给jboot.properties配置上类型,jboot.rpc.type = myrpc
036 * <p>
037 * 通过这三步,就可以扩展自己的Jbootrpc实现
038 *
039 * @author michael yang
040 */
041public class JbootSpiLoader {
042
043
044    /**
045     * 通过 SPI 去加载相应的扩展子类
046     *
047     * @param clazz
048     * @param spiName
049     * @param <T>
050     * @return
051     */
052    public static <T> T load(Class<T> clazz, String spiName, Object... paras) {
053        List<Class<T>> classes = ClassScanner.scanSubClass(clazz, true);
054        if (classes.isEmpty()) {
055            return null;
056        }
057
058        for (Class<T> c : classes) {
059            JbootSpi spiConfig = c.getAnnotation(JbootSpi.class);
060            if (spiConfig != null && spiName.equals(AnnotationUtil.get(spiConfig.value()))) {
061                return ClassUtil.newInstance(c, paras);
062            }
063            //support config class name
064            else if (spiName.equals(c.getName())) {
065                return ClassUtil.newInstance(c, paras);
066            }
067        }
068
069        return null;
070    }
071
072    /**
073     * 通过 SPI 去加载相应的扩展子类
074     *
075     * @param clazz
076     * @param spiName
077     * @param <T>
078     * @return
079     */
080    public static <T> T load(Class<T> clazz, String spiName) {
081        T returnObject = loadByServiceLoader(clazz, spiName);
082        if (returnObject != null) {
083            return returnObject;
084        }
085
086        if (StrUtil.isBlank(spiName)) {
087            return null;
088        }
089
090        List<Class<T>> classes = ClassScanner.scanSubClass(clazz, true);
091        if (classes.isEmpty()) {
092            return null;
093        }
094
095        for (Class<T> c : classes) {
096            JbootSpi spiConfig = c.getAnnotation(JbootSpi.class);
097            if (spiConfig != null && Objects.equals(spiName, AnnotationUtil.get(spiConfig.value()))) {
098                return ClassUtil.newInstance(c);
099            }
100            //support config class name
101            else if (Objects.equals(spiName, c.getName())) {
102                return ClassUtil.newInstance(c);
103            }
104        }
105
106        return null;
107    }
108
109    /**
110     * 通过 ServiceLoader 加载
111     *
112     * @param clazz
113     * @param spiName
114     * @param <T>
115     * @return
116     */
117    public static <T> T loadByServiceLoader(Class<T> clazz, String spiName) {
118        ServiceLoader<T> serviceLoader = ServiceLoader.load(clazz);
119        Iterator<T> iterator = serviceLoader.iterator();
120
121        while (iterator.hasNext()) {
122            T returnObject = iterator.next();
123
124            if (spiName == null) {
125                return returnObject;
126            }
127
128            JbootSpi spiConfig = returnObject.getClass().getAnnotation(JbootSpi.class);
129            if (spiConfig == null) {
130                continue;
131            }
132
133            if (spiName.equals(AnnotationUtil.get(spiConfig.value()))) {
134                return returnObject;
135            }
136        }
137
138        return null;
139    }
140}