代理的实现原理是啥?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代理的实现原理是啥?相关的知识,希望对你有一定的参考价值。
参考技术A 代理服务器有很多种,大体分为三类:HTTP、FTP、SOCKS,其中又分为透明代理和不透明代理,透明代理一般是网关,为硬件过程:
(1)客户端先和代理服务器通讯,建立TCP连接,目的IP是代理服务器的IP
(2)客户端发出GET命令,GET命令中包含URL或IP地址、明文
(3)代理服务器将其中的URL转换为IP地址,可能会有DNS,将源数据包中的数据拷贝下来,去掉URL,重新组包再发出去
(4)代理服务器和真实服务器通讯,源IP是代理服务器的IP
以上就是代理的实现原理,在我们日常生活中只有在学习IT才会了解哦,我也是在黑马程序员学习之后才了解的。本回答被提问者采纳
JAVA 动态代理原理和实现
在 Java 中动态代理和代理都很常见,几乎是所有主流框架都用到过的知识。在面试中也是经常被提到的话题,于是便总结了本文。
Java动态代理的基本原理为:被代理对象需要实现某个接口(这是前提),代理对象会拦截对被代理对象的方法调用,在其中可以全然抛弃被代理对象的方法实现而完成另外的功能,也可以在被代理对象方法调用的前后增加一些额外的功能。
动态代理可以为其他对象提供一个代理以控制对某个对象的访问。
代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
JDK 动态代理
动态代理的核心其实就是代理对象的生成,即 Proxy.newProxyInstance(classLoader, proxyInterface, handler)。
让我们进入newProxyInstance方法观摩下,核心代码其实就三行。
这个方法需要三个参数:
- ClassLoader,用于加载代理类的 Loader 类,通常这个 Loader 和被代理的类是同一个 Loader 类。
- Interfaces,是要被代理的那些那些接口。
- InvocationHandler,就是用于执行除了被代理接口中方法之外的用户自定义的操作,他也是用户需要代理的最终目的。用户调用目标方法都被代理到 InvocationHandler 类中定义的唯一方法 invoke 中。
1
2
3
4
5
6
|
//获取代理类 Class cl = getProxyClass(loader, interfaces); //获取带有InvocationHandler参数的构造方法 Constructor cons = cl.getConstructor(constructorParams); //把handler传入构造方法生成实例 return (Object) cons.newInstance( new Object[] { h }); |
一个典型的动态代理创建对象过程可分为以下四个步骤:
1、通过实现InvocationHandler接口创建调用处理器
1
|
IvocationHandler handler = new InvocationHandlerImpl(...); |
2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
1
|
Class clazz = Proxy.getProxyClass(classLoader, new Class[]{...}); |
3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
1
|
Constructor constructor = clazz.getConstructor( new Class[]{InvocationHandler. class }); |
4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
1
|
Interface Proxy = (Interface)constructor.newInstance( new Object[] (handler)); |
为了简化对象创建过程,Proxy类中的newProxyInstance方法封装了2~4,只需两步即可完成代理对象的创建。
1
2
|
Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject. class .getClassLoader(), new Class[]{Subject. class }, new InvocationHandlerImpl (real)); |
生成的proxySubject继承Proxy类实现Subject接口。实现的Subject的方法实际是调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的方法(Object result=method.invoke(proxied,args));
重点Proxy.newProxyInstance,源码分析,会在其他文档中单独总结记录。类Proxy的getProxyClass方法调用ProxyGenerator的 generateProxyClass方法产生ProxySubject.class的二进制数据。
创建代理对象时序图
获取代理类
getProxyClass(loader, interfaces)方法用于获取代理类,它主要做了三件事情:
在当前类加载器的缓存里搜索是否有代理类,没有则生成代理类并缓存在本地JVM里。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// 缓存的key使用接口名称生成的List Object key = Arrays.asList(interfaceNames); synchronized (cache) { do { Object value = cache.get(key); // 缓存里保存了代理类的引用 if (value instanceof Reference) { proxyClass = (Class) ((Reference) value).get(); } if (proxyClass != null ) { // 代理类已经存在则返回 return proxyClass; } else if (value == pendingGenerationMarker) { // 如果代理类正在产生,则等待 try { cache.wait(); } catch (InterruptedException e) { } continue ; } else { //没有代理类,则标记代理准备生成 cache.put(key, pendingGenerationMarker); break ; } } while ( true ); } |
生成并加载代理类
代理类的生成主要是以下这两行代码:
1
2
3
4
|
//生成代理类的字节码文件并保存到硬盘中(默认不保存到硬盘) proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces); //使用类加载器将字节码加载到内存中 proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0 , proxyClassFile.length); |
代理类的生成过程
ProxyGenerator.generateProxyClass()方法属于sun.misc包下,Oracle并没有提供源代码,但是我们可以使用
JD-GUI这样的反编译软件打开jrelib
t.jar来一探究竟,以下是其核心代码的分析。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//添加接口中定义的方法,此时方法体为空 for ( int i = 0 ; i < this .interfaces.length; i++) { localObject1 = this .interfaces[i].getMethods(); for ( int k = 0 ; k < localObject1.length; k++) { addProxyMethod(localObject1[k], this .interfaces[i]); } } //添加一个带有InvocationHandler的构造方法 MethodInfo localMethodInfo = new MethodInfo( "<init>" , "(Ljava/lang/reflect/InvocationHandler;)V" , 1 ); //循环生成方法体代码(省略) //方法体里生成调用InvocationHandler的invoke方法代码。(此处有所省略) this .cp.getInterfaceMethodRef( "InvocationHandler" , "invoke" , "Object; Method; Object;" ) //将生成的字节码,写入硬盘,前面有个if判断,默认情况下不保存到硬盘。 localFileOutputStream = new FileOutputStream(ProxyGenerator.access$ 000 ( this .val$name) + ".class" ); localFileOutputStream.write( this .val$classFile); |
生成的代理类源码
那么通过以上分析,我们可以推出动态代理为我们生成了一个这样的代理类。把方法doSomeThing的方法体修改为调用LogInvocationHandler的invoke方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public class ProxyBusiness extends Proxy implements IBusiness, IBusiness2 { private LogInvocationHandler h; @Override public void doSomeThing2() { try { Method m = (h.target).getClass().getMethod( "doSomeThing2" , null ); h.invoke( this , m, null ); } catch (Throwable e) { // 异常处理(略) } } @Override public boolean doSomeThing() { try { Method m = (h.target).getClass().getMethod( "doSomeThing" , null ); return (Boolean) h.invoke( this , m, null ); } catch (Throwable e) { // 异常处理(略) } return false ; } public ProxyBusiness(LogInvocationHandler h) { this .h = h; } |
测试代理的代码如下:
1
2
3
4
5
6
7
|
//测试 public static void main(String[] args) { //构建AOP的Advice LogInvocationHandler handler = new LogInvocationHandler( new Business()); new ProxyBusiness(handler).doSomeThing(); new ProxyBusiness(handler).doSomeThing2(); } |
下面看一个自定义代理的实现。
被代理类接口
1
2
3
|
public interface Subject { public void doSomething(); } |
被代理类
1
2
3
4
5
6
|
//目标对象 public class RealSubject implements Subject{ public void doSomething() { System.out.println( "call doSomething()" ); } } |
调用处理器(切面)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class ProxyHandler implements InvocationHandler { private Object proxied; public ProxyHandler( Object proxied ) { this .proxied = proxied; } public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable { //在转调具体目标对象之前,可以执行一些功能处理 System.out.println( "doSomething before" ); //转调具体目标对象的方法 return method.invoke( proxied, args); //在转调具体目标对象之后,可以执行一些功能处理 System.out.println( "doSomething after" ); } } |
测试我们的代理实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public class DynamicProxy { public static void main( String args[] ) { RealSubject real = new RealSubject(); Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject. class .getClassLoader(), new Class[]{Subject. class }, new ProxyHandler(real)); proxySubject.doSomething(); //write proxySubject class binary data to file createProxyClassFile(); } public static void createProxyClassFile() { String name = "ProxySubject" ; byte [] data = ProxyGenerator.generateProxyClass( name, new Class[] { Subject. class } ); try { FileOutputStream out = new FileOutputStream( name + ".class" ); out.write( data ); out.close(); } catch ( Exception e ) { e.printStackTrace(); } } } |
运行结果:
1
2
3
|
doSomething before call doSomething() doSomething after |
Proxy 接口
Proxy 的主要静态变量
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 映射表:用于维护类装载器对象到其对应的代理类缓存 private static Map loaderToCache = new WeakHashMap(); // 标记:用于标记一个动态代理类正在被创建中 private static Object pendingGenerationMarker = new Object(); // 同步表:记录已经被创建的动态代理类类型,主要被方法 isProxyClass 进行相关的判断 private static Map proxyClasses = Collections.synchronizedMap( new WeakHashMap()); // 关联的调用处理器引用 protected InvocationHandler h; Proxy的构造方法 // 由于 Proxy 内部从不直接调用构造函数,所以 private 类型意味着禁止任何调用 private Proxy() {} // 由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用 protected Proxy(InvocationHandler h) { this .h = h;} |
ProxySubject 源码
创建的代理类 ProxySubject.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
import java.lang.reflect.*; public final class ProxySubject extends Proxy implements Subject{ private static Method m1; private static Method m0; private static Method m3; private static Method m2; public ProxySubject(InvocationHandler invocationhandler){ super (invocationhandler); } public final boolean equals(Object obj){ try { return ((Boolean) super .h.invoke( this , m1, new Object[] { obj })).booleanValue(); } catch (Error _ex) { } catch (Throwable throwable){ throw new UndeclaredThrowableException(throwable); } } public final int hashCode() { try { return ((Integer) super .h.invoke( this , m0, null )).intValue(); } catch (Error _ex) { } catch (Throwable throwable){ throw new UndeclaredThrowableException(throwable); } } /*关键部分*/ public final void doSomething() { try { // Proxy类中protected InvocationHandler h;关联的调用处理器引用 super .h.invoke( this , m3, null ); return ; } catch (Error _ex) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final String toString() { try { return (String) super .h.invoke( this , m2, null ); } catch (Error _ex) { } catch (Throwable throwable){ throw new UndeclaredThrowableException(throwable); } } static { try { m1 = Class.forName( "java.lang.Object" ).getMethod( "equals" , new Class[] { Class.forName( "java.lang.Object" ) }); m0 = Class.forName( "java.lang.Object" ).getMethod( "hashCode" , new Class[ 0 ]); m3 = Class.forName( "Subject" ).getMethod( "doSomething" , new Class[ 0 ]); m2 = Class.forName( "java.lang.Object" ).getMethod( "toString" , new Class[ 0 ]); } catch (NoSuchMethodException nosuchmethodexception) { throw new NoSuchMethodError(nosuchmethodexception.getMessage()); } catch (ClassNotFoundException classnotfoundexception){ throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } } |
CGLib 动态代理
动态字节码生成。使用动态字节码生成技术实现AOP原理是在运行期间目标字节码加载后,生成目标类的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要基于接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public static void main(String[] args) { byteCodeGe(); } public static void byteCodeGe() { //创建一个织入器 Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(Business. class ); //设置需要织入的逻辑 enhancer.setCallback( new LogIntercept()); //使用织入器创建子类 IBusiness2 newBusiness = (IBusiness2) enhancer.create(); newBusiness.doSomeThing2(); } /** * 记录日志 */ public static class LogIntercept implements MethodInterceptor { @Override public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable { //执行原有逻辑,注意这里是invokeSuper Object rev = proxy.invokeSuper(target, args); //执行织入的日志 if (method.getName().equals( "doSomeThing2" )) { System.out.println( "记录日志" ); } return rev; } } |
转自:https://www.xttblog.com/?p=2732
以上是关于代理的实现原理是啥?的主要内容,如果未能解决你的问题,请参考以下文章