jdk动态代理源码分析(一)---代理的定义

最近在看rpc的实现原理,发现大部分通用的rpc框架在实现远程调用的时候,都是通过java动态代理封装好了通信细节,让用户可以像调用本地服务一样调用远程服务。但是关于java动态代理有两个问题想不通:jdk动态代理中的invoke方法是如何被自动调用的?jdk动态代理为什么只针对实现了接口的类?带着这两个问题,我仔细读了下源码。
代理的基本定义
代理模式定义:给某个原对象提供一个接口实现类(代理类),客户端不直接访问这个对象,而是通过代理类来间接访问。
代理模式涉及到了四个对象:
Client:服务调用方,通过代理类调用真实服务(serviceImpl)。
IService:功能接口类,类中包含了功能点的抽象。是serviceImpl 和 Proxy都要去实现的接口。
ServiceImpl:功能接口的具体实现类。
Proxy:代理类。其中包含了对功能时间类(ServiceImpl)的引用,从而可以操作真实服务接口。并且可以在调用真实服务处的前后进行一系列其他操作。
对象之间关系为:
 

 

 
代理的分类与使用
   java代理主要分为静态代理和动态代理两类。
  1、静态代理:所谓静态是指,在程序运行前已经写好并编译成了.class文件,而不是动态产生的。
   静态代理使用方式为手动实现一个继承了IService接口类的代理类Proxy。并在Proxy代理类中手动引用ServiceImpl 功能接口的具体实现类。
  代码:
  
package com.xiaosong.proxy.demo.service;

/**
 * Hello world!
 *
 */
public interface IHello {
	
	public void sayHello();
	
}

  

package com.xiaosong.proxy.demo.service.impl;

import com.xiaosong.proxy.demo.service.IHello;

public class Hello implements IHello {

	public void sayHello() {
		// TODO Auto-generated method stub
		System.out.println("Hello KuGou!");
	}
}

  

package com.xiaosong.proxy.demo.jdkproxy;

import com.xiaosong.proxy.demo.service.IHello;
import com.xiaosong.proxy.demo.service.impl.Hello;

public class StaticProxy implements IHello{

	public Hello hello;
	public StaticProxy (Hello hello){
		this.hello=hello;
	}
	
	public void sayHello() {
		
		System.out.println("before Hello...");
		hello.sayHello();
		System.out.println("after Hello...");
	
	}

}

  

  2、动态代理:所谓动态是指,不在代码编译期确定被加载的类,而是在代码运行期通过反射的方式来加载。这就是和静态编译最根本的区别。
       动态代理的使用方式分为3步:
      (1)写一个 InvocationHandler接口的实现类实现invoke方法,并在这个实现类中引用一个Object对象(该对象在运行期可能被赋值为各种各样的ServiceImpl 接口实现类对 
        象),在invoke方法通过反射调用Object对象中的方法。
      (2)调用Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this) 方法,object为1中实现类的对象,获取一个代理类Proxy。
      (3)将(2)中获取到的Object对象强转为IService类,并调用IService中的方法,就可以实现对ServiceImpl 的调用了。
    
package com.xiaosong.proxy.demo.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyInvocationHandler implements InvocationHandler {

	//代理目标对象
	public Object object;
	
	public MyInvocationHandler(Object object) {
		// TODO Auto-generated constructor stub
		this.object=object;
	}
	
	//获取代理对象工具方法
	public Object getProxyObject(){

		//object.getClass().getClassLoader()确保类加载器为代理目标的加载器
		return Proxy.newProxyInstance(object.getClass().getClassLoader(), 
									  object.getClass().getInterfaces(), 
									  this);
	}
	
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		System.out.println("前置方法...");
		
		//这里入参要是object,不能是proxy,否则造成死循环,后续会详细分析原因
		Object rs = method.invoke(object, args);
		
		System.out.println("后置方法...");
		
		return rs;
	}

}

  

相对于静态代理,动态代理有以下几个优点:
1、动态代理的代码量不会随着接口的增加而无限制的扩大。
2、由于代理类是固定通用的,所以动态代理可以有更多的用途,比如spring AOP,比如RPC远程调用。
 
缺点是什么呢?
上述的静态代理和动态代理的实现都是依赖接口的,如果需要代理一个没有实现接口的方法,JDK静态代理就无计可施了。那么问题来了,为什么JDK动态代理必须是依赖接口呢?我们继续往下看。
 
posted @ 2018-01-18 20:28  蓬莱海边的小虾米  阅读(122)  评论(0编辑  收藏  举报