官网:https://dubbo.apache.org/zh/docs/v2.7/dev/source/adaptive-extension/
1、Java SPI 的使用
2、Dubbo 读取配置文件生成实例,按需加载接口实现类,还增加了 IOC 和 AOP 等特性
3、Dubbo 会为拓展接口生成具有代理功能的代码。然后通过 javassist 或 jdk 编译这段代码,得到 Class 类。Dubbo 不会为没有标注 Adaptive 注解的方法生成代理逻辑。方法代理逻辑会从 URL 中提取目标拓展的名称,因此代码生成逻辑的一个重要的任务是从方法的参数列表或者其他参数中获取 URL 数据
简单介绍了 SPI 机制的原理,本节通过一个示例演示 Java SPI 的使用方法。首先,我们定义一个接口,名称为 Robot。
public interface Robot {
void sayHello();
}
接下来定义两个实现类,分别为 OptimusPrime 和 Bumblebee。
public class OptimusPrime implements Robot {
@Override
public void sayHello() {
System.out.println("Hello, I am Optimus Prime.");
}
}
public class Bumblebee implements Robot {
@Override
public void sayHello() {
System.out.println("Hello, I am Bumblebee.");
}
}
接下来 META-INF/services 文件夹下创建一个文件,名称为 Robot 的全限定名 org.apache.spi.Robot。文件内容为实现类的全限定的类名,如下:
org.apache.spi.OptimusPrime
org.apache.spi.Bumblebee
做好所需的准备工作,接下来编写代码进行测试。
public class JavaSPITest {
@Test
public void sayHello() throws Exception {
ServiceLoader<Robot> serviceLoader = ServiceLoader.load(Robot.class);
System.out.println("Java SPI");
serviceLoader.forEach(Robot::sayHello);
}
}
最后来看一下测试结果,如下:
Java SPI
Hello, I am Optimus Prime.
Hello, I am Bumblebee.
在这应该多看官网,写的比较详细。这里写利用javassist生成代码的例子
public class ServiceFactoryBean<T> implements FactoryBean<T> {}
private Class<? extends RorServiceInfoListService> rorService;
private List<RorServiceInfoListService> list;
public ServiceFactoryBean(ApplicationContext applicationContext, Class<? extends RorServiceInfoListService> clz) {
this.rorService = clz;
Map<String, ? extends RorServiceInfoListService> map = applicationContext.getBeansOfType(clz);
list = new ArrayList<>(map.values());
}
@Override
public T getObject() throws Exception {
return get();
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
private T get() {
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
for (RorServiceInfoListService spi : list) {
// 第一个参数作为条件选择
return method.invoke(spi, args);
}
throw new IllegalStateException("no service server can execute! spiList: " + list);
}
};
Object o = null;
try {
o = newProxyInstance(Thread.currentThread().getContextClassLoader(), RorServiceInfoListService.class, invocationHandler);
} catch (Exception e) {
e.printStackTrace();
}
return (T)o;
}
public Object newProxyInstance(ClassLoader loader, Class<?> interfaceClass, InvocationHandler h) throws Exception {
ClassPool pool = ClassPool.getDefault();
// 1.创建代理类:public class NewProxyClass
CtClass proxy0 = pool.makeClass("Proxy0");
/* 2.给代理类添加字段:private InvocationHandler h; */
CtClass handle = pool.get(InvocationHandler.class.getName());
CtField field = new CtField(handle, "h", proxy0);
field.setModifiers(AccessFlag.PRIVATE);
proxy0.addField(field);
/* 3.添加构造函数:public NewProxyClass(InvocationHandler h) { this.h = h; } */
CtConstructor ctConstructor = new CtConstructor(new CtClass[] { handle }, proxy0);
ctConstructor.setBody("{this.h = $1;}"); // $0代表this, $1代表构造函数的第1个参数
proxy0.addConstructor(ctConstructor);
/* 4.为代理类添加相应接口方法及实现 */
pool.insertClassPath(new ClassClassPath(interfaceClass));
CtClass ctClass = pool.get(interfaceClass.getName());
// 4.1 为代理类添加接口:public class NewProxyClass implements IHello
proxy0.addInterface(ctClass);
// 4.2 为代理类添加相应方法及实现
CtMethod[] declaredMethods = ctClass.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
String methodFieldName = "m" + i; // 新方法名
// 4.2.1 为代理类添加反射方法字段
// 如:private static Method m1 = Class.forName("chapter9.javassistproxy3.IHello").getDeclaredMethod("sayHello2", new Class[] { Integer.TYPE });
/* 构造反射字段声明及赋值语句 */
String classParamsStr = "new Class[0]";
if (declaredMethods[i].getParameterTypes().length > 0) {
for (CtClass clazz : declaredMethods[i].getParameterTypes()) {
classParamsStr = ((classParamsStr == "new Class[0]") ? clazz.getName() : classParamsStr + "," + clazz.getName()) + ".class";
}
classParamsStr = "new Class[] {" + classParamsStr + "}";
}
String methodFieldTpl = "private static java.lang.reflect.Method %s = Class.forName(\"%s\").getDeclaredMethod(\"%s\", %s);";
String methodFieldBody = String.format(methodFieldTpl, "m" + i, interfaceClass.getName(), declaredMethods[i].getName(), classParamsStr);
System.out.println(methodFieldBody);
// 为代理类添加反射方法字段
CtField methodField = CtField.make(methodFieldBody, proxy0);
proxy0.addField(methodField);
/* 4.2.2 为方法添加方法体 */
/* 构造方法体 */
String methodBody = "h.invoke($0, " + methodFieldName + ", $args)";
// 如果有返回类型,则需要转换为相应类型后返回
if (CtPrimitiveType.voidType != declaredMethods[i].getReturnType()) {
// 对8个基本类型进行转型
// 例如:((Integer)this.h.invoke(this, this.m2, new Object[] { paramString, new Boolean(paramBoolean), paramObject })).intValue();
if (declaredMethods[i].getReturnType() instanceof CtPrimitiveType) {
CtPrimitiveType ctPrimitiveType = (CtPrimitiveType) declaredMethods[i].getReturnType();
methodBody = "return ((" + ctPrimitiveType.getWrapperName() + ") " + methodBody + ")." + ctPrimitiveType.getGetMethodName() + "()";
} else {// 对于非基本类型直接转型即可
methodBody = "return (" + declaredMethods[i].getReturnType().getName() + ") " + methodBody;
}
}
methodBody += ";";
/* 为代理类添加方法 */
CtMethod newMethod = new CtMethod(declaredMethods[i].getReturnType(), declaredMethods[i].getName(),declaredMethods[i].getParameterTypes(), proxy0);
newMethod.setBody(methodBody);
proxy0.addMethod(newMethod);
}
proxy0.writeFile("D://tmp");
// 5.生成代理实例. 将入参InvocationHandler h设置到代理类的InvocationHandler h变量
@SuppressWarnings("unchecked")
Object proxy = proxy0.toClass().getConstructor(InvocationHandler.class).newInstance(h);
return proxy;
}
public static void main(String[] args) throws Exception{
ClassPool pool = ClassPool.getDefault();
// 1.创建代理类:public class NewProxyClass
CtClass proxy0 = pool.makeClass("Proxy0");
/* 2.给代理类添加字段:private InvocationHandler h; */
CtClass handle = pool.get(InvocationHandler.class.getName());
CtField field = new CtField(handle, "h", proxy0);
field.setModifiers(AccessFlag.PRIVATE);
proxy0.addField(field);
/* 4.为代理类添加相应接口方法及实现 */
CtClass ctClass = pool.get("com.edu.datacenter.ror.service.RorServiceInfoListService");
// 4.1 为代理类添加接口:public class NewProxyClass implements IHello
proxy0.addInterface(ctClass);
/* 3.添加构造函数:public NewProxyClass(InvocationHandler h) { this.h = h; } */
CtConstructor ctConstructor = new CtConstructor(new CtClass[] { handle }, proxy0);
ctConstructor.setBody("{this.h = $1;}"); // $0代表this, $1代表构造函数的第1个参数
proxy0.addConstructor(ctConstructor);
// 为代理类添加反射方法字段
CtField methodField = CtField.make("private static java.lang.reflect.Method m0 = Class.forName(\"com.edu.datacenter.ror.service.RorServiceInfoListService\").getDeclaredMethod(\"getData\", new Class[] {com.edu.datacenter.ror.domain.ServiceCtsInfoListReq.class});", proxy0);
proxy0.addField(methodField);
proxy0.writeFile("D://tmp");
}
@Bean
public ServiceFactoryBean getServiceFactoryBean(ApplicationContext applicationContext) {
return new ServiceFactoryBean(applicationContext, RorServiceInfoListService.class);
}
@Bean("serviceProxy")
public RorServiceInfoListService getProxy(ServiceFactoryBean serviceFactoryBean) throws Exception {
return (RorServiceInfoListService)serviceFactoryBean.getObject();
}
@Autowired
private RorServiceInfoListService serviceProxy;
执行过程中,idea启动可以正常启动。但是放到测试环境,java -jar **.jar启动失败,报错信息
javassist.NotFoundException:.........................................
经修改为
可以正常启动,并执行代码
这里涉及一个小知识点:
1、BeanFactory与FactoryBean的区别,可以扫一遍
2、各种Ware接口,提供资源用的