获得spring的指定目标对象,执行指定方法(JDK动态代理,cglib动态代理,Dubbo-Javassist代理)

63 篇文章 11 订阅

在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 block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			resultArr[1]=parameterArr;
			break;
		}
	}
	return resultArr;
   }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值