demo地址:

  https://github.com/ZbLeaning/leaning

代理:

   为其他对象提供一种代理以控制对这个对象的访问。分为静态代理和动态代理。代理模式的目的就是为真实业务对象提供一个代理对象以控制对真实业务对象的访问

静态代理:

   程序运行前就已存在的编译好的代理类

动态代理:

  程序运行期间根据需要动态创建代理类及其实例已完成功能

代理对象的作用:

  1、拦截对真实业务对象的访问

  2、代理对象和真实业务对象(目标对象)实现共同的接口或继承于同一个类

  3、代理对象是对目标对象的增强,可对消息进行预处理和后处理

代理的结构:

  角色: 代理类角色(Proxy):含义对真实对象的引用,负责对真实主题角色的调用,并进行预处理和后处理

  委托类角色(被代理类,Proxied):真实主题角色,业务

  抽象主题角色(Subject):接口或抽象类

静态代理:

  程序运行前,开发者创建或特定工具自动生成源代码并对其编译生成.class文件。

  实现步骤:

    1、定义业务接口

    2、实现业务接口

    3、定义代理类并实现业务接口,最后通过客户端调用

demo:实现在代理方法前后进行预处理和后处理

CodingService:抽象主题角色,构造接口

public interface CodingService {
String debug(String name);
String unitTest(String msg);
}
CodingServiceImpl:委托类角色

public class CodingServiceImpl implements CodingService{
@Override
public String debug(String name) {
return name + "发现了bug";
} @Override
public String unitTest(String msg) {
return "unitTest Result:" + msg;
}
}
CodingServiceProxy:代理类角色

public class CodingServiceProxy implements CodingService{
private CodingService codingService; public CodingServiceProxy(CodingService codingService){
this.codingService = codingService;
} @Override
public String debug(String name) {
System.out.println("预处理...");
String result = codingService.debug(name);
System.out.println(result);
System.out.println("后处理...");
return result;
} @Override
public String unitTest(String msg) {
System.out.println("预处理...");
String result = codingService.unitTest(msg);
System.out.println(result);
System.out.println("后处理...");
return result;
}
}
CodingClient:客户端

public class CodingClient {
public static void main(String[] args) {
CodingService codingService = new CodingServiceImpl();
CodingServiceProxy codingServiceProxy = new CodingServiceProxy(codingService);
codingServiceProxy.debug("西瓜");
codingServiceProxy.unitTest("好吃呀");
}
}

  代理类可在不修改原有代码前提下新增功能。开闭原则的典型实践。aop实现原理就是代理模式

JDK动态代理:

  静态代理的特点是委托类与其代理类一一对应。当有N个委托类时,代理类中的预处理和后处理可能是相同的,只是调用主题不同。用静态代理的话就要创建N个代理类。动态代理可以简单地为各个委托类分别生成代理类,共享预处理和后处理功能,大大减小程序规模。

  在动态代理中,代理类是在运行时生成的。动态代理主要分为JDK动态代理和CgLIB动态代理 JDK动态代理相关类/接口:

  java.lang.reflect.proxy:

    该类用于动态生成代理类, 只需传入目标接口,目标接口的类加载器及invocationHandler便可为目标接口生成代理类及代理对象

// 方法 1: 该方法用于获取指定代理对象所关联的InvocationHandler
static InvocationHandler getInvocationHandler(Object proxy) // 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces) // 方法 3:该方法用于判断指定类是否是一个动态代理类
static boolean isProxyClass(Class cl) // 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces,
InvocationHandler h)

java.lang.reflect.InvocationHandler:

  该接口包含一个invoke方法,通过该方法实现对委托类的代理的访问,是代理类完整逻辑的集中体现,包括要切入的增强逻辑和进行反射执行的真实业务逻辑。

// 该方法代理类完整逻辑的集中体现。第一个参数既是代理类实例,第二个参数是被调用的方法对象,
// 第三个方法是调用参数。通常通过反射完成对具体角色业务逻辑的调用,并对其进行增强。
Object invoke(Object proxy, Method method, Object[] args)

java.lang.ClassLoader:

  类加载器类,负责将类的字节码装载到Java虚拟机中并为其定义类对象,然后该类才能被使用。Proxy静态方法生成动态代理类同样需要通过类加载器来进行加载才能使用,它与普通类的唯一区别就是其字节码是由JVM在运行时动态生成的而非预存在于任何一个.class 文件中。

JDK动态代理实现步骤:

   1、创建被代理的接口和类

public interface HelloService {
String hello(String name);
String hi(String msg);
}
public class HelloServiceImple implements HelloService{
@Override
public String hello(String name) {
return "Hello " + name;
} @Override
public String hi(String msg) {
return "Hi, " + msg;
}
}

  2、实现InvocationHandler接口,对目标接口中声明的所有方法进行统一处理

public class HelloInvocationHandler implements InvocationHandler {
//委托类对象
private Object target; public HelloInvocationHandler(Object target){
this.target = target;
}
//增强方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("PROXY : " + proxy.getClass().getName());
// 反射调用,目标方法
Object result = method.invoke(target, args);
// 增强逻辑
System.out.println(method.getName() + " : " + result);
return result;
}
}

  3、调用Proxy的静态方法,创建代理类并生成相应的代理对象

public class HelloClient {
public static void main(String[] args) {
HelloService helloService = new HelloServiceImple();
//创建代理类并生成相应代理对象
HelloService proxy = (HelloService)Proxy.newProxyInstance(HelloService.class.getClassLoader(),
helloService.getClass().getInterfaces(), new HelloInvocationHandler(helloService));
proxy.hello("rico");
proxy.hi("panda");
}
}

小结:

  1、动态代理的实现关键是反射

  2、代理对象是对目标对象的增强,以便对消息进行预处理和后处理

  3、InvocationHandler中的invoke()方法是代理类完成逻辑的体现,包括要切入的增强逻辑和进行反射执行的真实业务逻辑

  4、使用JDK动态代理,只需要指定目标接口、目标接口的类加载器及具体的InvocationHandler。

  5、JDK动态代理生成的代理类继承了Proxy类,因此JDK动态代理只能实现接口代理而不能实现类代理,Java不允许多继承,其本身生成的代理类已经继承了Proxy类

  6、JDK动态代理生成的代理类也代理了三个Object类的方法:equals()、hashCode()、toString()

静态代理与JDK动态代理的更多相关文章

  1. Java之代理(jdk静态代理,jdk动态代理,cglib动态代理,aop,aspectj)

    一.概念 代理是什么呢?举个例子,一个公司是卖摄像头的,但公司不直接跟用户打交道,而是通过代理商跟用户打交道.如果:公司接口中有一个卖产品的方法,那么公司需要实现这个方法,而代理商也必须实现这个方法. ...

  2. 从静态代理,jdk动态代理到cglib动态代理-一文搞懂代理模式

    从代理模式到动态代理 代理模式是一种理论上非常简单,但是各种地方的实现往往却非常复杂.本文将从代理模式的基本概念出发,探讨代理模式在java领域的应用与实现.读完本文你将get到以下几点: 为什么需要 ...

  3. Java代理(静态代理、JDK动态代理、CGLIB动态代理)

    Java中代理有静态代理和动态代理.静态代理的代理关系在编译时就确定了,而动态代理的代理关系是在运行期确定的.静态代理实现简单,适合于代理类较少且确定的情况,而动态代理则给我们提供了更大的灵活性. J ...

  4. 代理模式详解:静态代理、JDK动态代理与Cglib动态代理

    代理模式简介分类 概念 ​ 代理,是为了在不修改目标对象的基础上,增强目标方法的业务逻辑. ​ 客户类需要执行的是目标对象的目标方法,但是真正执行的是代理对象的代理方法,客户类对目标对象的访问是通过代 ...

  5. 静态代理和利用反射形成的动态代理(JDK动态代理)

    代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...

  6. 017 Java中的静态代理、JDK动态代理、cglib动态代理

    一.静态代理 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由业务实现类.业务代理类两部分组成.业务实现类负责实现主要的业务方法,业 ...

  7. 代理模式(静态代理、JDK动态代理原理分析、CGLIB动态代理)

    代理模式 代理模式是设计模式之一,为一个对象提供一个替身或者占位符以控制对这个对象的访问,它给目标对象提供一个代理对象,由代理对象控制对目标对象的访问. 那么为什么要使用代理模式呢? 1.隔离,客户端 ...

  8. 代理模式 静态代理、JDK动态代理、Cglib动态代理

    1 代理模式 使用代理模式时必须让代理类和被代理类实现相同的接口: 客户端通过代理类对象来调用被代理对象方法时,代理类对象会将所有方法的调用分派到被代理对象上进行反射执行: 在分派的过程中还可以添加前 ...

  9. java静态代理和JDK动态代理

    静态代理 编译阶段就生产了对应的代理类 public interface IBussiness { void execute(); } public class BussinessImpl imple ...

随机推荐

  1. Docker 网络之理解 bridge 驱动

    笔者在前文<Docker 网络之进阶篇>中介绍了 CNM(Container Network Model),并演示了 bridge 驱动下的 CNM 使用方式.为了深入理解 CNM 及最常 ...

  2. Perl一行式:选择行输出、删除、追加、插入

    perl一行式程序系列文章:Perl一行式 对于Perl的一行式perl程序来说,选择要输出的.要删除的.要插入/追加的行是非常容易的事情,因为print/say决定行是否输出/插入/追加/删除.虽然 ...

  3. MyBatis动态代理执行原理

    前言 大家使用MyBatis都知道,不管是单独使用还是和Spring集成,我们都是使用接口定义的方式声明数据库的增删改查方法.那么我们只声明一个接口,MyBatis是如何帮我们来实现SQL呢,对吗,我 ...

  4. C# 如何添加Excel页眉页脚(图片、文字、奇偶页不同)

    简介 我们可以通过代码编程来对Excel工作表实现很多操作,在下面的示例中,将介绍如何来添加Excel页眉.页脚.在页眉处,我们可以添加文字,如公司名称.页码.工作表名.日期等,也可以添加图片,如LO ...

  5. python学习笔记(十 三)、网络编程

    最近心情有点儿浮躁,难以静下心来 Python提供了强大的网络编程支持,很多库实现了常见的网络协议以及基于这些协议的抽象层,让你能够专注于程序的逻辑,而无需关心通过线路来传输比特的问题. 1 几个网络 ...

  6. Java开发笔记(四十六)类的构造方法

    前面介绍了如何定义一个简单的类,以及它的成员属性和成员方法,从示例代码可以看到,不管是OrangeSimple还是OrangeMember,都要先利用关键字new创建一个实例,然后才能通过实例名称访问 ...

  7. jquery实现ajax提交表单的方法总结

    方法一: 分别获取所需数据元素,DOM结构外层不用包form标签(适用于数据量少,数据元素分散于整个页面) $.ajax({ type: 'POST', url:'', data: { residen ...

  8. Dynamics 365-Full Text Index on Stopwords

    之前写了一篇关于Online Relevance Search的博文,然后又看到罗勇大神关于Full Text Index的博文:Dynamics CRM中一个查找字段引发的[血案],于是准备写点关于 ...

  9. FocusListener焦点监听器

    [FocusListener焦点监听器] public class Demo extends JFrame { public Demo(){ setDefaultCloseOperation(Wind ...

  10. Android冷启动优化

    我们知道新打开一个应用的时候,会出现短暂的白屏或者黑屏,严重影响到我们的用户体验,其实这个过程是launcher启动新进程,进程中启动activity时,会先绑定window,然后使用默认的windo ...