静态代理与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 ...
随机推荐
- [ SSH框架 ] Spring框架学习之一
一.Spring概述 1.1 什么是Spring Spring是一个开源框架, Spring是于2003年兴起的一个轻量级的Java开发框架,由 Rod Johnson在其著作 Expert One- ...
- springmvc 项目完整示例01 需求与数据库表设计 简单的springmvc应用实例 web项目
一个简单的用户登录系统 用户有账号密码,登录ip,登录时间 打开登录页面,输入用户名密码 登录日志,可以记录登陆的时间,登陆的ip 成功登陆了的话,就更新用户的最后登入时间和ip,同时记录一条登录记录 ...
- Linux和Shell回炉复习系列文章总目录
本页内容都是本人回炉Linux时整理出来的.这些文章中,绝大多数命令类内容都是翻译.整理man或info文档总结出来的,所以相对都比较完整. 本人的写作方式.风格也可能会让朋友一看就恶心到直接右上角叉 ...
- [转]GitLab-CI与GitLab-Runner
本文转自:https://www.jianshu.com/p/2b43151fb92e 一.持续集成(Continuous Integration) 要了解GitLab-CI与GitLab Runne ...
- App阅读pdf和扫描二维码功能
在之前开发的Android手机App中,需要实现阅读pdf和扫描二维码的功能,在github 上找到大牛封装好包,亲测可用. 阅读pdf: https://github.com/barteksc/An ...
- 浅谈CLR CTS CLS。。。
So The First Is CLR CLR的全程是Common Language Runtime 公共语言运行时 可以把他理解为包含运行.net程序的引擎 和 一堆符合公共语言基础(CLI)的类 ...
- php 时间戳最大值
今天遇到一个bug,获取有效期值错误,在定位跟踪后发现有效期有值,如下: $expireDate = ; //2037-08-16 09:30:48 但是在该时间戳的基础上加上1 year后, $ex ...
- Web前端 HTML知识总结
HTML篇 一.HTML的概念 HTML:就是Hyper Text Markup Languaged的缩写,意思就是超文本标志语言 (超文本:功能比普通文本要强:标志语言:使用一组标签对内容进行描述的 ...
- Design Mobile实现国际化
参考:https://mobile.ant.design/components/locale-provider-cn/
- C# 利用SharpZipLib生成压缩包
本文通过一个简单的小例子简述SharpZipLib压缩文件的常规用法,仅供学习分享使用,如有不足之处,还请指正. 什么是SharpZipLib ? SharpZipLib是一个C#的类库,主要用来解压 ...