底层api调用上层代码
假如有两个java普通项目java-api, java-api-impl,后者是前者的实现并依赖前者, 我们要在java-api调用java-api-impl的具体实现怎么设计呢?
- 反射
- java spi(本质是反射+文件)
- 反射+注解
- 反射+文件(spring.factroy)
反射-工厂模式
//java-api
public interface Say {
void say();
}
public class SayFactory {
public static <T implements Say> T create(Class<T> type) {
try {
T t = type.newInstance();
return t;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
//java-api-impl
public class ZhanSanSay implements Say {
@Override
public void say() {
System.out.println("zhansan say");
}
}
//test
Say say = SayFactory.create(ZhanSanSay.class);
say.say();
反射-driver模式
//java-api
public interface Say {
void say();
}
public class SayManage {
public final static List<Say> sayList = new ArrayList<>();
public static void registerSay(Say say){
if(say != null){
sayList.add(say);
}
}
public static Say getSay(){
if(sayList.size()>0){
return sayList.get(0);
}
throw new RuntimeException("Not find Say!");
}
}
//java-api-impl
public class ZhanSanSay implements Say {
static {
SayManage.registerSay(new ZhanSanSay());
}
@Override
public void say() {
System.out.println("zhansan say");
}
}
//test
Class.forName("com.example.ZhanSanSay");
Say say = SayManage.getSay();
say.say();
反射-slf4j模式(slf4j 1.8版本以前)
//java-api
public interface Say {
void say();
}
//java-api
// 这里会报出StaticSayBinder找不到红色错误,我们编译时在java-api项目中自定义StaticSayBinder一个实现,打包时用maven插件删除它
public class SayFactory {
private static volatile boolean init = false;
public static Say getSay() {
if(!init){
bind();
}
return StaticSayBinder.getSingleton().getSay();
}
private final static void bind() {
try {
StaticLoggerBinder.getSingleton();
init = true;
} catch (NoClassDefFoundError ncde) {
throw new RuntimeException("Not find Say !");
} catch (Exception e) {
throw new RuntimeException("Unexpected initialization failure", e);
}
}
}
//java-api-impl
public class StaticSayBinder {
private static StaticSayBinder SINGLETON = new StaticSayBinder();
public static StaticSayBinder getSingleton() {
return SINGLETON;
}
public Say getSay(){
return new ZhanSanSay();
}
}
public class ZhanSanSay implements Say {
@Override
public void say() {
System.out.println("zhansan say");
}
}
//test
Say say = SayFactory.getSay();
say.say();
java spi(slf4j 1.8及以后)
ServiceLoader是jdk6里面引进的一个特性。它用来实现SPI(Service Provider Interface),一种服务发现机制,很多框架用它来做来做服务的扩展发现。
首先定义一个SPIService接口
//java-api
public interface Say {
void say();
}
再定义两个实现类
//java-api-impl
public class ZhanSanSay implements Say {
@Override
public void say() {
System.out.println("zhansan say");
}
}
public class LiSiSay implements Say {
@Override
public void say() {
System.out.println("lisi say");
}
}
在java-api-impl项目ClassPath路径META-INF/services/下添加配置文件com.study.Say,META-INF/services/com.study.Say,文件名为接口的全限定类名。在配置文件中加入两个实现类的全限定类名。
com.study.impl.ZhanSanSay
com.study.impl.LiSiSay
写一个测试类SPITest.java
public class SPITest {
public static void main(String[] args) {
ServiceLoader<Say> loaders = ServiceLoader.load(Say.class);
Iterator<Say> it = loaders.iterator();
while (it.hasNext()) {
Say say= it.next();
say.say();
}
}
}
运行结果:
zhansan say
lisi say
ServiceLoader的load方法将在META-INF/services/com.study.Say中配置的子类都进行了加载。
反射+注解
先添加依赖:
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
在加一个注解扫描工具类:
public class AnnotationUtil {
public static <T> Set<Class<? extends T>> findClassList(Class<? extends T> clazz, Class<? extends Annotation> annotationClass) {
String packageName = clazz.getPackage().getName();
Reflections reflections = new Reflections(packageName);
return reflections.getTypesAnnotatedWith(annotationClass)
.stream()
.filter(clazz::isAssignableFrom)
.map(c -> (Class<? extends T>) c)
.collect(Collectors.toSet());
}
}
具体实现:
//java-api
public interface Say {
void say();
}
public @interface SayAnnotation {
}
public class SayFactory {
public static Say getSay() throws RuntimeException {
Set<Class<? extends Say>> classList = AnnotationUtil.findClassList(Say.class, SayAnnotation.class);
return classList.stream()
.findFirst()
.map(clazz->{
Say say = null;
try {
say = clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return say;
})
.<RuntimeException>orElseThrow(()->{
throw new RuntimeException("Not find Say !");
});
}
}
//java-api-impl
//这里需要注意:ZhanSanSay的包名一定要和Say的包名一样,不然注解扫描不到
@SayAnnotation
public class ZhanSanSay implements Say {
@Override
public void say() {
System.out.println("zhansan say");
}
}
//test
Say say = SayFactory.getSay();
say.say();
反射+文件(spring.factory)
添加依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.21</version>
</dependency>
具体实现:
//java-api
public interface Say {
void say();
}
public class SayFactory {
public static Say getSay(){
return SpringFactoriesLoader.loadFactoryNames(Say.class, null)
.stream()
.map(className->{
Say factoryInstance;
try {
Class<?> aClass = Class.forName(className);
factoryInstance = (Say) aClass.newInstance();
} catch (ClassNotFoundException|InstantiationException|IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException("Not find Say !");
}
return factoryInstance;
})
.findFirst()
.<RuntimeException>orElseThrow(()->{
throw new RuntimeException("Not find Say !");
});
}
}
//java-api-impl
public class ZhanSanSay implements Say {
@Override
public void say() {
System.out.println("zhansan say");
}
}
//java-api-impl项目中添加文件classpath:META-INF/spring.factories,其内容为(根据实际情况添加全类名):
com.study.api.Say=\
com.study.api.impl.ZhanSanSay
//test
Say say = SayFactory.getSay();
say.say();