获得spring的指定目标对象,执行指定方法(JDK动态代理,cglib动态代理,Dubbo-Javassist代理)
来源:互联网 发布:c语言输出double类型 编辑:程序博客网 时间:2024/06/06 01:27
在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<String, BeanDefinition> 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<String, BeanDefinition> 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<String, BeanDefinition> 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<String, BeanDefinition> 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<methodArr.length;i++){Method m=methodArr[i];if(m.getName().equals(method)&&m.getParameterTypes().length==dataArr.length){//命中方法,只校验了名字和参数数量Class[] classArr=m.getParameterTypes();//目标方法的参数列表resultArr[0]=m;Object[] parameterArr=new Object[classArr.length];//需要赋值的参数列表for(int j=0;j<classArr.length;j++){//循环目标方法的参数列表,赋值用String oneData=dataArr[j];//输入的第j行信息Class parameterClass=classArr[j];//目标方法的第j个参数try {if(parameterClass.equals(String.class)){//参数是String类型parameterArr[j]=oneData;}else{//参数是包装类型,还没有考虑int,Integer,数组等类型Object newInstance=parameterClass.newInstance();//新建目标方法第j个参数的实例JSONObject oneJsonObject=(JSONObject)JSON.parse(oneData);Iterator<Entry<String, Object>> iter=oneJsonObject.entrySet().iterator();while(iter.hasNext()){//把输入第j行的信息存给第j个参数Entry<String, Object> 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 blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}}resultArr[1]=parameterArr;break;}}return resultArr; }
- 获得spring的指定目标对象,执行指定方法(JDK动态代理,cglib动态代理,Dubbo-Javassist代理)
- java动态代理(JDK, CGLIB, Javassist)
- Java 动态代理详解(JDK 和CGLIB,Javassist,ASM)
- Java动态代理(JDK 和CGLIB,Javassist,ASM)
- 基于Spring AOP的JDK动态代理和CGLIB代理
- jdk与cglib动态代理目标对象创建对比
- 动态代理(JDK + cglib)
- CGLib&JDK动态代理
- 动态代理JDK cglib
- jdk、cglib动态代理
- 动态代理--Jdk、CGLIB
- jdk+cglib动态代理
- 动态代理:JDK动态代理和CGLIB代理的区别
- 动态代理:JDK动态代理和CGLIB代理的区别
- 动态代理:JDK动态代理和CGLIB代理的区别
- spring(AOP)静态代理、JDK动态代理、cglib实现代理
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
- Centos7改字符集
- C语言笔记之排序算法(4)
- wampserver+natapp实现内网穿透
- Socket接收字节缓冲区
- 部署Maven项目到tomcat报错:java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderLi
- 获得spring的指定目标对象,执行指定方法(JDK动态代理,cglib动态代理,Dubbo-Javassist代理)
- linux常用命令大全,linux常见命令(指令)介绍
- Servlet开发简介
- java定时删除日志
- Esp8266学习之旅② 利用GPIO开始使用按钮点亮你的“第一盏灯”。(附带demo)
- Android Studio2.0中使用离线ArcGIS Runtime Android SDK 100.1.0开发原生地图应用.docx
- 作业
- Linux-4.9.2内核在mini2440上的移植(二)——Ubuntu编译环境搭建(下)
- itk中的Cos变换