在spring的配置文件中配置的bean,spring会进行依赖注入和初始化对象。
根据配置不同,spring会选择不同的代理方式。对于JDK动态代理、cglib动态代理,spring会找到目标接口的实现类并初始化一个对象,对于Dubbo的consumer,默认会使用Dubbo自己写的动态代理实现方式(除非明确配置为使用JDK等代理),使用Javassist生成目标接口的代理类,并初始化该类的对象,这种是一种工厂方式。
在spring的上下文中,保存的实际上是bean的代理,而不是直接保存目标对象。
以下代码可以指定一个在spring中注入过的类名,指定方法名,然后从spring上下文中得到这个对应的代理,并执行对应的方法。
/**
* @param service 在spring配置文件中注册的id
* @param method 方法名
* @param data 方法传入参数
* @throws Exception
*/
public void testDubboService(String service,String method,String data) throws Exception{
System.out.println("service---"+service);
System.out.println("method---"+method);
System.out.println("data---"+data);
Object obj=ApplicationContextUtil.getBean(service);
if(AopUtils.isJdkDynamicProxy(obj)) { //jdk代理
Field h = obj.getClass().getDeclaredField("CGLIB$CALLBACK_0");
h.setAccessible(true);
Object dynamicAdvisedInterceptor = h.get(obj);
Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
advised.setAccessible(true);
Object newObj = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
Map map=ApplicationContextUtil.getBeanDefinitions();
BeanDefinition definition=map.get(service);
String className=definition.getBeanClassName();
Class beanClass=Class.forName(className);
Method oneMethod=beanClass.getMethod(method, String.class);
oneMethod.invoke(newObj, data);//执行
} else if(AopUtils.isCglibProxy(obj)){ //cglib代理
Field h = obj.getClass().getSuperclass().getDeclaredField("h");
h.setAccessible(true);
AopProxy aopProxy = (AopProxy) h.get(obj);
Field advised = aopProxy.getClass().getDeclaredField("advised");
advised.setAccessible(true);
Object newObj = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();
Map map=ApplicationContextUtil.getBeanDefinitions();
BeanDefinition definition=map.get(service);
String className=definition.getBeanClassName();
Class beanClass=Class.forName(className);
Method oneMethod=beanClass.getMethod(method, String.class);
oneMethod.invoke(newObj, data);//执行
} else if(obj.getClass().getName().startsWith("com.alibaba.dubbo.common.bytecode.proxy")){//dubbo代理
Field handlerField=obj.getClass().getDeclaredField("handler");
handlerField.setAccessible(true);
com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler invokerInvocationHandler = (com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler)handlerField.get(obj);
Field invokerField=invokerInvocationHandler.getClass().getDeclaredField("invoker");
invokerField.setAccessible(true);
com.alibaba.dubbo.rpc.Invoker invoker=(com.alibaba.dubbo.rpc.Invoker)invokerField.get(invokerInvocationHandler);
Field failoverClusterInvokerField=invoker.getClass().getDeclaredField("invoker");
failoverClusterInvokerField.setAccessible(true);
FailoverClusterInvoker failoverClusterInvoker =(FailoverClusterInvoker)failoverClusterInvokerField.get(invoker);
Class failoverClusterInvokerInterfaceClass=failoverClusterInvoker.getInterface();
Method oneMethod=failoverClusterInvokerInterfaceClass.getMethod(method, String.class);
Object result=oneMethod.invoke(obj, data);//执行
Class resultClass=result.getClass();
}
}
bean是从上下文中获取的,Method是从spring记录的BeanDefinitions来获取的,按照bean不同的代理方式选择不同的获取方式。
上面代码只写了参数是一个String的情况,实际上传入参数和返回值可能会更复杂。
更新的分割线====================================================================================================
更新了一下,在dubbo代理的代码里,原来支持只有一个参数而且必须是String类型的方法,现在加上了支持有包装类参数的方法,参数是多个也可以
多个参数的话,各个参数之间用换行符隔开,包装类的参数使用JSON格式,使用了com.alibaba.fastjson.JSON
JDK代理和CGLib代理的使用方式其实是一样的
代码如下:
/**
* @param service 在spring配置文件中注册的id
* @param method 方法名
* @param data 方法传入参数
* @throws Exception
*/
@RequestMapping("testDubboService")
public void testDubboService(String service,String method,String data) throws Exception{
System.out.println("service---"+service);
System.out.println("method---"+method);
System.out.println("data---"+data);
Object obj=ApplicationContextUtil.getBean(service);
if(AopUtils.isJdkDynamicProxy(obj)) { //jdk代理
Field h = obj.getClass().getDeclaredField("CGLIB$CALLBACK_0");
h.setAccessible(true);
Object dynamicAdvisedInterceptor = h.get(obj);
Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
advised.setAccessible(true);
Object newObj = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
Map map=ApplicationContextUtil.getBeanDefinitions();
BeanDefinition definition=map.get(service);
String className=definition.getBeanClassName();
Class beanClass=Class.forName(className);
Method oneMethod=beanClass.getMethod(method, String.class);
oneMethod.invoke(newObj, data);//执行
} else if(AopUtils.isCglibProxy(obj)){ //cglib代理
Field h = obj.getClass().getSuperclass().getDeclaredField("h");
h.setAccessible(true);
AopProxy aopProxy = (AopProxy) h.get(obj);
Field advised = aopProxy.getClass().getDeclaredField("advised");
advised.setAccessible(true);
Object newObj = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();
Map map=ApplicationContextUtil.getBeanDefinitions();
BeanDefinition definition=map.get(service);
String className=definition.getBeanClassName();
Class beanClass=Class.forName(className);
Method oneMethod=beanClass.getMethod(method, String.class);
oneMethod.invoke(newObj, data);//执行
} else if(obj.getClass().getName().startsWith("com.alibaba.dubbo.common.bytecode.proxy")){//dubbo代理
Field handlerField=obj.getClass().getDeclaredField("handler");
handlerField.setAccessible(true);
com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler invokerInvocationHandler = (com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler)handlerField.get(obj);
Field invokerField=invokerInvocationHandler.getClass().getDeclaredField("invoker");
invokerField.setAccessible(true);
com.alibaba.dubbo.rpc.Invoker invoker=(com.alibaba.dubbo.rpc.Invoker)invokerField.get(invokerInvocationHandler);
Field failoverClusterInvokerField=invoker.getClass().getDeclaredField("invoker");
failoverClusterInvokerField.setAccessible(true);
FailoverClusterInvoker failoverClusterInvoker =(FailoverClusterInvoker)failoverClusterInvokerField.get(invoker);
Class failoverClusterInvokerInterfaceClass=failoverClusterInvoker.getInterface();
//Method oneMethod=failoverClusterInvokerInterfaceClass.getMethod(method, String.class);
//Object result=oneMethod.invoke(obj, data);//执行
Object[] resultArr=disposeParameter(failoverClusterInvokerInterfaceClass,method,data);
Method oneMethod=(Method)resultArr[0];
Object[] parameterArr=(Object[])resultArr[1];
Object result=oneMethod.invoke(obj, parameterArr);//执行
if(result!=null){
Class resultClass=result.getClass();
System.out.println(resultClass.getName());
}
}
}
/**
*
* @param targetClass 目标类
* @param method 方法名
* @param data 传入参数
* @return 长度为2的数组,第一个元素是要执行的Method实例,第二个元素是要方法执行的参数数组
*/
public Object[] disposeParameter(Class targetClass, String method,String data){
Object[] resultArr=new Object[2];
String[] dataArr=data.split("\n");
Method[] methodArr=targetClass.getMethods();
for(int i=0;i> iter=oneJsonObject.entrySet().iterator();
while(iter.hasNext()){//把输入第j行的信息存给第j个参数
Entry entry=iter.next();
String key=entry.getKey();
Object value=entry.getValue();
try {
Field classField=parameterClass.getDeclaredField(key);
classField.setAccessible(true);
classField.set(newInstance, value);
} catch (NoSuchFieldException e) {//找不到这个属性,再从父类中找这个属性,没有继续往上迭代,只找了上面一级
System.out.println("没有这个属性"+key);
Class superClass=parameterClass.getSuperclass();
try {
Field classField=superClass.getDeclaredField(key);
classField.setAccessible(true);
classField.set(newInstance, value);
} catch (NoSuchFieldException e1) {
System.out.println("父类也没有这个属性"+key);
} catch (SecurityException e1) {
e1.printStackTrace();
}
} catch (SecurityException e) {
e.printStackTrace();
}
}
parameterArr[j]=newInstance;
}
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
resultArr[1]=parameterArr;
break;
}
}
return resultArr;
}