support spi

This commit is contained in:
Looly 2020-03-02 18:08:58 +08:00
parent 85c9dae9ae
commit bd6b07f6b9
7 changed files with 81 additions and 130 deletions

View File

@ -15,6 +15,7 @@
* 【core 】 增加ServiceLoaderUtil
* 【core 】 增加EnumUtil.getEnumAt方法
* 【core 】 增强EnumConvert判断能力issue#I17082@Gitee
* 【log 】 使用SPI机制代替硬编码
### Bug修复

View File

@ -1,6 +1,7 @@
package cn.hutool.core.util;
import java.util.Iterator;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
/**
@ -18,6 +19,25 @@ import java.util.ServiceLoader;
*/
public class ServiceLoaderUtil {
/**
* 加载第一个可用服务如果用户定义了多个接口实现类只获取第一个不报错的服务
*
* @param <T> 接口类型
* @param clazz 服务接口
* @return 第一个服务接口实现对象无实现返回{@code null}
*/
public static <T> T loadFirstAvailable(Class<T> clazz) {
final Iterator<T> iterator = load(clazz).iterator();
if(iterator.hasNext()){
try {
return iterator.next();
} catch (ServiceConfigurationError e) {
// ignore
}
}
return null;
}
/**
* 加载第一个服务如果用户定义了多个接口实现类只获取第一个
*

View File

@ -1,30 +1,23 @@
package cn.hutool.extra.template.engine;
import com.jfinal.template.Engine;
import cn.hutool.core.util.ServiceLoaderUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateException;
import cn.hutool.extra.template.engine.beetl.BeetlEngine;
import cn.hutool.extra.template.engine.enjoy.EnjoyEngine;
import cn.hutool.extra.template.engine.freemarker.FreemarkerEngine;
import cn.hutool.extra.template.engine.rythm.RythmEngine;
import cn.hutool.extra.template.engine.thymeleaf.ThymeleafEngine;
import cn.hutool.extra.template.engine.velocity.VelocityEngine;
import cn.hutool.log.StaticLog;
import com.jfinal.template.Engine;
/**
* 简单模板工厂用于根据用户引入的模板引擎jar自动创建对应的模板引擎对象
*
* @author looly
*
* @author looly
*/
public class TemplateFactory {
/**
* 根据用户引入的模板引擎jar自动创建对应的模板引擎对象<br>
* 推荐创建的引擎单例使用此方法每次调用会返回新的引擎
*
*
* @param config 模板配置包括编码模板文件path等信息
* @return {@link Engine}
*/
@ -37,41 +30,16 @@ public class TemplateFactory {
/**
* 根据用户引入的模板引擎jar自动创建对应的模板引擎对象<br>
* 推荐创建的引擎单例使用此方法每次调用会返回新的引擎
*
*
* @param config 模板配置包括编码模板文件path等信息
* @return {@link Engine}
*/
private static TemplateEngine doCreate(TemplateConfig config) {
try {
return new BeetlEngine(config);
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new FreemarkerEngine(config);
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new VelocityEngine(config);
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new RythmEngine(config);
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new EnjoyEngine(config);
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new ThymeleafEngine(config);
} catch (NoClassDefFoundError e) {
// ignore
final TemplateEngine engine = ServiceLoaderUtil.loadFirstAvailable(TemplateEngine.class);
if(null != engine){
return engine;
}
throw new TemplateException("No template found ! Please add one of template jar to your project !");
}
}

View File

@ -1,17 +1,9 @@
package cn.hutool.extra.tokenizer.engine;
import cn.hutool.core.util.ServiceLoaderUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.tokenizer.TokenizerEngine;
import cn.hutool.extra.tokenizer.TokenizerException;
import cn.hutool.extra.tokenizer.engine.analysis.SmartcnEngine;
import cn.hutool.extra.tokenizer.engine.ansj.AnsjEngine;
import cn.hutool.extra.tokenizer.engine.hanlp.HanLPEngine;
import cn.hutool.extra.tokenizer.engine.ikanalyzer.IKAnalyzerEngine;
import cn.hutool.extra.tokenizer.engine.jcseg.JcsegEngine;
import cn.hutool.extra.tokenizer.engine.jieba.JiebaEngine;
import cn.hutool.extra.tokenizer.engine.mmseg.MmsegEngine;
import cn.hutool.extra.tokenizer.engine.mynlp.MynlpEngine;
import cn.hutool.extra.tokenizer.engine.word.WordEngine;
import cn.hutool.log.StaticLog;
/**
@ -38,51 +30,11 @@ public class TokenizerFactory {
* @return {@link TokenizerEngine}
*/
private static TokenizerEngine doCreate() {
try {
return new AnsjEngine();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new HanLPEngine();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new IKAnalyzerEngine();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new JcsegEngine();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new JiebaEngine();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new MmsegEngine();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new WordEngine();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new SmartcnEngine();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new MynlpEngine();
} catch (NoClassDefFoundError e) {
// ignore
final TokenizerEngine engine = ServiceLoaderUtil.loadFirstAvailable(TokenizerEngine.class);
if(null != engine){
return engine;
}
throw new TokenizerException("No tokenizer found ! Please add some tokenizer jar to your project !");
}
}

View File

@ -0,0 +1,6 @@
cn.hutool.extra.template.engine.beetl.BeetlEngine
cn.hutool.extra.template.engine.freemarker.FreemarkerEngine
cn.hutool.extra.template.engine.velocity.VelocityEngine
cn.hutool.extra.template.engine.rythm.RythmEngine
cn.hutool.extra.template.engine.enjoy.EnjoyEngine
cn.hutool.extra.template.engine.thymeleaf.ThymeleafEngine

View File

@ -0,0 +1,9 @@
cn.hutool.extra.tokenizer.engine.ansj.AnsjEngine
cn.hutool.extra.tokenizer.engine.hanlp.HanLPEngine
cn.hutool.extra.tokenizer.engine.ikanalyzer.IKAnalyzerEngine
cn.hutool.extra.tokenizer.engine.jcseg.JcsegEngine
cn.hutool.extra.tokenizer.engine.jieba.JiebaEngine
cn.hutool.extra.tokenizer.engine.mmseg.MmsegEngine
cn.hutool.extra.tokenizer.engine.word.WordEngine
cn.hutool.extra.tokenizer.engine.analysis.SmartcnEngine
cn.hutool.extra.tokenizer.engine.mynlp.MynlpEngine

View File

@ -14,13 +14,12 @@ import cn.hutool.log.dialect.tinylog.TinyLogFactory;
import java.net.URL;
import java.util.Map;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
/**
* 日志工厂类
*
*
* @author Looly
* @see Slf4jLogFactory
* @see Log4j2LogFactory
* @see Log4jLogFactory
@ -29,20 +28,21 @@ import java.util.concurrent.ConcurrentHashMap;
* @see JbossLogFactory
* @see ConsoleLogFactory
* @see JdkLogFactory
*
* @author Looly
*
*/
public abstract class LogFactory {
/** 日志框架名,用于打印当前所用日志框架 */
/**
* 日志框架名用于打印当前所用日志框架
*/
protected String name;
/** 日志对象缓存 */
/**
* 日志对象缓存
*/
private Map<Object, Log> logCache;
/**
* 构造
*
*
* @param name 日志框架名
*/
public LogFactory(String name) {
@ -52,7 +52,7 @@ public abstract class LogFactory {
/**
* 获取日志框架名用于打印当前所用日志框架
*
*
* @return 日志框架名
* @since 4.1.21
*/
@ -62,7 +62,7 @@ public abstract class LogFactory {
/**
* 获得日志对象
*
*
* @param name 日志对象名
* @return 日志对象
*/
@ -77,7 +77,7 @@ public abstract class LogFactory {
/**
* 获得日志对象
*
*
* @param clazz 日志对应类
* @return 日志对象
*/
@ -92,7 +92,7 @@ public abstract class LogFactory {
/**
* 创建日志对象
*
*
* @param name 日志对象名
* @return 日志对象
*/
@ -100,7 +100,7 @@ public abstract class LogFactory {
/**
* 创建日志对象
*
*
* @param clazz 日志对应类
* @return 日志对象
*/
@ -110,7 +110,7 @@ public abstract class LogFactory {
* 检查日志实现是否存在<br>
* 此方法仅用于检查所提供的日志相关类是否存在当传入的日志类类不存在时抛出ClassNotFoundException<br>
* 此方法的作用是在detectLogFactory方法自动检测所用日志时如果实现类不存在调用此方法会自动抛出异常从而切换到下一种日志的检测
*
*
* @param logClassName 日志实现相关类
*/
protected void checkLogExist(Class<?> logClassName) {
@ -118,6 +118,7 @@ public abstract class LogFactory {
}
// ------------------------------------------------------------------------- Static start
/**
* @return 当前使用的日志工厂
*/
@ -127,7 +128,9 @@ public abstract class LogFactory {
/**
* 自定义日志实现
*
*
* @param logFactoryClass 日志工厂类
* @return 自定义的日志工厂类
* @see Slf4jLogFactory
* @see Log4j2LogFactory
* @see Log4jLogFactory
@ -136,9 +139,6 @@ public abstract class LogFactory {
* @see JbossLogFactory
* @see ConsoleLogFactory
* @see JdkLogFactory
*
* @param logFactoryClass 日志工厂类
* @return 自定义的日志工厂类
*/
public static LogFactory setCurrentLogFactory(Class<? extends LogFactory> logFactoryClass) {
return GlobalLogFactory.set(logFactoryClass);
@ -146,7 +146,9 @@ public abstract class LogFactory {
/**
* 自定义日志实现
*
*
* @param logFactory 日志工厂类对象
* @return 自定义的日志工厂类
* @see Slf4jLogFactory
* @see Log4j2LogFactory
* @see Log4jLogFactory
@ -155,9 +157,6 @@ public abstract class LogFactory {
* @see JbossLogFactory
* @see ConsoleLogFactory
* @see JdkLogFactory
*
* @param logFactory 日志工厂类对象
* @return 自定义的日志工厂类
*/
public static LogFactory setCurrentLogFactory(LogFactory logFactory) {
return GlobalLogFactory.set(logFactory);
@ -165,7 +164,7 @@ public abstract class LogFactory {
/**
* 获得日志对象
*
*
* @param name 日志对象名
* @return 日志对象
*/
@ -175,7 +174,7 @@ public abstract class LogFactory {
/**
* 获得日志对象
*
*
* @param clazz 日志对应类
* @return 日志对象
*/
@ -194,7 +193,8 @@ public abstract class LogFactory {
* 决定日志实现
* <p>
* 依次按照顺序检查日志库的jar是否被引入如果未引入任何日志库则检查ClassPath下的logging.properties存在则使用JdkLogFactory否则使用ConsoleLogFactory
*
*
* @return 日志实现类
* @see Slf4jLogFactory
* @see Log4j2LogFactory
* @see Log4jLogFactory
@ -203,7 +203,6 @@ public abstract class LogFactory {
* @see JbossLogFactory
* @see ConsoleLogFactory
* @see JdkLogFactory
* @return 日志实现类
*/
public static LogFactory create() {
final LogFactory factory = doCreate();
@ -215,7 +214,8 @@ public abstract class LogFactory {
* 决定日志实现
* <p>
* 依次按照顺序检查日志库的jar是否被引入如果未引入任何日志库则检查ClassPath下的logging.properties存在则使用JdkLogFactory否则使用ConsoleLogFactory
*
*
* @return 日志实现类
* @see Slf4jLogFactory
* @see Log4j2LogFactory
* @see Log4jLogFactory
@ -224,16 +224,11 @@ public abstract class LogFactory {
* @see JbossLogFactory
* @see ConsoleLogFactory
* @see JdkLogFactory
* @return 日志实现类
*/
private static LogFactory doCreate() {
final ServiceLoader<LogFactory> factories = ServiceLoaderUtil.load(LogFactory.class);
for (LogFactory factory : factories) {
try {
return factory;
} catch (ServiceConfigurationError e) {
// ignore
}
final LogFactory factory = ServiceLoaderUtil.loadFirstAvailable(LogFactory.class);
if(null != factory){
return factory;
}
// 未找到任何可支持的日志库时判断依据当JDK Logging的配置文件位于classpath中使用JDK Logging否则使用Console