对于每一个Java开发来说,代理这个词或多或少都会听说过。你可能听到过的有代理模式、动态代理、反向代理等。那么,到底什么是代理,这么多代理又有什么区别呢。本文就来简要分析一下。

代理技术,其实不只是Java语言特有的技术,其实在互联网早期就已经出现了这种技术。

在计算机网络层面,常用的代理技术有:正向代理、反向代理和透明代理。最常用到的就是正向代理和反向代理。

正向代理和反向代理

正向代理

正向代理(forward proxy):是一个位于客户端和目标服务器之间的服务器(代理服务器),为了从目标服务器取得内容,客户端向代理服务器发送一个请求并指定目标,然后代理服务器向目标服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的配置才能使用正向代理。一般情况下,如果没有特别说明,代理技术默认是指正向代理技术。

这种代理其实在生活中是比较常见的,比如科学上网技术,其用到的就是代理技术。

小明想要访问某国外网站,该网站无法在国内直接访问,但是小明可以访问到一个代理服务器,这个代理服务器可以访问到这个国外网站。这样呢,小明对该国外网站的访问就需要通过代理服务器来转发请求,并且该代理服务器也会将请求的响应再返回给小明。这个上网的过程就是用到了正向代理。

在通过正向代理服务器的时候,目标服务器是不知道真正的客户端是谁的,只知道是代理服务器在发送请求。

正向代理的用途

突破访问限制 通过代理服务器,可以突破自身IP访问限制,访问国外网站,教育网等。

最近一些年,随着VPN技术的不断发展,一般的突破访问限制都是通过VPN来实现的,如果你仔细了解一下VPN的话,你会发现,其实VPN也是正向代理的一种实现,其本质上也是一个代理服务器。

提高访问速度 通常代理服务器都设置一个较大的硬盘缓冲区,会将部分请求的响应保存到缓冲区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。

隐藏客户端真实IP 上网者也可以通过这种方法隐藏自己的IP,免受攻击。

反向代理

反向代理(reverse proxy):是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。

对于常用的场景,就是我们在Web开发中用到的负载均衡服务器,客户端发送请求到负载均衡服务器上,负载均衡服务器再把请求转发给一台真正的服务器来执行,再把执行结果返回给客户端。

前面我们说过,通过正向代理服务器访问目标服务器,目标服务器是不知道真正的客户端是谁的,甚至不知道访问自己的是一个代理。而通过反向代理服务器访问目标服务器时,客户端是不知道真正的目标服务器是谁的,甚至不知道自己访问的是一个代理。这也是正向代理和反向代理的区别。

反向代理的用途

隐藏服务器真实IP 使用反向代理,可以对客户端隐藏服务器的IP地址。

负载均衡 反向代理服务器可以做负载均衡,根据所有真实服务器的负载情况,将客户端请求分发到不同的真实服务器上。

提高访问速度 反向代理服务器可以对于静态内容及短时间内有大量访问请求的动态内容提供缓存服务,提高访问速度。

提供安全保障 反向代理服务器可以作为应用层防火墙,为网站提供对基于Web的攻击行为(例如DoS/DDoS)的防护,更容易排查恶意软件等。还可以为后端服务器统一提供加密和SSL加速(如SSL终端代理),提供HTTP访问认证等。

静态代理和动态代理

前面介绍的是计算机网络层的代理机制,一般指的是服务请求的代理。在Java的日常开发中还会接触到另外一种代理,或者说叫做代理模式。

在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。

通过引入一个新的对象来实现对真实对象的操作或者将新的对象作为真实对象的一个替身,这种实现机制即为代理模式,通过引入代理对象来间接访问一个对象,这就是代理模式的模式动机。

代理模式(Proxy Pattern) :给某一个对象提供一个代理,并由代理对象控制对原对象的引用。

按照代理类的创建时期,代理类可分为两种,即动态代理类和静态代理类。就是我们经常提到的静态代理和动态代理中主要用到的类。

所以,静态代理和动态代理的主要区别就是代理类创建的时间不同。

静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

动态代理类:在程序运行时,运用反射机制动态创建而成。

静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。

Java中的静态代理

所谓静态代理,就是代理类是由程序员自己编写的,在编译期就确定好了的。来看下下面的例子:

public interface HelloSerivice {
public void say();
} public class HelloSeriviceImpl implements HelloSerivice{ @Override
public void say() {
System.out.println("hello world");
}
}
复制代码

上面的代码比较简单,定义了一个接口和其实现类。这就是代理模式中的目标对象目标对象的接口。接下类定义代理对象。

public class HelloSeriviceProxy implements HelloSerivice{

    private HelloSerivice target;
public HelloSeriviceProxy(HelloSerivice target) {
this.target = target;
} @Override
public void say() {
System.out.println("记录日志");
target.say();
System.out.println("清理数据");
}
}
复制代码

上面就是一个代理类,他也实现了目标对象的接口,并且扩展了say方法。下面是一个测试类:

public class Main {
@Test
public void testProxy(){
//目标对象
HelloSerivice target = new HelloSeriviceImpl();
//代理对象
HelloSeriviceProxy proxy = new HelloSeriviceProxy(target);
proxy.say();
}
} // 记录日志
// hello world
// 清理数据
复制代码

这就是一个简单的静态的代理模式的实现。代理模式中的所有角色(代理对象、目标对象、目标对象的接口)等都是在编译期就确定好的。

静态代理的用途

控制真实对象的访问权限 通过代理对象控制对真实对象的使用权限。

避免创建大对象 通过使用一个代理小对象来代表一个真实的大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。

增强真实对象的功能 这个比较简单,通过代理可以在调用真实对象的方法的前后增加额外功能。

动态代理

前面介绍了静态代理,虽然静态代理模式很好用,但是静态代理还是存在一些局限性的,比如使用静态代理模式需要程序员手写很多代码,这个过程是比较浪费时间和精力的。一旦需要代理的类中方法比较多,或者需要同时代理多个对象的时候,这无疑会增加很大的复杂度。

有没有一种方法,可以不需要程序员自己手写代理类呢。这就是动态代理啦。

动态代理中的代理类并不要求在编译期就确定,而是可以在运行期动态生成,从而实现对目标对象的代理功能。

Java中,实现动态代理有两种方式:

1、JDK动态代理:java.lang.reflect 包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。

2、Cglib动态代理:Cglib (Code Generation Library )是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。

关于这两种动态代理的写法本文就不深入展开了,读者感兴趣的话,后面我再写文章单独介绍。本文主要来简单说一下这两种动态代理的区别和用途。

JDK动态代理和Cglib动态代理的区别

JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。

Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。

Cglib包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它需要你对JVM内部结构包括class文件的格式和指令集都很熟悉。

Cglib与动态代理最大的区别就是:

使用动态代理的对象必须实现一个或多个接口

使用cglib代理的对象则无需实现接口,达到代理类无侵入。

动态代理的用途

Java的动态代理,在日常开发中可能并不经常使用,但是并不代表他不重要。Java的动态代理的最主要的用途就是应用在各种框架中。因为使用动态代理可以很方便的运行期生成代理类,通过代理类可以做很多事情,比如AOP,比如过滤器、拦截器等。

在我们平时使用的框架中,像servlet的filter、包括spring提供的aop以及struts2的拦截器都使用了动态代理功能。我们日常看到的mybatis分页插件,以及日志拦截、事务拦截、权限拦截这些几乎全部由动态代理的身影。

总结

本文为你介绍了网络层面的正向代理和反向代理、开发模式层面的静态代理和动态代理。希望通过阅读本文,你会对代理技术有一定的了解。当然,这些概念也不要搞混哦。

所有和Java中代理有关的知识点都在这了。的更多相关文章

  1. 关于Java中的String类知识点小总结

    Java中的String类知识点 前言 在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串. 如何创建字符串 最简单的方式 String str = "he ...

  2. 理论篇-Java中一些零碎的知识点

    1. Java中length,length方法,size方法区别 length属性:用于获取数组长度. length方法:用于获取字符串长度. size方法:用于获取泛型集合有多少个元素. 2. is ...

  3. Java中代理对象的使用小结

    在某些情况下,一个客户不想或不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到了中介作用,这不仅仅使用代理模式,还可以实现适配器模式.装饰模式等. 代理对象内部含有对真实对象的引用,从而 ...

  4. JAVA中代理模式

    代理模式 在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用.代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能 ...

  5. Java中代理

    普通代理(最简单的代理) 需要有两个实现同一个接口的类,一个是被代理的类,一个是代理类 被代理类中我们按照自己想实现的功能重写接口中的方法 代理类中因为需要代理被代理类,所以在代理类中需要有个被代理类 ...

  6. java中代理,静态代理,动态代理以及spring aop代理方式,实现原理统一汇总

    若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. ...

  7. Java中多线程并发体系知识点汇总

    一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种 ...

  8. java中的字符流知识点总结

    java中字符流 字符流:对文本的读取,速度比字节流快 常见的字符流:Reader 和 Writer Reader是InputStreamReader的父类,InputStreamReader是Fil ...

  9. java中判断一个字符串是否“都为数字”和“是否包含数字”和“截取数字”

    在javascript中有一个方法isDigit()使用来判断一个字符串是否都是数字,在java的字符串处理方法中没有这样的方法,觉得常常需要用到,于是上网搜了一下,整理出了两个用正则表达式匹配的判断 ...

随机推荐

  1. Debian 7 amd64 + fbterm + ucimf

    前段时间,显示器出了问题,导致Debian下只有终端显示正常,桌面显示效果很是摇晃模糊.遂起了念头,能不能在终端下就能完成日常的工作. google了很久,终于知道fbterm可以在终端下显示中文,加 ...

  2. OSG学习:位置变换节点示例

    osg::PositionAttitudeTransform节点. #include <osgViewer\Viewer> #include <osg\Node> #inclu ...

  3. css那些事儿2 盒子模型

    盒子模型是网页元素所占据页面窗口的矩形范围,是网页布局的核心基础之一,这里的盒子模型与我们平常收到的包裹类似. 一个包裹从内到外,分为真实物品部分,物品与外壳之间的填充区,外壳的厚度,当多个包裹放置在 ...

  4. #Leetcode# 951. Flip Equivalent Binary Trees

    https://leetcode.com/problems/flip-equivalent-binary-trees/ For a binary tree T, we can define a fli ...

  5. 图解linux安装tomcat(附常用命令)

    本例使用的是centos6.5版本,具体内容如下 一.首先到官方下载tomcat服务 http://tomcat.apache.org/download-70.cgi 二.将tomcat上传至linu ...

  6. intellij idea 如何将一个普通项目转换为maven项目

    1.工程文件下新建文件pom.xml,并填写好内容. 2.在pom.xml 文件上右键 Add as Maven Project.

  7. SpringBoot2.0(一) mybatis

    使用mybatis springboot使用mybatis主要依赖 mybatis-spring-boot-starter 来实现.其提供了2中解决方案,一种是使用注解:另一种是简化后的传统的xml方 ...

  8. 【Python】面向对象--类的特殊成员方法

    类的特殊成员方法 1. __doc__ 表示类的描述信息 class Func(object): '''__doc__方法是用来打印类的描述信息''' def tell(self): pass def ...

  9. 【bzoj4540】[Hnoi2016]序列 单调栈+离线+扫描线+树状数组区间修改区间查询

    题目描述 给出一个序列,多次询问一个区间的所有子区间最小值之和. 输入 输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数.接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i ...

  10. BZOJ4260 Codechef REBXOR(trie)

    用trie求出前缀最大区间异或和.后缀最大区间异或和即可.注意空间是nlog的. #include<iostream> #include<cstdio> #include< ...