Java代理详解
一、概述
代理模式是Java常用的设计模式之一,实现代理模式要求代理类和委托类(被代理的类)具有相同的方法(提供相同的服务),代理类对象自身并不实现真正的核心逻辑,而是通过调用委托类对象的相关方法来处理核心逻辑,而代理类对象主要负责为委托类对象过滤消息、预处理消息、转发消息给委托类、事后处理消息等等。通常代理类会与委托类存在关联关系。
二、静态代理
public interface SaleCar {
void sale();
}
2.hafiz真正卖车子实现类
public class HafizSaleCar implements SaleCar {
@Override
public void sale() {
System.out.println("hafiz sale his car...");
}
}
3.二手车交易中介类
public class CarTradeProxy implements SaleCar {
private HafizSaleCar owner;
public CarTradeProxy(HafizSaleCar owner) {
this.owner = owner;
}
@Override
public void sale() {
System.out.println("proxy add price...");
owner.sale();
}
}
4.测试类
public class Client {
public static void main(String[] args) {
HafizSaleCar owner = new HafizSaleCar();
CarTradeProxy proxy = new CarTradeProxy(owner);
proxy.sale();
}
}
5.测试结果
从上面的代码中,我们可以看出,其实代理类(CarTradeProxy)和委托类(HafizSaleCar)好像区别并不大,我们直接创建一个HafizSaleCar对象,然后调用它的sale()方法不就好了?细心的同学你会发现,其实代理在真正调用委托类的方法之前做了中介加价的操作,这也就意味着我们使用代理模式实现在委托类的基础上增加额外的逻辑操作。
以上就是一个很简单的静态代理的实现过程。但是这个时候我又有了一个新需求,我想用我手里的存款以及买车子赚的钱来给自己买一套新房子,那我又不想东奔西跑找房源,于是我又把买房这件事委托给了房产中介,下面我们就来实现这个逻辑。
1.再定义一个买房的接口
public interface BuyHouse {
void buy();
}
2.重写委托类,实现卖车和买房两个接口
public class HafizTrade implements SaleCar, BuyHouse {
@Override
public void buy() {
System.out.println("hafiz buy house...");
}
@Override
public void sale() {
System.out.println("hafiz sale car...");
}
}
可以看到,我现在既要卖掉我的车子,又要购买新的房子。
3.再创建一个买房子的中介代理类
public class HouseTradeProxy implements BuyHouse {
private HafizTrade customer;
public HouseTradeProxy(HafizTrade customer) {
this.customer = customer;
}
@Override
public void buy() {
System.out.println("proxy add price...");
customer.buy();
}
}
4.卖车子的代理类修改如下
public class CarTradeProxy implements SaleCar {
private HafizTrade owner;
public CarTradeProxy(HafizTrade owner) {
this.owner = owner;
}
@Override
public void sale() {
System.out.println("proxy add price...");
owner.sale();
}
}
5.新的测试类
public class Client {
public static void main(String[] args) {
HafizTrade trader = new HafizTrade();
CarTradeProxy carTradeProxy = new CarTradeProxy(trader);
carTradeProxy.sale();
System.out.println("-----------------------------------------------");
HouseTradeProxy houseTradeProxy = new HouseTradeProxy(trader);
houseTradeProxy.buy();
System.out.println("-----------------------------------------------");
}
}
6.测试结果
这样通过静态代理的方式,我们的确也可以很完美的解决我们的问题,但当我们有越来越多的委托类需要代理,而且代理做的工作又一样,那是不是会多出来很多的代理类,我们开发者会疯掉的,这时候我们就想:如果我们可以只做一次,就能代理一类委托类该多好啊?那么这个时候,动态代理就应运而生了,它可以使得我们只定义一次就能为一类委托类做代理。
三、动态代理
静态代理要求我们在程序发布上线运行之前,就要开发好对应委托类的代理类,而动态代理是我们在程序发布之前,并没有创建好对应的代理类,而是在运行的时候动态的创建代理类。
动态代理实现方式有两种:jdk自带动态代理实现以及cglib实现。jdk代理只适合代理实现接口的目标对象,cglib可以代理没有实现接口的目标对象。
四、基于JDK实现动态代理
1.实现步骤
1).通过实现 InvocationHandler 接口创建自己的调用处理器
2).通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类
3).通过反射机制获得动态代理类的构造函数(jdk自带,不需手动处理)
4).通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入(jdk自带,不需手动处理)
2.创建代理处理器
public class ProxyHandler implements InvocationHandler {
private Object target;
public ProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy add price...");
Object result = method.invoke(target, args);
return result;
}
}
3.测试类
public class Client {
public static void main(String[] args) {
HafizTrade trader = new HafizTrade();
ProxyHandler handler = new ProxyHandler(trader);
Class<? extends HafizTrade> clazz = trader.getClass();
ClassLoader classLoader = clazz.getClassLoader();
Class<?>[] interfaces = clazz.getInterfaces();
SaleCar carProxy = (SaleCar)Proxy.newProxyInstance(classLoader, interfaces, handler);
carProxy.sale();
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++");
BuyHouse houseProxy = (BuyHouse)Proxy.newProxyInstance(classLoader, interfaces, handler);
houseProxy.buy();
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++"); }
}
4.测试结果
5.原理
生成一个代理类,这个代理类继承Proxy类并且实现了我们定义的接口,代理对象调用方法的时候,调用这个代理对象的一个成员InvocationHandler(上面我们传入了一个InvocationHandler实现对象)的方法,也就是我们包装了委托类后的方法。
五、基于cglib实现动态代理
1.实现步骤
1).通过实现CGLib包提供的MethodInterceptor接口,重写intercept方法,创建自己的方法拦截器
2).通过CGLib中的Enhancer的creat方法创建动态代理对象
2.添加cglib的maven依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
3.自定义ProxyInterceptor
public class ProxyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Trade proxy add price...");
Object result = methodProxy.invokeSuper(o, objects);
return result;
}
}
4.测试client
public class Client {
public static void main(String[] args) {
ProxyInterceptor proxy = new ProxyInterceptor();
HafizTrade tradeProxy = (HafizTrade)Enhancer.create(HafizTrade.class, proxy);
tradeProxy.sale();
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++");
tradeProxy.buy();
}
}
5.测试结果
6.原理
首先通过asm字节码生成框架生成代理类Class的二进制字节码,然后通过Class.forName加载二进制字节码,生成Class对象,最后通过反射机制获取实例构造,并初始化代理类对象。
六、总结
动态代理可以使得我们一次可以解决一批需要创建代理的问题,使得代码更加灵活,提高了程序的扩展性。动态代理在主流java框架中也非常常用,比如最著名的spring,它在AOP的功能就是使用动态代理实现,还有Dubbo等这样的RPC服务框架,在客户端都是通过代理完成服务的真正调用。了解和学会代理以及实现方式能帮助我们更好地理解主流框架。
关于动态代理的实现细节,可以参考:http://www.360doc.com/content/14/0801/14/1073512_398598312.shtml#
Java代理详解的更多相关文章
- Java Annotation详解 理解和使用Annotation
系统中用到了java注解: 查了一下如何使用注解,到底注解是什么: (1)创建方法:MsgTrace Java Class==> 在Create New Class中: name:输入MsgTr ...
- Java ClassLoad详解
Java ClassLoad详解 类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一.它使得 Java 类可以被动态加载到 Java 虚拟机中并执行.类加载器从 JDK 1. ...
- 静态代理,动态代理,Cglib代理详解
一.静态代理 新建一个接口 定义一个玩家方法: package com."".proxy.staticc; public interface Iplayer { public vo ...
- android java 设计模式详解 Demo
android java 设计模式详解 最近看了一篇设计模式的文章,深得体会,在此基础我将每种设计模式的案例都写成Demo的形式,方便读者研究学习, 首先先将文章分享给大家: 设计模式(Design ...
- SpringBoot27 JDK动态代理详解、获取指定的类类型、动态注册Bean、接口调用框架
1 JDK动态代理详解 静态代理.JDK动态代理.Cglib动态代理的简单实现方式和区别请参见我的另外一篇博文. 1.1 JDK代理的基本步骤 >通过实现InvocationHandler接口来 ...
- Java接口 详解(二)
上一篇Java接口 详解(一)讲到了接口的基本概念.接口的使用和接口的实际应用(标准定义).我们接着来讲. 一.接口的应用—工厂设计模式(Factory) 我们先看一个范例: package com. ...
- Java ClassLoader详解(转载)
Java ClassLoader详解 类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一.它使得 Java 类可以被动态加载到 Java 虚拟机中并执行.类加载器从 JDK ...
- Java内部类详解
Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...
- 黑马----JAVA迭代器详解
JAVA迭代器详解 1.Interable.Iterator和ListIterator 1)迭代器生成接口Interable,用于生成一个具体迭代器 public interface Iterable ...
随机推荐
- CSS禁止用户选择复制
-webkit-user-select:none ;-moz-user-select:none; P.S. -wekit-gg浏览器 -moz -ff浏览器 WebKit 是一个开源的浏览器引擎,与之 ...
- C互质个数
C互质个数 Time Limit:1000MS Memory Limit:65536K Total Submit:55 Accepted:27 Description 贝贝.妞妞和康康都长大了,如今 ...
- The ways to kill Oracle session
As we all known ,its the normal way to use the SQL 'alter system kill 'sid,serial#'' to kill a ses ...
- Data truncation: Data too long for column 'gender' at row 1 出现的原因
创建数据库的代码如下: create database day15 ; use day15 ; create table customer( id varchar(100) primary key, ...
- 设计模式(3)--SimpleFactory( [1] 简单工厂模式)--创建型
1.模式定义: 简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式.简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例. 2.模式特点: 实现方式的 ...
- Opentk教程系列-1绘制一个三角形
本系列教程翻译自Neo Kabuto's Blog.已经取得作者授权. 本文原文地址http://neokabuto.blogspot.com/2013/02/opentk-tutorial-1-op ...
- es6五种遍历对象属性的方法 - 表格整理
ES6 一共有5种方法可以遍历对象的属性. (1)for...in for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性). (2)Object.keys(obj) Obje ...
- 这是一个简单的前台短信验证码功能 ajax实现异步处理 (发送和校验)
<script type="text/javascript"> var InterValObj; //timer变量,控制时间 var count = 60; //间隔 ...
- 自制简易Linux系统
l 要求: 裁剪一个装载有网卡驱动可以上网并且使用到init的一个小系统 l 准备: 虚拟机,centos6.4 l 步骤: 一.在宿主机上添加一块硬盘,并为其安装grub 1. 在宿主机上添加一块硬 ...
- .NET平台微服务项目汇集
最近博客园出现了一篇文章<微服务时代之2017年五军之战:Net PHP谁先死>,掀起了一波撕逼,作者只是从一个使用者的角度来指点江山,这个姿势是不对的..NET Core就是专门针对模块 ...