Java代理:静态代理、动态代理
要理解动态代理,需要先理解反射(http://www.cnblogs.com/Donnnnnn/p/7729443.html)
通俗理解:
在很多底层框架中都会用得到,比如struts,Spring等都用到了动态代理,它的作用很简单:
利用反射将你要使用的类,重新生成一个子类或本类,这样框架就可以利用这个新生成的类做一些事情,比如在该类的方法前后加一些代码。
这样的话,你想像一下,你是不是不用修改任何已经编写好的代码,只要使用代理就可以灵活的加入任何东西,将来不喜欢了,不用也不会影响原来的代码。
例子:
我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品。关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,“委托者”对我们来说是不可见的;
静态代理:
代理类在程序运行前就已经存在(通常都是我们在Java代码中定义的)
代码实例:
厂家: 委托类(被代理类)
微商代理: 代理类
通常情况下,静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。
下面我们用Vendor类代表生产厂家,BusinessAgent类代表微商代理,来介绍下静态代理的简单实现
委托类和代理类都实现了Sell接口
1、Sell接口的定义如下:
package First; public interface Sell { void sell(); void ad(); }
2、Vendor类的定义如下:
package First;
/*
* 委托类:厂家
*/
public class Vendor implements Sell{ @Override
public void sell() {
System.out.println("sell method");
} @Override
public void ad() {
System.out.println("ad method");
} }
3、代理类BusinessAgent的定义如下:
package First;
/*
* 代理类:微商
*/
public class BusinessAgent implements Sell { private Vendor vendor; public BusinessAgent(Vendor vendor) {
this.vendor = vendor;
} @Override
public void sell() {
vendor.sell();
} @Override
public void ad() {
vendor.ad();
} }
从BusinessAgent类的定义我们可以了解到,静态代理可以通过聚合来实现,让代理类持有一个委托类的引用即可。
下面我们考虑一下这个需求:
给Vendor类增加一个过滤功能,只卖货给大学生。
通过静态代理,我们无需修改Vendor类的代码就可以实现,只需在BusinessAgent类中的sell方法中添加一个判断方法即可,如下所示:
4、增加功能版BusinessAgent:
package First;
/*
* 代理类:微商
*/
public class BusinessAgent implements Sell { private Vendor vendor; public BusinessAgent(Vendor vendor) {
this.vendor = vendor;
} @Override
public void sell() {
if(isCollegeStudent()){
vendor.sell();
} } @Override
public void ad() {
vendor.ad();
} public boolean isCollegeStudent(){
//为了好理解,这里直接返回True
return true;
} }
添加一个判断是否是大学生的方法:isCollegeStudent(),只需在代理类BusinessAgent类中判断,无需修改委托类Vendor
- 优点一:可以隐藏委托类的实现;
- 优点二:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。
静态代理的局限在于运行前必须编写好代理类
动态代理:
代理类在程序运行时创建的代理方式被成为动态代理。(是不是想到了反射)
也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。
例子:
假设我们要实现这样一个需求:
在执行委托类中的方法之前输出“before”,在执行完毕后输出“after”。
我们还是以上面例子中的Vendor类作为委托类,BusinessAgent类作为代理类来进行介绍。
首先我们来使用静态代理来实现这一需求,相关代码如下:
package First;
/*
* 代理类:微商
*/
public class BusinessAgent implements Sell { //引用委托类
private Vendor vendor; public BusinessAgent(Vendor vendor) {
this.vendor = vendor;
} @Override
public void sell() {
System.out.println("before");
vendor.sell();
System.out.println("after");
} @Override
public void ad() {
System.out.println("before");
vendor.ad();
System.out.println("after");
} }
从以上代码中我们可以了解到,通过静态代理实现我们的需求需要我们在每个方法中都添加相应的逻辑,
这里只存在两个方法所以工作量还不算大,假如Sell接口中包含上百个方法呢?这时候使用静态代理就会编写许多冗余代码。
通过使用动态代理,我们可以做一个“统一指示”,从而对所有代理类的方法进行统一处理,而不用逐一修改每个方法。
下面我们来具体介绍下如何使用动态代理方式实现我们的需求:
一、使用动态代理
(1)委托类的定义
package First;
/*
* 委托类:厂家
*/
public class Vendor implements Sell{ @Override
public void sell() {
System.out.println("sell method");
} @Override
public void ad() {
System.out.println("ad method");
} }
(2)中介类(调用处理器)
中介类必须实现InvocationHandler接口,作为调用处理器”拦截“对代理类方法的调用。
InvocationHandler接口(java.lang.reflect包下)
这个接口的定义如下:
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args);
}
从InvocationHandler这个名称我们就可以知道,实现了这个接口的中介类用做“调用处理器”。
当我们调用代理类对象的方法时,这个“调用”会转送到invoke方法中,代理类对象作为proxy参数传入,参数method标识了我们具体调用的是代理类的哪个方法,args为这个方法的参数。这样一来,我们对代理类中的所有方法的调用都会变为对invoke的调用,
这样我们可以在invoke方法中添加统一的处理逻辑(也可以根据method参数对不同的代理类方法做不同的处理)。因此我们只需在中介类的invoke方法实现中输出“before”,然后调用委托类的invoke方法,再输出“after”。下面我们来一步一步具体实现它。
中介类的定义如下:
package First;
/*
* 中介类:实现类
*/
import java.lang.reflect.Method; public class DynamicProxy implements InvocationHandler{ private Object obj;//obj为委托类对象 public DynamicProxy(Object obj){
this.obj = obj;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result = method.invoke(obj, args); System.out.println("before");
return result;
} }
(3)动态生成代理类
package First;
/*
* 动态生成代理类
*/
import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { DynamicProxy inter = new DynamicProxy(new Vendor());
/*
* 1. 获取代理类实例sell (它的实现类是Vendor)
* 2. newProxyInstance方法来获取一个代理类实例
* 3. newProxyInstance(代理类的ClassLoader , 接口类Sell , 动态代理的实现类DynamicProxy)
*/
Sell sell = (Sell)(Proxy.newProxyInstance(Sell.class.getClassLoader(), new Class[] {Sell.class}, inter));
sell.sell();
sell.ad();
} }
我们运行一下,看看我们的动态代理是否能正常工作。我这里运行后的输出为:
before
sell method
after
before
ad method
after
AOP的通知也是这样实现的吧
在以上代码中,我们调用Proxy类的newProxyInstance方法来获取一个代理类实例。这个代理类实现了我们指定的接口并且会把方法调用分发到指定的调用处理器。
这个方法的声明如下:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
方法的三个参数含义分别如下:
- loader:定义了代理类的ClassLoder;
- interfaces:代理类实现的接口列表
h:调用处理器,也就是我们上面定义的实现了InvocationHandler接口的类实例 ( 即DynamicProxy类 )
参考:
http://www.jianshu.com/p/cbd58642fc08
目前还没有理解动态代理,以上只是做个笔记加深我自己的印象
Java代理:静态代理、动态代理的更多相关文章
- Java之代理(jdk静态代理,jdk动态代理,cglib动态代理,aop,aspectj)
一.概念 代理是什么呢?举个例子,一个公司是卖摄像头的,但公司不直接跟用户打交道,而是通过代理商跟用户打交道.如果:公司接口中有一个卖产品的方法,那么公司需要实现这个方法,而代理商也必须实现这个方法. ...
- Java代理(静态代理、JDK动态代理、CGLIB动态代理)
Java中代理有静态代理和动态代理.静态代理的代理关系在编译时就确定了,而动态代理的代理关系是在运行期确定的.静态代理实现简单,适合于代理类较少且确定的情况,而动态代理则给我们提供了更大的灵活性. J ...
- 静态代理和利用反射形成的动态代理(JDK动态代理)
代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...
- Java中的JDK动态代理
所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...
- Java核心技术点之动态代理
本篇博文会从代理的概念出发,介绍Java中动态代理技术的使用,并进一步探索它的实现原理.由于个人水平有限,叙述中难免出现不清晰或是不准确的地方,希望大家可以指正,谢谢大家:) 一.概述 1. 什么是代 ...
- 代理模式 & Java原生动态代理技术 & CGLib动态代理技术
第一部分.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常 ...
- Java Proxy和CGLIB动态代理原理
动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询.测试框架的后端mock.RPC,Java注解对象获取等.静态代理的代理关系在编译时就确定了,而动态代理的代理关 ...
- 静态代理与JDK动态代理
demo地址: https://github.com/ZbLeaning/leaning 代理: 为其他对象提供一种代理以控制对这个对象的访问.分为静态代理和动态代理.代理模式的目的就是为真实业务对象 ...
- (转)轻松学,Java 中的代理模式及动态代理
背景:讲到反射机制,肯定会想到动态代理. 轻松学,Java 中的代理模式及动态代理 代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强.值得注意的是,代理类和被代理类应该 ...
- Java设计模式-代理模式之动态代理(附源代码分析)
Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...
随机推荐
- Windows下使用创建多层文件夹 SHCreateDirectoryEx 函数需要注意的问题
1.在使用SHCreateDirectoryEx函数创建多层文件夹的过程中,发现在文件夹路径中,只能使用\\而不能使用/,否则将创建文件夹失败. 2.下面为在MFC中使用的代码片段 CString n ...
- jq 折面板+tab切换(自己封装的插件哦!!)
如上图所示的一个折面板效果+tab切换:最重要的js代码如下: 对于布局简单介绍下: hot_wrap_li 这个是带箭头的横条: Arrow 这个是箭头的div:hot_wrap_li_wrap 这 ...
- 移动端rem适配布局
dome如下: <!doctype html><html><head> <meta charset="UTF-8" /> <m ...
- angular2 学习笔记 (Typescript - Attribute & reflection & decorator)
更新 : 2018-11-27 { date: Date } 之前好像搞错了,这个是可以用 design:type 拿到的 { date: Date | null } 任何类型一但配上了 | 就 de ...
- 全栈性能测试修炼宝典--Jmeter实战(一)
性能测试方向职业发展 1.软件测试发展路线 我们可以暂且把软件测试职业路线分为3个方向,分别是业务路线.技术路线.管理路线:4个象限,分别为执行层.中层.中高层过渡.高层. (1)业务路线 常见业务路 ...
- 在python中使用正则表达式(二)
这一节主要学习一下compile()函数和group()方法 1. re.compile() compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,然后就可以用编译后 ...
- spring: beanutils.copyproperties将一个对象的数据塞入到另一个对象中(合并对象)
spring: beanutils.copyproperties将一个对象的数据塞入到另一个对象中(合并对象) 它的出现原因: BeanUtils提供对Java反射和自省API的包装.其主要目的是利用 ...
- English Voice of <<City of stars>>
City of stars 星光之城啊 Are you shining just for me? 你是否只愿为我闪耀 City of stars 星光之城啊 There's so much that ...
- English trip EM2-PE-1B Teacher:Patirck
PE = 演讲课 课上内容(Lesson) How are you today? 你今天怎么样? What is your name? 你的名字叫什么? What do you come from ...
- English trip M1 - AC3 Teacher:Corrine
课堂上内容 16,black,games The clothes is Only $. is lucky number in China. God give us black eyes,but we ...