摘要
上一篇文章,讲述了类加载机制的破坏场景-JNDI的远程加载类方式。本篇,讲述Java的另一种破坏双亲委派机制的场景-SPI。它可以用于很多框架的扩展,常见的如Java JDBC、Spring、SpringBoot、Dubbo、Log日志等。
一、概念
SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。 SPI的作用就是为这些被扩展的API寻找服务实现。使用SPI机制的优势是实现解耦,使得第三方服务模块的装配控制逻辑与调用者的业务代码分离。
二、JDK SPI
Java中如果想要使用SPI功能,首先要提供标准的SPI接口(服务供应商接口),然后再由供应商提供相关接口实现,最后由服务调用者使用。通过SPI机制中约定的信息进行查询相应接口的实现,如下图:
SPI遵循的约定如下:
1、当服务提供者提供了一个接口的一种具体实现后,在META-INF/services 目录下创建一个以 “接口全限定名” 为命名的文件,内容为实现类的权限定名;
2、调用者将SPI接口实现类所在的jar包,放在主程序的classpath中;
3、主程序通过 java.util.ServiceLoader 动态加载实现模块,它通过扫描META-INF/services 目录下的配置文件找到实现类的全限定名,把类加载到JVM
4、SPI的实现类必须要有一个无参构造
SPI实现案例:
1、首先新建一个maven项目用于存放SPI标准接口,该项目主要是提供给供应商用于依赖并且实现提供自己的服务.
package SPI;
public interface HelloService {
String HelloSPI();
}
2、新建一个maven项目用于存放SPI标准接口服务实现,该项目中添加依赖上面接口项目maven信息
package SPI;
public class HelloServiceImpl1 implements HelloService{
@Override
public String HelloSPI() {
return "HelloServiceImpl1.HelloSPI()方法调用";
}
}
package SPI;
public class HelloServiceImpl2 implements HelloService {
@Override
public String HelloSPI() {
return "HelloServiceImpl2.HelloSPI()方法调用";
}
}
并且在接口实现项目resources目录新建META-INF/services/SPI.HelloService文件,内容如下
SPI.HelloServiceImpl1
SPI.HelloServiceImpl2
3、新建测试的maven项目,在pom中添加上面两个项目依赖,用ServiceLoad调用接口
package SPI;
import java.util.ServiceLoader;
public class App {
public static void main(String[] args) {
ServiceLoader<HelloService> loader=ServiceLoader.load(HelloService.class);
for(HelloService helloSPI : loader){
System.out.println(helloSPI.getClass().getName() + " , result is : "+helloSPI.HelloSPI());
}
}
}
测试效果:
SPI.HelloServiceImpl1 , result is : HelloServiceImpl1.HelloSPI()方法调用
SPI.HelloServiceImpl2 , result is : HelloServiceImpl2.HelloSPI()方法调用
Process finished with exit code 0
Java SPI实现ServiceLoad源码解析:
应用代码:
ServiceLoader<HelloService> loader=ServiceLoader.load(HelloService.class);
ServiceLoader源码:【典型的静态工厂模式、迭代器模式】
#根据接口类加载SPI服务实现,默认使用当前线程的类加载器
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
#调用构造方法返回ServiceLoader<S>对象
public static <S> ServiceLoader<S> load(Class<S> service,ClassLoader loader){
return new ServiceLoader<>(service, loader);
}
#构造器,私有
private ServiceLoader(Class<S> svc, ClassLoader cl) {
//接口类空检查
service = Objects.requireNonNull(svc, "Service interface cannot be null");
//初始化类加载器,如果为空则使用应用系统类加载器
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
//安全控制
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
//加载
reload();
}
// Cached providers, in instantiation order
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
#加载实现(重新加载)
public void reload() {
//清理缓存
providers.clear();
//实例化一个延迟迭代器
lookupIterator = new LazyIterator(service, loader);
}
#根据SPI接口名和URL地址读取SPI定义文件中的内容,存放到ArrayList里并返回迭代器
private Iterator<String> parse(Class<?> service, URL u) throws ServiceConfigurationError {
InputStream in = null;
BufferedReader r = null;
ArrayList<String> names = new ArrayList<>();
try {
in = u.openStream();
r = new BufferedReader(new InputStreamReader(in, "utf-8"));
int lc = 1;
//一行一行读
while ((lc = parseLine(service, u, r, lc, names)) >= 0);
} catch (IOException x) {
fail(service, "Error reading configuration file", x);
} finally {
try {
if (r != null) r.close();
if (in != null) in.close();
} catch (IOException y) {
fail(service, "Error closing configuration file", y);
}
}
return names.iterator();
}
#读取SPI接口实现定义文件内容
private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
List<String> names) throws IOException, ServiceConfigurationError {
String ln = r.readLine();
if (ln == null) {
return -1;
}
int ci = ln.indexOf('#');
if (ci >= 0) ln = ln.substring(0, ci);
ln = ln.trim();
int n = ln.length();
if (n != 0) {
if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
fail(service, u, lc, "Illegal configuration-file syntax");
int cp = ln.codePointAt(0);
if (!Character.isJavaIdentifierStart(cp))
fail(service, u, lc, "Illegal provider-class name: " + ln);
for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
cp = ln.codePointAt(i);
if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
fail(service, u, lc, "Illegal provider-class name: " + ln);
}
if (!providers.containsKey(ln) && !names.contains(ln))
names.add(ln);
}
return lc + 1;
}
#定义SPI迭代器发现服务的目录前缀
private static final String PREFIX = "META-INF/services/";
#LazyIterator是内部类[迭代器模式实现]
private class LazyIterator implements Iterator<S> {
Class<S> service;
ClassLoader loader;
Enumeration<URL> configs = null;
Iterator<String> pending = null;
String nextName = null;
private LazyIterator(Class<S> service, ClassLoader loader) {
this.service = service;
this.loader = loader;
}
#判断"META-INF/services/+接口全限定名文件"中是否存在接口实现
private boolean hasNextService() {
if (nextName != null) {
return true;
}
//第一次迭代时,获取文件
if (configs == null) {
try {
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
//将SPI服务实现定义文件的内容读取到一个ArrayList并将迭代器返回设置
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());
}
//设置第一个nextName
nextName = pending.next();
return true;
}
#获取下一个service接口实现实例
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
//使用Class.forName()方式加载,并且不执行初始化动作
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,
"Provider " + cn + " not found");
}
//检查类型是否实现SPI接口
if (!service.isAssignableFrom(c)) {
fail(service,
"Provider " + cn + " not a subtype");
}
try {
//最后调用类反射方法获取实例
S p = service.cast(c.newInstance());
//缓存到服务提供者集合
providers.put(cn, p);
return p;
} catch (Throwable x) {
fail(service,
"Provider " + cn + " could not be instantiated",
x);
}
throw new Error(); // This cannot happen
}
#实现对外开放迭代器接口
public boolean hasNext() {
if (acc == null) {
return hasNextService();
} else {
PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
public Boolean run() { return hasNextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
#实现对外开放迭代器接口
public S next() {
if (acc == null) {
return nextService();
} else {
PrivilegedAction<S> action = new PrivilegedAction<S>() {
public S run() { return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
#该方法不支持,直接抛出异常
public void remove() {
throw new UnsupportedOperationException();
}
}
Dubbo SPI实现案例:
#pom.xml引入依赖
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
1、扩展接口项目定义相关接口
package SPI;
import org.apache.dubbo.common.extension.SPI;
@SPI
public interface HelloDubboService {
String HelloDubboSPI();
}
2、供应商服务项目实现上述接口
package SPI;
public class HelloDubboServiceImpl1 implements HelloDubboService{
@Override
public String HelloDubboSPI() {
return "HelloDubboServiceImpl1.HelloDubboSPI()方法调用";
}
}
package SPI;
public class HelloDubboServiceImpl2 implements HelloDubboService {
@Override
public String HelloDubboSPI() {
return "HelloDubboServiceImpl2.HelloDubboSPI()方法调用";
}
}
并且在接口实现项目resources目录新建META-INF/services/SPI.HelloDubboService文件,内容如下
HelloImpl1=SPI.HelloDubboServiceImpl1
HelloImpl2=SPI.HelloDubboServiceImpl2
3、客户端项目调用相关接口
public class App {
public static void main(String[] args) {
ExtensionLoader<HelloDubboService> loader = ExtensionLoader.getExtensionLoader(HelloDubboService.class);
System.out.println("============================================");
System.out.println(loader.getExtension("HelloImpl2").HelloDubboSPI());
System.out.println("============================================");
}
}
效果:
六月 15, 2022 2:23:02 下午 org.apache.dubbo.common.logger.LoggerFactory info
信息: using logger: org.apache.dubbo.common.logger.jcl.JclLoggerAdapter
============================================
HelloDubboServiceImpl2.HelloDubboSPI()方法调用
============================================
Disconnected from the target VM, address: '127.0.0.1:53740', transport: 'socket'
Process finished with exit code 0
Dubbo SPI- ExtensionLoader源码分析:
Dubbo中几个扩展相关的概念、
扩展点:一个接口,并且在类上添加@SPI("HelloImpl1")用于标识,HelloImpl1表示默认的扩展实现名称,该名称定义在接口实现类的jar包的Dubbo SPI实现文件中;路径如下:
META-INF/dubbo/internal/+服务接口全限定名
META-INF/dubbo/internal/+服务接口全限定名
META-INF/dubbo/+服务接口全限定名
META-INF/services/+服务接口全限定名
META-INF/services/+服务接口全限定名
扩展:扩展点(接口)的实现。
扩展自适应实例:其实就是一个Extension的代理,它实现了扩展点接口。在调用扩展点的接口方法时,会根据实际的参数来决定要使用哪个扩展。dubbo会根据接口中的参数,自动地决定选择哪个实现。可以由开发者自己实现自适应扩展实现类(类上面添加@Adaptive标识);也通过在接口方法上添加@Adaptive标识方法是自适应的,扩展点加载器会根据接口类型动态的生成一个扩展点代理,该代理可根据URL查询条件中的参数动态的决定使用哪个扩展。
扩展点加载器 :用于加载扩展点的加载器ExtensionLoader的实例;
@SPI:该注解作用于扩展点的接口上,表明该接口是一个扩展点。
@Adaptive:@Adaptive注解用在扩展接口的方法上。表示该方法是一个自适应方法。Dubbo在为扩展点生成自适应实例时,如果方法有@Adaptive注解,会为该方法生成对应的代码。
自适应类:
@Adaptive
public class HelloDubboServiceImpl1 implements HelloDubboService{
@Override
public String HelloDubboSPI() {
return "HelloDubboServiceImpl1.HelloDubboSPI()方法调用";
}
}
调用方式:
ExtensionLoader<HelloDubboService> loader = ExtensionLoader.getExtensionLoader(HelloDubboService.class);
System.out.println(loader.getAdaptiveExtension().HelloDubboSPI());
自适方法:
import org.apache.dubbo.common.URL;
@SPI("HelloImpl1")
public interface HelloDubboService {
@Adaptive
String HelloDubboSPI(URL url);
@Adaptive
String HelloDubboSPI2(URL url);
}
public class HelloDubboServiceImpl1 implements HelloDubboService{
@Override
public String HelloDubboSPI(URL url) {
return "HelloDubboServiceImpl1.HelloDubboSPI()方法调用";
}
@Override
public String HelloDubboSPI2(URL url) {
return "HelloDubboServiceImpl1.HelloDubboSPI2()方法调用";
}
}
public class HelloDubboServiceImpl2 implements HelloDubboService {
@Override
public String HelloDubboSPI(URL url) {
return "HelloDubboServiceImpl2.HelloDubboSPI()方法调用";
}
@Override
public String HelloDubboSPI2(URL url) {
return "HelloDubboServiceImpl2.HelloDubboSPI2()方法调用";
}
}
调用方式:
ExtensionLoader<HelloDubboService> loader = ExtensionLoader.getExtensionLoader(HelloDubboService.class);
URL url=new URL("rpc","127.0.0.1",222).addParameter("hello.dubbo.service","HelloImpl1");
System.out.println(loader.getAdaptiveExtension().HelloDubboSPI2(url));
dubbo自动生成代码如下:
package SPI;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class HelloDubboService$Adaptive implements SPI.HelloDubboService {
public java.lang.String HelloDubboSPI(org.apache.dubbo.common.URL arg0) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("hello.dubbo.service", "HelloImpl1");
if (extName == null)
throw new IllegalStateException("Failed to get extension (SPI.HelloDubboService) name from url (" + url.toString() + ") use keys([hello.dubbo.service])");
SPI.HelloDubboService extension = (SPI.HelloDubboService) ExtensionLoader.getExtensionLoader(SPI.HelloDubboService.class).getExtension(extName);
return extension.HelloDubboSPI(arg0);
}
public java.lang.String HelloDubboSPI2(org.apache.dubbo.common.URL arg0) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("hello.dubbo.service", "HelloImpl1");
if (extName == null)
throw new IllegalStateException("Failed to get extension (SPI.HelloDubboService) name from url (" + url.toString() + ") use keys([hello.dubbo.service])");
SPI.HelloDubboService extension = (SPI.HelloDubboService) ExtensionLoader.getExtensionLoader(SPI.HelloDubboService.class).getExtension(extName);
return extension.HelloDubboSPI2(arg0);
}
}
@Activate:@Activate称为自动激活扩展点注解,主要使用在有多个扩展点实现、需要同时根据不同条件被激活的场景中,如Filter需要多个同时激活,因为每个Filter实现的是不同的功能。
@Activate的参数
参数名 效果
-
- String[] group() URL中的分组如果匹配则激活
-
- String[] value() URL中如果包含该key值,则会激活
-
- String[] before() 填写扩展点列表,表示哪些扩展点要在本扩展点之前激活
-
- String[] after() 表示哪些扩展点需要在本扩展点之后激活
-
- int order() 排序信息
例:
org.apache.dubbo.Filter扩展点有非常多的实现,例如CacheFilter。
@Activate( group = {"consumer", "provider"},value = {"cache"})
public class CacheFilter implements Filter {
private CacheFactory cacheFactory;
...
}
group = {consumer, provider} 表示客户端和和服务端都会加载,value表示url中有cache的时候对扩展点激活。
public static void main(String[] args) {
ExtensionLoader<Filter> loader = ExtensionLoader.getExtensionLoader(Filter.class);
URL url = new URL("", "", 0);
// 在url中添加cache参数
url = url.addParameter("cache", "cache");
List<Filter> filters = loader.getActivateExtension(url, "cache");
//List<Filter> filters = loader.getActivateExtension(url, "cache","consumers");
System.out.println(filters);
}
在上面的代码中,如果在url添加cache参数,便可以在filters得到org.apache.dubbo.cache.filter.CacheFilter@...对象了。
扩展点工厂 :dubbo在实现IOC注入时,需要使用对象工厂来获取用于注入的对象。而dubbo这里的工厂也是个扩展点,同时框架提供了三个实现;
//自适应扩展点工厂:
该自适应扩展点会从以下支持的两种工厂中获取实例,如果
adaptive=org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
//基于SPI实现扩展点工厂
只处理SPI注解的扩展点
spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory
//基于spring实现扩展点工厂
先根据name去获取,如果不存在,则根据type去获取
spring=org.apache.dubbo.config.spring.extension.SpringExtensionFactory
Dubbo AOP :dubbo SPI机制中通过定义包装类来实现AOP。就是将真实的扩展点对象包装到一个AOP代理类里面,代理类同时也实现了SPI接口,并且在该接口中调用真实扩展点的方法,同时还可以在调用真实扩展点的前后添加处理逻辑;
AOP切面包装类
public class HelloDubboServiceAopWraper implements HelloDubboService {
HelloDubboService helloDubboService;
public HelloDubboServiceAopWraper(HelloDubboService helloDubboService){
this.helloDubboService=helloDubboService;
}
@Override
public String HelloDubboSPI(URL url) {
System.out.println("包装类HelloDubboSPI");
return helloDubboService.HelloDubboSPI(url);
}
@Override
public String HelloDubboSPI2(URL url) {
System.out.println("包装类HelloDubboSPI2");
return helloDubboService.HelloDubboSPI2(url);
}
}
在META-INF\services\SPI.HelloDubboService添加该包装类:
SPI.HelloDubboServiceAopWraper
调用方式:
ExtensionLoader<HelloDubboService> loader = ExtensionLoader.getExtensionLoader(HelloDubboService.class);
URL url=new URL("rpc","127.0.0.1",222).addParameter("hello.dubbo.service","HelloImpl2");
System.out.println(loader.getAdaptiveExtension().HelloDubboSPI2(url));
System.out.println(loader.getExtension("HelloImpl1").HelloDubboSPI2(url));
Dubbo IOC :dubbo SPI机制中实现了通过遍历扩展点中setMethodName的形式方法,根据对应的类型和属性名称使用扩展点工厂来获取待注入对象,来实现依赖注入。
定义依赖属性类接口
@SPI("ManPerson")
public interface Person {
@Adaptive
void sayHellow(URL url);
}
实现1
public class ManPerson implements Person {
@Override
public void sayHellow(URL url) {
System.out.println("ManPerson-sayHellow");
}
}
实现2
public class WumanPerson implements Person {
@Override
public void sayHellow(URL url) {
System.out.println("WumanPerson-sayHellow");
}
}
配置扩展META-INF\services\SPI.Person
ManPerson=SPI.ManPerson
WumanPerson=SPI.WumanPerson
依赖注入:
public class HelloDubboServiceImpl1 implements HelloDubboService{
private Person person;
public void setPerson(Person person){
this.person=person;
}
@Override
public String HelloDubboSPI(URL url) {
person.sayHellow(url);
return "HelloDubboServiceImpl1.HelloDubboSPI()方法调用";
}
@Override
public String HelloDubboSPI2(URL url) {
person.sayHellow(url);
return "HelloDubboServiceImpl1.HelloDubboSPI2()方法调用";
}
}
调用方式:
URL url=new URL("rpc","127.0.0.1",222).addParameter("hello.dubbo.service","HelloImpl1").addParameter("person","ManPerson");
System.out.println(loader.getAdaptiveExtension().HelloDubboSPI2(url));
System.out.println(loader.getExtension("HelloImpl1").HelloDubboSPI2(url));
ExtensionLoader源码:【典型的静态工厂模式】
package org.apache.dubbo.common.extension;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;
import org.apache.dubbo.common.Extension;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.compiler.Compiler;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.support.ActivateComparator;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.ConcurrentHashSet;
import org.apache.dubbo.common.utils.ConfigUtils;
import org.apache.dubbo.common.utils.Holder;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
public class ExtensionLoader<T> {
private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);
//扩展点接口实现-定义的目录
private static final String SERVICES_DIRECTORY = "META-INF/services/";
private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
private static final String DUBBO_INTERNAL_DIRECTORY = "META-INF/dubbo/internal/";
//逗号分隔正则
private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
//扩展点加载器缓存
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap();
//扩展点实例缓存
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap();
//扩展点接口类型
private final Class<?> type;
//扩展点工厂(对象工厂),IOC实现时,需要用到
private final ExtensionFactory objectFactory;
//
private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap();
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder();
private final Map<String, Object> cachedActivates = new ConcurrentHashMap();
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap();
private final Holder<Object> cachedAdaptiveInstance = new Holder();
private volatile Class<?> cachedAdaptiveClass = null;
private String cachedDefaultName;
private volatile Throwable createAdaptiveInstanceError;
private Set<Class<?>> cachedWrapperClasses;
private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap();
private ExtensionLoader(Class<?> type) {
this.type = type;
//1、当接口类型为ExtensionFactory.class,则设置对象工厂为空;
//2、否则通过扩展点的方式获取对象工厂的自适应实例
this.objectFactory = type == ExtensionFactory.class ? null : (ExtensionFactory)getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension();
}
//判断接口是否有@SPI注解标识
private static <T> boolean withExtensionAnnotation(Class<T> type) {
return type.isAnnotationPresent(SPI.class);
}
//通过接口类型获取扩展点加载器
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Extension type == null");
} else if (!type.isInterface()) {
//接口检查
throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
} else if (!withExtensionAnnotation(type)) {
//@SPI注解标识检查
throw new IllegalArgumentException("Extension type (" + type + ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
} else {
//通过扩展点接口类型从缓存中获取扩展点加载器
ExtensionLoader<T> loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
//缓存中不存在,则new扩展点加载器
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
}
return loader;
}
}
public static void resetExtensionLoader(Class type) {
ExtensionLoader loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
if (loader != null) {
Map<String, Class<?>> classes = loader.getExtensionClasses();
Iterator var3 = classes.entrySet().iterator();
while(var3.hasNext()) {
Entry<String, Class<?>> entry = (Entry)var3.next();
EXTENSION_INSTANCES.remove(entry.getValue());
}
classes.clear();
EXTENSION_LOADERS.remove(type);
}
}
//获取类加载器
private static ClassLoader findClassLoader() {
//根据优先级关系获取类加载器,当上一个级别没获取到,则到下一个级别去获取;当前线程上下文类加载器>ExtensionLoader.class的类加载器>系统应用类加载器
return ClassUtils.getClassLoader(ExtensionLoader.class);
}
public String getExtensionName(T extensionInstance) {
return this.getExtensionName(extensionInstance.getClass());
}
public String getExtensionName(Class<?> extensionClass) {
this.getExtensionClasses();
return (String)this.cachedNames.get(extensionClass);
}
//根据传递的URL、key获取激活扩展活对象
public List<T> getActivateExtension(URL url, String key) {
return this.getActivateExtension(url, (String)key, (String)null);
}
//根据传递的URL、多个key数组获取激活扩展活对象
public List<T> getActivateExtension(URL url, String[] values) {
return this.getActivateExtension(url, (String[])values, (String)null);
}
//根据传递的URL、key、group获取激活扩展活对象
public List<T> getActivateExtension(URL url, String key, String group) {
String value = url.getParameter(key);
return this.getActivateExtension(url, StringUtils.isEmpty(value) ? null : CommonConstants.COMMA_SPLIT_PATTERN.split(value), group);
}
//根据传递的URL、多个key数组、group获取激活扩展活对象
public List<T> getActivateExtension(URL url, String[] values, String group) {
List<T> exts = new ArrayList();
List<String> names = values == null ? new ArrayList(0) : Arrays.asList(values);
String name;
Object ext;
if (!((List)names).contains("-default")) {
//加载扩展点类映射关系
this.getExtensionClasses();
Iterator var6 = this.cachedActivates.entrySet().iterator();
label59:
while(true) {
String[] activateGroup;
String[] activateValue;
while(true) {
if (!var6.hasNext()) {
exts.sort(ActivateComparator.COMPARATOR);
break label59;
}
Entry<String, Object> entry = (Entry)var6.next();
name = (String)entry.getKey();
ext = entry.getValue();
if (ext instanceof Activate) {
activateGroup = ((Activate)ext).group();
activateValue = ((Activate)ext).value();
break;
}
if (ext instanceof com.alibaba.dubbo.common.extension.Activate) {
activateGroup = ((com.alibaba.dubbo.common.extension.Activate)ext).group();
activateValue = ((com.alibaba.dubbo.common.extension.Activate)ext).value();
break;
}
}
if (this.isMatchGroup(group, activateGroup)) {
T ext = this.getExtension(name);
if (!((List)names).contains(name) && !((List)names).contains("-" + name) && this.isActive(activateValue, url)) {
exts.add(ext);
}
}
}
}
List<T> usrs = new ArrayList();
for(int i = 0; i < ((List)names).size(); ++i) {
name = (String)((List)names).get(i);
if (!name.startsWith("-") && !((List)names).contains("-" + name)) {
if ("default".equals(name)) {
if (!usrs.isEmpty()) {
exts.addAll(0, usrs);
usrs.clear();
}
} else {
ext = this.getExtension(name);
usrs.add(ext);
}
}
}
if (!usrs.isEmpty()) {
exts.addAll(usrs);
}
return exts;
}
private boolean isMatchGroup(String group, String[] groups) {
if (StringUtils.isEmpty(group)) {
return true;
} else {
if (groups != null && groups.length > 0) {
String[] var3 = groups;
int var4 = groups.length;
for(int var5 = 0; var5 < var4; ++var5) {
String g = var3[var5];
if (group.equals(g)) {
return true;
}
}
}
return false;
}
}
private boolean isActive(String[] keys, URL url) {
if (keys.length == 0) {
return true;
} else {
String[] var3 = keys;
int var4 = keys.length;
label34:
for(int var5 = 0; var5 < var4; ++var5) {
String key = var3[var5];
Iterator var7 = url.getParameters().entrySet().iterator();
String k;
String v;
do {
do {
if (!var7.hasNext()) {
continue label34;
}
Entry<String, String> entry = (Entry)var7.next();
k = (String)entry.getKey();
v = (String)entry.getValue();
} while(!k.equals(key) && !k.endsWith("." + key));
} while(!ConfigUtils.isNotEmpty(v));
return true;
}
return false;
}
}
public T getLoadedExtension(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
} else {
Holder<Object> holder = this.getOrCreateHolder(name);
return holder.get();
}
}
private Holder<Object> getOrCreateHolder(String name) {
Holder<Object> holder = (Holder)this.cachedInstances.get(name);
if (holder == null) {
this.cachedInstances.putIfAbsent(name, new Holder());
holder = (Holder)this.cachedInstances.get(name);
}
return holder;
}
public Set<String> getLoadedExtensions() {
return Collections.unmodifiableSet(new TreeSet(this.cachedInstances.keySet()));
}
public Object getLoadedAdaptiveExtensionInstances() {
return this.cachedAdaptiveInstance.get();
}
//通过扩展名称来获取实例对象
public T getExtension(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
} else if ("true".equals(name)) {
//返回默认的扩展点对象实例
return this.getDefaultExtension();
} else {
Holder<Object> holder = this.getOrCreateHolder(name);
Object instance = holder.get();
if (instance == null) {
synchronized(holder) {
instance = holder.get();
if (instance == null) {
//根据名称创建扩展点实例对象
instance = this.createExtension(name);
holder.set(instance);
}
}
}
return instance;
}
}
public T getDefaultExtension() {
this.getExtensionClasses();
return !StringUtils.isBlank(this.cachedDefaultName) && !"true".equals(this.cachedDefaultName) ? this.getExtension(this.cachedDefaultName) : null;
}
public boolean hasExtension(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
} else {
Class<?> c = this.getExtensionClass(name);
return c != null;
}
}
public Set<String> getSupportedExtensions() {
Map<String, Class<?>> clazzes = this.getExtensionClasses();
return Collections.unmodifiableSet(new TreeSet(clazzes.keySet()));
}
public String getDefaultExtensionName() {
this.getExtensionClasses();
return this.cachedDefaultName;
}
public void addExtension(String name, Class<?> clazz) {
this.getExtensionClasses();
if (!this.type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Input type " + clazz + " doesn't implement the Extension " + this.type);
} else if (clazz.isInterface()) {
throw new IllegalStateException("Input type " + clazz + " can't be interface!");
} else {
if (!clazz.isAnnotationPresent(Adaptive.class)) {
if (StringUtils.isBlank(name)) {
throw new IllegalStateException("Extension name is blank (Extension " + this.type + ")!");
}
if (((Map)this.cachedClasses.get()).containsKey(name)) {
throw new IllegalStateException("Extension name " + name + " already exists (Extension " + this.type + ")!");
}
this.cachedNames.put(clazz, name);
((Map)this.cachedClasses.get()).put(name, clazz);
} else {
if (this.cachedAdaptiveClass != null) {
throw new IllegalStateException("Adaptive Extension already exists (Extension " + this.type + ")!");
}
this.cachedAdaptiveClass = clazz;
}
}
}
/** @deprecated */
@Deprecated
public void replaceExtension(String name, Class<?> clazz) {
this.getExtensionClasses();
if (!this.type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Input type " + clazz + " doesn't implement Extension " + this.type);
} else if (clazz.isInterface()) {
throw new IllegalStateException("Input type " + clazz + " can't be interface!");
} else {
if (!clazz.isAnnotationPresent(Adaptive.class)) {
if (StringUtils.isBlank(name)) {
throw new IllegalStateException("Extension name is blank (Extension " + this.type + ")!");
}
if (!((Map)this.cachedClasses.get()).containsKey(name)) {
throw new IllegalStateException("Extension name " + name + " doesn't exist (Extension " + this.type + ")!");
}
this.cachedNames.put(clazz, name);
((Map)this.cachedClasses.get()).put(name, clazz);
this.cachedInstances.remove(name);
} else {
if (this.cachedAdaptiveClass == null) {
throw new IllegalStateException("Adaptive Extension doesn't exist (Extension " + this.type + ")!");
}
this.cachedAdaptiveClass = clazz;
this.cachedAdaptiveInstance.set((Object)null);
}
}
}
//获取扩展点自适应实例对象
public T getAdaptiveExtension() {
//从缓存中取扩展点自适应实例对象
Object instance = this.cachedAdaptiveInstance.get();
if (instance == null) {
//如果包含创建自适应对象失败的信息,则抛出异常
if (this.createAdaptiveInstanceError != null) {
throw new IllegalStateException("Failed to create adaptive instance: " + this.createAdaptiveInstanceError.toString(), this.createAdaptiveInstanceError);
}
synchronized(this.cachedAdaptiveInstance) {
instance = this.cachedAdaptiveInstance.get();
if (instance == null) {
try {
//创建扩展自适应实例对象
instance = this.createAdaptiveExtension();
this.cachedAdaptiveInstance.set(instance);
} catch (Throwable var5) {
this.createAdaptiveInstanceError = var5;
throw new IllegalStateException("Failed to create adaptive instance: " + var5.toString(), var5);
}
}
}
}
return instance;
}
private IllegalStateException findException(String name) {
Iterator var2 = this.exceptions.entrySet().iterator();
Entry entry;
do {
if (!var2.hasNext()) {
StringBuilder buf = new StringBuilder("No such extension " + this.type.getName() + " by name " + name);
int i = 1;
Iterator var4 = this.exceptions.entrySet().iterator();
while(var4.hasNext()) {
Entry<String, IllegalStateException> entry = (Entry)var4.next();
if (i == 1) {
buf.append(", possible causes: ");
}
buf.append("\r\n(");
buf.append(i++);
buf.append(") ");
buf.append((String)entry.getKey());
buf.append(":\r\n");
buf.append(StringUtils.toString((Throwable)entry.getValue()));
}
return new IllegalStateException(buf.toString());
}
entry = (Entry)var2.next();
} while(!((String)entry.getKey()).toLowerCase().contains(name.toLowerCase()));
return (IllegalStateException)entry.getValue();
}
//根据名称创建扩展点实例
private T createExtension(String name) {
Class<?> clazz = (Class)this.getExtensionClasses().get(name);
if (clazz == null) {
throw this.findException(name);
} else {
try {
T instance = EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
//反射创建实例
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = EXTENSION_INSTANCES.get(clazz);
}
//IOC实现(依赖注入)
this.injectExtension(instance);
//AOP实现(包装扩展点实例)
Set<Class<?>> wrapperClasses = this.cachedWrapperClasses;
//此处为循环包装,也就是可以包装多层
Class wrapperClass;
if (CollectionUtils.isNotEmpty(wrapperClasses)) {
for(Iterator var5 = wrapperClasses.iterator(); var5.hasNext(); instance = this.injectExtension(wrapperClass.getConstructor(this.type).newInstance(instance))) {
wrapperClass = (Class)var5.next();
}
}
return instance;
} catch (Throwable var7) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " + this.type + ") couldn't be instantiated: " + var7.getMessage(), var7);
}
}
}
private T injectExtension(T instance) {
try {
if (this.objectFactory != null) {
Method[] var2 = instance.getClass().getMethods();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
Method method = var2[var4];
//没有设置DisableInject注解的setter方法处理
if (this.isSetter(method) && method.getAnnotation(DisableInject.class) == null) {
Class<?> pt = method.getParameterTypes()[0];
//判断是否为JAVA基础类型
if (!ReflectUtils.isPrimitives(pt)) {
try {
//根据setter方法获取属性名称
String property = this.getSetterProperty(method);
//通过扩展点工厂获取扩展实例
Object object = this.objectFactory.getExtension(pt, property);
if (object != null) {
//调用setter方法设置依赖
method.invoke(instance, object);
}
} catch (Exception var9) {
logger.error("Failed to inject via method " + method.getName() + " of interface " + this.type.getName() + ": " + var9.getMessage(), var9);
}
}
}
}
}
} catch (Exception var10) {
logger.error(var10.getMessage(), var10);
}
return instance;
}
private String getSetterProperty(Method method) {
return method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
}
private boolean isSetter(Method method) {
return method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers());
}
private Class<?> getExtensionClass(String name) {
if (this.type == null) {
throw new IllegalArgumentException("Extension type == null");
} else if (name == null) {
throw new IllegalArgumentException("Extension name == null");
} else {
return (Class)this.getExtensionClasses().get(name);
}
}
//获取扩展点实现类映射关系key:实现名称,value:实现类名称
private Map<String, Class<?>> getExtensionClasses() {
//缓存中获取
Map<String, Class<?>> classes = (Map)this.cachedClasses.get();
if (classes == null) {
synchronized(this.cachedClasses) {
classes = (Map)this.cachedClasses.get();
if (classes == null) {
//加载扩展点实现类
classes = this.loadExtensionClasses();
this.cachedClasses.set(classes);
}
}
}
return classes;
}
//加载扩展点实现类
private Map<String, Class<?>> loadExtensionClasses() {
//获取默认的扩展名
this.cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap();
//从以下目录获取扩展类映射关系
this.loadDirectory(extensionClasses, "META-INF/dubbo/internal/", this.type.getName());
this.loadDirectory(extensionClasses, "META-INF/dubbo/internal/", this.type.getName().replace("org.apache", "com.alibaba"));
this.loadDirectory(extensionClasses, "META-INF/dubbo/", this.type.getName());
this.loadDirectory(extensionClasses, "META-INF/dubbo/", this.type.getName().replace("org.apache", "com.alibaba"));
this.loadDirectory(extensionClasses, "META-INF/services/", this.type.getName());
this.loadDirectory(extensionClasses, "META-INF/services/", this.type.getName().replace("org.apache", "com.alibaba"));
return extensionClasses;
}
//获取默认的扩展名,并缓存到cachedDefaultName字段
private void cacheDefaultExtensionName() {
//SPI扩展点接口注解里的默认值
SPI defaultAnnotation = (SPI)this.type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if ((value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if (names.length > 1) {
throw new IllegalStateException("More than 1 default extension name on extension " + this.type.getName() + ": " + Arrays.toString(names));
}
if (names.length == 1) {
this.cachedDefaultName = names[0];
}
}
}
}
//从某个目录下获取某个类型的扩展映射关系存入extensionClasses
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
//META-INF/.../SPI接口类全限定名
String fileName = dir + type;
try {
//获取类加载器
ClassLoader classLoader = findClassLoader();
Enumeration urls;
//根据文件名获取资源url
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
while(urls.hasMoreElements()) {
java.net.URL resourceURL = (java.net.URL)urls.nextElement();
//加载扩展点实现类映射关系
this.loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable var8) {
logger.error("Exception occurred when loading extension class (interface: " + type + ", description file: " + fileName + ").", var8);
}
}
//加载扩展点实现类映射关系
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8));
Throwable var5 = null;
try {
String line;
try {
while((line = reader.readLine()) != null) {
int ci = line.indexOf('#');
if (ci >= 0) {
line = line.substring(0, ci);
}
line = line.trim();
if (line.length() > 0) {
try {
String name = null;
int i = line.indexOf('=');
if (i > 0) {
name = line.substring(0, i).trim();
line = line.substring(i + 1).trim();
}
if (line.length() > 0) {
//加载类,存缓存
this.loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
}
} catch (Throwable var19) {
IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + this.type + ", class line: " + line + ") in " + resourceURL + ", cause: " + var19.getMessage(), var19);
this.exceptions.put(line, e);
}
}
}
} catch (Throwable var20) {
var5 = var20;
throw var20;
}
} finally {
if (reader != null) {
if (var5 != null) {
try {
reader.close();
} catch (Throwable var18) {
var5.addSuppressed(var18);
}
} else {
reader.close();
}
}
}
} catch (Throwable var22) {
logger.error("Exception occurred when loading extension class (interface: " + this.type + ", class file: " + resourceURL + ") in " + resourceURL, var22);
}
}
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
if (!this.type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Error occurred when loading extension class (interface: " + this.type + ", class line: " + clazz.getName() + "), class " + clazz.getName() + " is not subtype of interface.");
} else {
if (clazz.isAnnotationPresent(Adaptive.class)) {
//将扩展点自适应类缓存起来
this.cacheAdaptiveClass(clazz);
} else if (this.isWrapperClass(clazz)) {
//将包装类缓存起来用于AOP
this.cacheWrapperClass(clazz);
} else {
//
clazz.getConstructor();
if (StringUtils.isEmpty(name)) {
name = this.findAnnotationName(clazz);
if (name.length() == 0) {
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
}
}
String[] names = NAME_SEPARATOR.split(name);
if (ArrayUtils.isNotEmpty(names)) {
//缓存激活类到名称的映射
this.cacheActivateClass(clazz, names[0]);
String[] var6 = names;
int var7 = names.length;
for(int var8 = 0; var8 < var7; ++var8) {
String n = var6[var8];
this.cacheName(clazz, n);
this.saveInExtensionClass(extensionClasses, clazz, n);
}
}
}
}
}
private void cacheName(Class<?> clazz, String name) {
if (!this.cachedNames.containsKey(clazz)) {
this.cachedNames.put(clazz, name);
}
}
private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name) {
Class<?> c = (Class)extensionClasses.get(name);
if (c == null) {
extensionClasses.put(name, clazz);
} else if (c != clazz) {
throw new IllegalStateException("Duplicate extension " + this.type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName());
}
}
//缓存激活扩展类映射关系
private void cacheActivateClass(Class<?> clazz, String name) {
Activate activate = (Activate)clazz.getAnnotation(Activate.class);
if (activate != null) {
this.cachedActivates.put(name, activate);
} else {
com.alibaba.dubbo.common.extension.Activate oldActivate = (com.alibaba.dubbo.common.extension.Activate)clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
if (oldActivate != null) {
this.cachedActivates.put(name, oldActivate);
}
}
}
private void cacheAdaptiveClass(Class<?> clazz) {
if (this.cachedAdaptiveClass == null) {
this.cachedAdaptiveClass = clazz;
} else if (!this.cachedAdaptiveClass.equals(clazz)) {
throw new IllegalStateException("More than 1 adaptive class found: " + this.cachedAdaptiveClass.getClass().getName() + ", " + clazz.getClass().getName());
}
}
private void cacheWrapperClass(Class<?> clazz) {
if (this.cachedWrapperClasses == null) {
this.cachedWrapperClasses = new ConcurrentHashSet();
}
this.cachedWrapperClasses.add(clazz);
}
//判断该类是否为包装类
private boolean isWrapperClass(Class<?> clazz) {
try {
clazz.getConstructor(this.type);
return true;
} catch (NoSuchMethodException var3) {
return false;
}
}
private String findAnnotationName(Class<?> clazz) {
Extension extension = (Extension)clazz.getAnnotation(Extension.class);
if (extension == null) {
String name = clazz.getSimpleName();
if (name.endsWith(this.type.getSimpleName())) {
name = name.substring(0, name.length() - this.type.getSimpleName().length());
}
return name.toLowerCase();
} else {
return extension.value();
}
}
//创建扩展点自适应实例对象
private T createAdaptiveExtension() {
try {
//创建扩展点自适应实例对象,并设置依赖
return this.injectExtension(this.getAdaptiveExtensionClass().newInstance());
} catch (Exception var2) {
throw new IllegalStateException("Can't create adaptive extension " + this.type + ", cause: " + var2.getMessage(), var2);
}
}
//获取扩展点自适应类
private Class<?> getAdaptiveExtensionClass() {
//Dubbo SPI定义目录META-INF/..去获取扩展点的实现类
this.getExtensionClasses();
//Dubbo SPI中不存在扩展自适应类,则代码拼装创建一个
return this.cachedAdaptiveClass != null ? this.cachedAdaptiveClass : (this.cachedAdaptiveClass = this.createAdaptiveExtensionClass());
}
//生成扩展自适应类
private Class<?> createAdaptiveExtensionClass() {
String code = (new AdaptiveClassCodeGenerator(this.type, this.cachedDefaultName)).generate();
ClassLoader classLoader = findClassLoader();
Compiler compiler = (Compiler)getExtensionLoader(Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
public String toString() {
return this.getClass().getName() + "[" + this.type.getName() + "]";
}
}
总结一下:
SPI,全称为 Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,主要用于服务发现、供应商扩展等。
- Java SPI实现起来比较简单,都是约定俗成的事,按他的标准来就行,在实现Java SPI需要满足以下条件
(1)、写一个接口,并且提供对应的具体的实现
(2)、在META-INF/service/目录下新建一个以接口的全限定名命名的文件,如jdbc.sql.Driver
(3)、使用ServiceLoader.load()方法进行加载
-
Java SPI工作原理主要是通过ServiceLoader来加载指定目录下的类实现
-
Java SPI的缺点:扫描META-INF/service/目录,加载目录下所有的service,不管你有没有使用到
-
Dubbo SPI 在Java SPI的基础上对其进行加强,使用Key-Value的形式来标识各个Service,并且增加了对扩展点的IOC(支持Spring获取bean注入)和AOP支持
-
Dubbo主要是通过ExtensionLoader来进行进行扩展点的加载
-
Dubbo的自适应扩展点就是我们通过自己传入的参数来进行动态的加载扩展点
-
@Adaptive注解可以标注在类和方法上,两者的区别是:标注在类上说明这个类是自适应扩展点的类,标注在方法上需要动态生成字节码,然后动态生成类
-
@Activate注解有点类似Spring的条件注解,根据条件进行扩展点的激活
-
Dubbo支持动态的生成自适应类对象,并且支持自动编译加载
adaptive=org.apache.dubbo.common.compiler.support.AdaptiveCompiler
jdk=org.apache.dubbo.common.compiler.support.JdkCompiler
javassist=org.apache.dubbo.common.compiler.support.JavassistCompiler(默认)