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. Spring Boot(五):Spring Boot Jpa 的使用

    在上篇文章Spring Boot(二):Web 综合开发中简单介绍了一下 Spring Boot Jpa 的基础性使用,这篇文章将更加全面的介绍 Spring Boot Jpa 常见用法以及注意事项. ...

  2. 痞子衡嵌入式:语音处理工具Jays-PySPEECH诞生记(5)- 语音识别实现(SpeechRecognition, PocketSphinx0.1.15)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是语音处理工具Jays-PySPEECH诞生之语音识别实现. 语音识别是Jays-PySPEECH的核心功能,Jays-PySPEECH借 ...

  3. Docker 安装rabbitMQ

    Docker 安装rabbitMQ docker pull rabbitmq:3.7.7-management 使用:docker images 查看所有镜像 4.根据下载的镜像创建和启动容器 doc ...

  4. SpringBoot 整合 apollo

    简介 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置管理场景 ...

  5. 【Java】数组转List常见方式的对比

    一.最常用通过 Arrays.asList(strArray) 方式,将数组转换List后,不能对List增删,只能查改,否则抛异常. 关键代码: List list = Arrays.asList( ...

  6. TiDB

    由于目前的项目把mysql换成了TiDb,所以特意来了解下tidb.其实也不能说换,由于tidb和mysql几乎完全兼容,所以我们的程序没有任何改动就完成了数据库从mysql到TiDb的转换,TiDB ...

  7. Java原型模式

    原型模式 原型模式也称克隆模式.原型模式jian ming zhi yi,就是先创造出一个原型,然后通过类似于Java中的clone方法,对对象的拷贝,克隆类似于new,但是不同于new.new创造出 ...

  8. vue2.x 时间范围 date range timepicker。只在项目中使用elementUI的date-picker

    elementUI官方案例:http://element.eleme.io/#/zh-CN/component/date-picker (1)效果图: (2)安装和引入 npm i element-u ...

  9. PHP实现开心消消乐的算法示例

    本文主要介绍了关于PHP如何实现我们大家都知道的开心消消乐的算法,分享PHP教程出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 一.需求描述:      1.在一个8*8的矩阵方格中随机 ...

  10. DAS、SAN和NAS三种存储方式

    DAS存储 DAS存储在我们生活中是非常常见的,尤其是在中小企业应用中,DAS是最主要的应用模式,存储系统被直连到应用的服务器中,在中小企业中,许多的数据应用是必须安装在直连的DAS存储器上. DAS ...