代理模式:给某一个对象提供代理对象,由代理对象控制具体对象的引用。

代理,指的就是一个角色对表另一个角色采取行动,就生活中,一个红酒厂商,是不会直接把红酒零销给客户的,都是通过代理完成他的销售业务。而客户也不会为了喝红酒到处去找厂商,他只要找到厂商当地的代理就行了,具体红酒厂商在哪里,客户不用关系,代理会帮忙处理好。

代理模式涉及到的角色:

1:抽象主题角色,声明了代理主题和真实主题的公共接口,使用任何需要真实主题的地方都可以使用代理主题。

2:代理主题角色,含有真实主题的引用,从而可以在任何时候操作真实主题,代理主题提供和真实主题相同的接口,使他可以随时替代真实主题,代理主题持有真实主题的引用,不但可以控制真实主题的创建、删除,还可以在真实主题被调用之前就行拦截,或调用之后进行某些处理操作。

3:真实代理对象,定义了代理角色所代表的具体对象。

下面是代理模式的实现类图

根据上图的关系,我们可以根据客户买红酒模拟代理模式的实现。

/**
*
*抽象主题角色,定义真实角色和代理角色的公共接口
*
*/
public interface SellInterface { public Object sell();
}

接着我们定义真实主题角色(这里就是红酒工厂),它必须实现SellInterface接口。

/**
*
* 真实主题角色,这里指红酒工厂角色,它实现了抽象主题角色SellInterface接口
*
*/
public class RedWineFactory implements SellInterface { public Object sell() {
return null;
} }

下面是代理主题角色(这里指红酒代理商),同样它必须实现SellInterface接口。

/**
*
* 代理主题角色,这里指红酒代理商,它必须实现SellInterface接口,还持有红酒厂商
* RedWineFactory对象的引用,从而使它能在调用真实主题前后做一些必要的处理。
*
*/
public class RedWineProxy implements SellInterface { //持有一个RedWineFactory的引用
private RedWineFactory redWineFactory; //销售总量
private static int sell_count=0; public Object sell() {
if (checkUser()) {//在通过代理主题角色,我们可在真实主题角色被调用之前做一些诸如权限判断的事情 Object obj=redWineFactory.sell(); sell_count++;//同样在调用之后可以执行一些额外的操作。 return obj;
}else {
throw new RuntimeException();
} } protected boolean checkUser() {
//do something return true;
}
}

接下来我们看看调用代理对象的代码

public static void main(String[] args) {
SellInterface sell=new RedWineProxy(); sell.sell();
}

从上面例子可以看出代理模式的工作方式,因为代理主题和真实主题都实现了共同的接口,这可以使不改变原来接口的情况下,只要用真实主题对象的地方,都可以用代理主题来替代,其次代理主题在客户和真实主题之间起一个中间介作用,利用这个中介平台,我们可以在客户把请求传给真实主题前,做一些必要的预处理。

Java对代理模式的支持,动态代理

上面的代理,我们强迫代理类实现抽象接口,这导致我们的代理无法通用雨其它接口,而Java通过Proxy类和InvocationHandler接口可以解决这问题。

/**
* 代理一定要实现InvocationHandler接口
*
*/
public class ProxyObject implements InvocationHandler { private Object proxy_obj; public ProxyObject(Object obj) { this.proxy_obj=obj;
} public static Object factory(Object obj){
Class cls =obj.getClass(); //通过Proxy类的newProxyInstance方法返回代理对象。
return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), new ProxyObject(obj));
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("函数调用之前被拦截了:"+method); if (args!=null) {
//打印参数列表
System.out.println("方法有:"+args.length+"个参数。。。。。"); for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
//利用反射机制动态调用原对象的方法。
Object mo=method.invoke(proxy_obj, args); System.out.println("函数调用之后进行处理:"+method); return mo;
} //测试代码
public static void main(String[] args) {
SellInterface sell=(SellInterface) factory(new RedWineFactory());
sell.sell();
} }

通过上面的代码可以看出,代理主题ProxyObjce类并没有实现我们定义的SellInterface接口,而是实现了Java的InvocationHandler接口,这样就把代理主题角色和我们的业务代码分离来,使代理对象能通用于其他接口,其实InvocationHandler接口就是一种拦截机制,当系统中有了代理对象以后,对原对象方法的调用,都会由InvocationHandler接口来处理,并把方法信息以参数的形式传递给invoke方法,这样,我们就可以在invoke方法中拦截原对象的调用,并用过反射机制来动态调用原对象的方法,这好像也是spring aop编程的基础吧。

Java动态代理,cglib动态代理的应用

JDK的动态代理用起来非常简单,但是它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类可以使用CGLIB包。

CGLIB是一个强大的高性能的代码生成包。它被许多AOP的框架(例如Spring AOP)使用,为他们提供方法的interception(拦截)。Hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联。EasyMock通过使用模仿(moke)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理

/**
*
* 这是没有实现接口的实现类。
*
*/
public class RedWineFactoryCglib { public Object sell(String str) {
return null;
}
}
/**
* 使用cglib动态代理
*/
public class ProxyObjectCglib implements MethodInterceptor { private Object target; /**
* 创建代理对象
* @return
*/
public Object getInstance(Object target){
this.target=target; Enhancer enhancer =new Enhancer(); enhancer.setSuperclass(this.target.getClass()); //回调方法
enhancer.setCallback(this);
//创建代理对象
return enhancer.create();
} /**
* 回调方法
*/
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable { System.out.println("函数调用之前被拦截了:"+method); if (args!=null) {
//打印参数列表
System.out.println("方法有:"+args.length+"个参数。。。。。"); for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
} proxy.invokeSuper(obj, args); System.out.println("函数调用之后进行处理:"+method); return null;
} public static void main(String[] args) {
ProxyObjectCglib cglib =new ProxyObjectCglib();
RedWineFactoryCglib sell=(RedWineFactoryCglib) cglib.getInstance(new RedWineFactoryCglib());
sell.sell("123");
}
}

Proxy Pattern(Java动态代理和cglib的实现)的更多相关文章

  1. Spring中AOP的两种代理方式(Java动态代理和CGLIB代理)

    第一种代理即Java的动态代理方式上一篇已经分析,在这里不再介绍,现在我们先来了解下GCLIB代理是什么?它又是怎样实现的?和Java动态代理有什么区别? cglib(Code Generation ...

  2. Java动态代理和CGLib代理

    本文参考 在上一篇"Netty + Spring + ZooKeeper搭建轻量级RPC框架"文章中涉及到了Java动态代理和CGLib代理,在这篇文章中对这两种代理方式做详解 下 ...

  3. Spring中AOP的两种代理方式(Java动态代理和CGLIB代理-转载

    内容是摘抄的,不知最初的原作者,见谅 Java 动态代理.具体有如下四步骤: 通过实现 InvocationHandler 接口创建自己的调用处理器: 通过为 Proxy 类指定 ClassLoade ...

  4. java动态代理和cglib

    1.代理类可以分为两种. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. 动态代理:在程序运行时,运用反射机制动态创建而成. 2.JD ...

  5. java面试-java动态代理和cglib代理

      代理模式就是为了提供额外或不同的操作,而插入的用来替代实际对象的对象,这些操作涉及到与实际对象的通信,因此代理通常充当中间人角色 一.java动态代理   java动态代理可以动态地创建代理并动态 ...

  6. java反射 java动态代理和cglib动态代理的区别

    java反射      https://blog.csdn.net/f2764052703/article/details/89311013 java 动态代理   https://blog.csdn ...

  7. java动态代理和cglib动态代理

    动态代理应用广泛,Spring,Struts等框架很多功能是通过动态代理,或者进一步封装来实现的. 常见的动态代理模式实现有Java API提供的动态代理和第三方开源类库CGLIB动态代理. Java ...

  8. JAVA高级架构师基础功:Spring中AOP的两种代理方式:动态代理和CGLIB详解

    在spring框架中使用了两种代理方式: 1.JDK自带的动态代理. 2.Spring框架自己提供的CGLIB的方式. 这两种也是Spring框架核心AOP的基础. 在详细讲解上述提到的动态代理和CG ...

  9. Java三种代理模式:静态代理、动态代理和cglib代理

    一.代理模式介绍 代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能. 简言之,代理模式就是 ...

随机推荐

  1. FruitFrolic

    这是一个连连看小游戏,以 Unity2D 开发.因用了数种水果图片来做头像,所以游戏取名 FruitFrolic.同样,它也只是我闲时的练手. 少时曾玩过掌上游戏机里的俄罗斯方块及打飞机,及手机上的推 ...

  2. JavaScript 跳坑指南

    JavaScript 跳坑指南 坑0-String replace string的replace方法我们经常用,替换string中的某些字符,语法像这样子 string.replace(subStr/ ...

  3. 微信小程序开发感受

    研究了大概有一个多星期的小程序了,说一下感受,之后会随时更新,一边学习,一边加上一部分学习代码和心得.我是一个前端厂里的新手,搬砖的时间不是很长,所以到一部分知识的理解浅之又浅,所以只能说自己的理解, ...

  4. Boost学习笔记(六) progress_display注意事项

    progress_display可以用作基本的进度显示,但它有个固有的缺陷:无法把进度显示输出与程序的输出分离. 这是因为progress_display和所有C++程序一样,都向标准输出(cout) ...

  5. 1. ReactNative 基础

    /** 1. reactNative  反应式语言 2. 既拥有原生的用户体验,又保留React的开发效率 3. FaceBook研究 H5,Android,iOS 4. BAT的插件化,热修改  2 ...

  6. d3.js读书笔记-1

    d3.js入门 d3入门 D3是一个强大的数据可视化工具,它是基于Javascript库的,用于创建数据可视化图形.在生成可视化图形的过程中,需要以下几步: 把数据加载到浏览器的内存空间: 把数据绑定 ...

  7. 修改客户端连接的服务器IP地址(内部使用)

    登录系统时如果出现 “验证失败”,或者,无法登陆系统,请修改服务器端IP地址,修改方法如下: 注意: (1)修改服务器端IP地址时,要提前关闭/退出客户端.建议也看看“Windows的任务管理器”中是 ...

  8. final finally finalize

    final  //如果不是final 的话,我可以在checkInt方法内部把i的值改变(有意或无意的,       //虽然不会改变实际调用处的值),特别是无意的,可能会引用一些难以发现的BUG   ...

  9. MySQL索引原理及慢查询优化 转载

    原文地址: http://tech.meituan.com/mysql-index.html MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能 ...

  10. sublime text 3插件

    Package Control Messages Emmet emmet插件 Thank you for installing Emmet -- a toolkit that can greatly ...