静态代理与JDK动态代理
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动态代理的更多相关文章
- Java之代理(jdk静态代理,jdk动态代理,cglib动态代理,aop,aspectj)
一.概念 代理是什么呢?举个例子,一个公司是卖摄像头的,但公司不直接跟用户打交道,而是通过代理商跟用户打交道.如果:公司接口中有一个卖产品的方法,那么公司需要实现这个方法,而代理商也必须实现这个方法. ...
- 从静态代理,jdk动态代理到cglib动态代理-一文搞懂代理模式
从代理模式到动态代理 代理模式是一种理论上非常简单,但是各种地方的实现往往却非常复杂.本文将从代理模式的基本概念出发,探讨代理模式在java领域的应用与实现.读完本文你将get到以下几点: 为什么需要 ...
- Java代理(静态代理、JDK动态代理、CGLIB动态代理)
Java中代理有静态代理和动态代理.静态代理的代理关系在编译时就确定了,而动态代理的代理关系是在运行期确定的.静态代理实现简单,适合于代理类较少且确定的情况,而动态代理则给我们提供了更大的灵活性. J ...
- 代理模式详解:静态代理、JDK动态代理与Cglib动态代理
代理模式简介分类 概念 代理,是为了在不修改目标对象的基础上,增强目标方法的业务逻辑. 客户类需要执行的是目标对象的目标方法,但是真正执行的是代理对象的代理方法,客户类对目标对象的访问是通过代 ...
- 静态代理和利用反射形成的动态代理(JDK动态代理)
代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...
- 017 Java中的静态代理、JDK动态代理、cglib动态代理
一.静态代理 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由业务实现类.业务代理类两部分组成.业务实现类负责实现主要的业务方法,业 ...
- 代理模式(静态代理、JDK动态代理原理分析、CGLIB动态代理)
代理模式 代理模式是设计模式之一,为一个对象提供一个替身或者占位符以控制对这个对象的访问,它给目标对象提供一个代理对象,由代理对象控制对目标对象的访问. 那么为什么要使用代理模式呢? 1.隔离,客户端 ...
- 代理模式 静态代理、JDK动态代理、Cglib动态代理
1 代理模式 使用代理模式时必须让代理类和被代理类实现相同的接口: 客户端通过代理类对象来调用被代理对象方法时,代理类对象会将所有方法的调用分派到被代理对象上进行反射执行: 在分派的过程中还可以添加前 ...
- java静态代理和JDK动态代理
静态代理 编译阶段就生产了对应的代理类 public interface IBussiness { void execute(); } public class BussinessImpl imple ...
随机推荐
- <meta> 标签 和<title> 标签
<meta> 标签 主流浏览器都支持 <meta> 标签. 标签定义及使用说明 元数据(Metadata)是数据的数据信息. <meta> 标签提供了 HTML 文 ...
- Mysql 主键如何实现持久化
自增主键没有持久化是个比较早的bug,这点从其在官方bug网站的id号也可看出(https://bugs.mysql.com/bug.php?id=199) 首先,我们可以直观的重现如下. mysql ...
- php注册、登录界面的制作
当初我觉得一个网站上注册和登录这两个功能很神奇,后来自己研究一下发现其实道理很简单,接下来看一下怎么实现的吧.... 我实在我的电脑上建了几个文件: login.html (登录页面) registe ...
- java-同步控制及不可变设置(只读访问)
1.还是直接上代码简单了解一下: package com.synchronize.test; import java.util.ArrayList; import java.util.Collecti ...
- 外媒评李开复的《AI·未来》:四大浪潮正在席卷全球
外媒评李开复的<AI·未来>:四大浪潮正在席卷全球 https://mp.weixin.qq.com/s/oElub0QOYjOROhqN3ULUkg [网易智能讯 9月17日消息]李开复 ...
- RN开发中的报错以及告警
报错一: Attempted to transition from state `RESPONDER_INACTIVE_PRESS_IN` to `RESPONDER_ACTIVE_LONG_PRES ...
- [Web][高中同学毕业分布去向网站+服务器上挂载]二、敲定思路与方向(HTML5+JS(JQuery+ECharts))
高中同学毕业分布网站:敲定思路 一.背景 第一集:http://www.cnblogs.com/Twobox/p/8368121.html 中大体确定了自己的 大体目标.大体思路. 但是 . 在今天的 ...
- WordCount
一.Gitee地址:https://gitee.com/zjgss99/WordCount 二.项目分析: 对程序设计语言源文件统计字符数.单词数.行数,统计结果以指定格式输出到默认文件中,以及其他扩 ...
- Linux 中磁盘容量配额
linux的设计之处就是为了多用户同时执行不同的任务,但是硬件资源是有限的,不能让一个用户无限制的上传文件,如果不加以限制,那么磁盘最终将会被充满,对此我们应该使用uquota来加以限制. 1.quo ...
- 前后端分离djangorestframework—— 接入支付宝支付平台
支付宝 简介 支付宝是什么不用多说了,本次教程适合初学者 前提准备 话不多说,干就完了 1.注册开发者账号,设置公钥私钥 首先进入支付宝开发者平台:传送门 ,有账号直接登录,没账号用你平时用来付款收钱 ...