在服務(本地和遠程)暴露的時候會調用proxyFactory.getInvoker方法
具體位置:
- 本地暴露:ServiceConfig#exportLocal line:538
- 遠程暴露: ServiceConfig#doExportUrlsFor1Protocol line:512
會先調用AOP織入的類StubProxyFactoryWrapper#getInvoker
然后執行JavassistProxyFactory#getInvoker
JavassistProxyFactory#getInvoker如下
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// getWrapper會生成代理類
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
然后進入Wrapper#getWrapper--> Wrapper#makeWrapper, 具體代碼就在這個makeWrapper方法里面
例如現在暴露的服務如下:
public interface TestService {
String getData(String var1);
List<String> getList();
}
那么生成的代理類如下:
public class Wrapper0 extends com.alibaba.dubbo.common.bytecode.Wrapper {
/**
* 屬性名, 屬性類型
*/
public static java.util.Map pts = new HashMap<String, Class<?>>();
public static String[] pns = new String[0];
/**
* 所有的方法名
*/
public static String[] mns = {"getData"};
/**
* 本類中的所有方法名
*/
public static String[] dmns = {"getData"};
/**
* 一個方法中所有的參數類型 mts[n]屬性的個數和方法的個數形同
*/
public static Class[] mts0 = {String.class};
public static Class[] mts1 = {List.class};
@Override
public String[] getPropertyNames() {
return pns;
}
@Override
public boolean hasProperty(String n) {
return pts.containsKey(n);
}
@Override
public Class getPropertyType(String n) {
return (Class) pts.get(n);
}
@Override
public String[] getMethodNames() {
return mns;
}
@Override
public String[] getDeclaredMethodNames() {
return dmns;
}
@Override
public void setPropertyValue(Object o, String n, Object v) {
per.qiao.service.TestService w;
try {
w = ((per.qiao.service.TestService) o);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + n + "\" filed or setter method in class per.qiao.service.TestService.");
}
@Override
public Object getPropertyValue(Object o, String n) {
per.qiao.service.TestService w;
try {
w = ((per.qiao.service.TestService) o);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
if (n.equals("list")) {
return w.getList();
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + n + "\" filed or setter method in class per.qiao.service.TestService.");
}
/**
* 在調用接口時,就時調用的這個方法
@param o 接口實例
@param n 方法名
@param p 參數類型
@param v 參數
*/
@Override
public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
per.qiao.service.TestService w;
try {
w = ((per.qiao.service.TestService) o);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
try {
//這個try范圍內就是你所需要暴露的所有方法
if ("getData".equals(n) && p.length == 1) {
return w.getData((java.lang.String) v[0]);
}
if ("getList".equals(n) && p.length == 0) {
return w.getList();
}
} catch (Throwable e) {
throw new java.lang.reflect.InvocationTargetException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method \"" + n + "\" in class per.qiao.service.TestService.");
}
}
javassist生成動態代理類的示例
public class CompilerByJavassist {
public static void main(String[] args) throws Exception {
// ClassPool:CtClass對象的容器
ClassPool pool = ClassPool.getDefault();
// 通過ClassPool生成一個public新類Emp.java
CtClass ctClass = pool.makeClass("per.qiao.javassist.Qiao");
// 添加屬性 private String name
CtField nameFild = new CtField(pool.getCtClass("java.lang.String"), "name", ctClass);
nameFild.setModifiers(Modifier.PRIVATE);
ctClass.addField(nameFild);
// 其次添加熟悉privtae int age
CtField ageField = new CtField(pool.getCtClass("int"), "age", ctClass);
ageField.setModifiers(Modifier.PRIVATE);
ctClass.addField(ageField);
// 為屬性name和age添加getXXX和setXXX方法
ctClass.addMethod(CtNewMethod.getter("getName", nameFild));
ctClass.addMethod(CtNewMethod.setter("setName", nameFild));
ctClass.addMethod(CtNewMethod.getter("getAge", ageField));
ctClass.addMethod(CtNewMethod.setter("setAge", ageField));
// 添加構造函數
CtConstructor ctConstructor = new CtConstructor(new CtClass[] {}, ctClass);
// 為構造函數設置函數體
StringBuffer buffer = new StringBuffer();
buffer.append("{\n").append("name=\"qiaogege\";\n").append("age=25;\n}");
ctConstructor.setBody(buffer.toString());
// 把構造函數添加到新的類中
ctClass.addConstructor(ctConstructor);
// 添加自定義方法 public void printInfo {...}
CtMethod ctMethod = new CtMethod(CtClass.voidType, "printInfo", new CtClass[] {}, ctClass);
// 為自定義方法設置修飾符
ctMethod.setModifiers(Modifier.PUBLIC);
// 為自定義方法設置函數體
StringBuffer buffer2 = new StringBuffer();
buffer2.append("{\nSystem.out.println(\"begin!\");\n")
.append("System.out.println(name);\n")
.append("System.out.println(age);\n")
.append("System.out.println(\"over!\");\n").append("}");
ctMethod.setBody(buffer2.toString());
ctClass.addMethod(ctMethod);
//最好生成一個class
Class<?> clazz = ctClass.toClass();
Object obj = clazz.newInstance();
//ctClass.debugWriteFile("E://Qiao.class");
//反射 執行方法
obj.getClass().getMethod("printInfo", new Class[] {})
.invoke(obj, new Object[] {});
ctClass.debugWriteFile("E://Emp.class");
// 把生成的class文件寫入文件
byte[] byteArr = ctClass.toBytecode();
FileOutputStream fos = new FileOutputStream(new File("E://Qiao.class"));
fos.write(byteArr);
fos.close();
}
}
生成的Class文件放入IDEA中反編譯后的結果如下
public class Qiao {
private String name = "qiaogege";
private int age = 25;
public String getName() {
return this.name;
}
public void setName(String var1) {
this.name = var1;
}
public int getAge() {
return this.age;
}
public void setAge(int var1) {
this.age = var1;
}
public Qiao() {
}
public void printInfo() {
System.out.println("begin!");
System.out.println(this.name);
System.out.println(this.age);
System.out.println("over!");
}
}
小結:
1. Dubbo通過javassist動態生成一個代理類對象,該對象不同於普通的javassist生成的對象,而是只記錄了暴露接口中的方法的相關參數,生成一個Wrapper類型的對象,並保存在WRAPPER_MAP中,通過invokeMethod方法來執行相應的方法
2. 再將生成的Wrapper對象包裝在AbstractProxyInvoker中進行服務暴露
還有一篇 dubbo中使用動態代理