Java常见23中设计模式之【代理模式】
一、静态代理模式
静态代理,使用继承的方式实现自己新增的服务
这种模式可以实现帮助被代理者完成一些前期的准备工作和后期的善后工作,但是核心的业务逻辑仍然是由被代理者完成。
在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个代理的第三者间接引用,。起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或额外服务。
代理是一个对象,代理对象为其他对象提供一种代理,以控制对这个对象的访问,代理对象起到中介作用,可以去掉或者增加额外的服务。
如:火车票代售点就是火车站售票处的一个代理对象,可通过访问代售点进行业务处理。
二,静态代理的2种实现方式:继承和聚合
静态代理中的代理和被代理对象在代理之前关系是确定的。它们都实现了相同的接口或者继承相同的抽象类。
下面的例子分别讲述了所有的类实现同一个接口,类对象之间是如何代理的。
案例代码实现:
1.定义一个接口类Moveable.java
package com.sjms.test.proxy.interfaces;
public interface Moveable {
void move();
}
2.定义一个实体类Car.java 并实现以上接口。
package com.sjms.test.proxy.impl;
import com.sjms.test.proxy.interfaces.Moveable;
public class Car implements Moveable {
@Override
public void move() {
try {
System.out.println("开始喽");
Thread.sleep(1000L);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.定义一个代理类Car2.java(此类,即实现了父类方法,又实现了新增的业务)
package com.sjms.test.proxy.impl;
public class Car2 extends Car {
public void move() {//实现自身方法
Long startTime = System.currentTimeMillis();
System.out.println("开始开车。。。。");
super.move();//实现父类方法
Long endTime = System.currentTimeMillis();
System.out.println("已经停止。。。。,用时:"+(endTime-startTime));
}
}
4.Test.java类
package com.sjms.test.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import com.sjms.test.proxy.handler.TimerHandler;
import com.sjms.test.proxy.impl.Car;
import com.sjms.test.proxy.impl.Car2;
import com.sjms.test.proxy.impl.Car3;
import com.sjms.test.proxy.interfaces.Moveable;
4.通过聚合构造函数方式 (通过将参数传递进来,然后我们使用传递进来的参数,调用其方法,实现静态代理)
public class Car3 implements Moveable{
private Car car;
public Car3(Car car) {
super();
this.car = car;
}
@Override
public void move() {
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶.......");
//通过构造方法将car传进来,然后通过car调用方法
car.move();
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶......");
System.out.println("汽车行驶时间:"+(endtime - starttime)+"毫秒!");
}
}
public class Test {
public static void main(String[] args) {
//1.静态代理,使用继承的方式实现自己新增的服务
Moveable moveable = new Car2();
moveable.move();
//2.聚合静态代理,使用构造方法传入参数。
/*Car car = new Car();
Moveable car3 = new Car3(car);
car3.move();*/
}
}
二、使用静态代理,会让我们的代理类无限膨胀下去,所以出现了动态代理模式(JDK动态代理、CGLIB动态代理)
在代理类和被代理类之间加上一个事务处理器,将我们需要处理的具体功能放在其中进行处理。
1.JDK动态代理(InvocationHandler事务处理器,Proxy:代理类)
InvocationHandler接口中仅定义了一个方法public object invoke(Object obj,Method method,Object[] args)
第一个参数:代理类,第二个参数:被代理的方法,第三个参数:该方法的参数数组
Proxy:动态代理类,通过newProxyInstance方法返回代理类的实例,
实现步骤:
1).创建一个实现InvocationHandler接口的实现类,并实现invoke方法
2).创建被代理的类和接口(Car和Moveable 在上面的案例中已经构建)
3).动态创建一个代理类(Proxy.newProxyInstance)package com.sjms.test.proxy.handler;
TimerHandler.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimerHandler implements InvocationHandler{
private Object target;
public TimerHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] param)
throws Throwable {
Long startTime = System.currentTimeMillis();
System.out.println("汽车开始行使了...");
method.invoke(target);
Long entTime = System.currentTimeMillis();
System.out.println("汽车结束行驶......");
System.out.println("汽车行驶时间:"+(entTime - startTime)+"毫秒!");
return null;
}
}
Test.java 构造代理类,实现具体的代理类
package com.sjms.test.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import com.sjms.test.proxy.handler.TimerHandler;
import com.sjms.test.proxy.impl.Car;
import com.sjms.test.proxy.impl.Car2;
import com.sjms.test.proxy.impl.Car3;
import com.sjms.test.proxy.interfaces.Moveable;
public class Test {
public static void main(String[] args) {
//1.静态代理,使用继承的方式实现自己新增的服务
Moveable moveable = new Car2();
moveable.move();
//2.聚合静态代理,使用构造方法传入参数。
/*Car car = new Car();
Moveable car3 = new Car3(car);
car3.move();*/
//3.动态代理
Car carObj = new Car();//被代理的类
InvocationHandler handler = new TimerHandler(carObj);//事务处理器
//使用代理器实现
Moveable move = (Moveable)Proxy.newProxyInstance(carObj.getClass().getClassLoader(), carObj.getClass().getInterfaces(), handler);
//move 为生产的代理类
move.move();
}
}
2.cgLib的动态代理实现
由于JDK只能针对实现了接口的类做动态代理,而不能对没有实现接口的类做动态代理,所以cgLib横空出世!
CGlib是一个强大、高性能的Code生成类库,它可以在程序运行期间动态扩展类或接口,它的底层是使用java字节码操作框架ASM实现。它可以动态的操作类部方法
1) 引入cgLib 库
2)定义业务类,被代理的类没有实现任何接口(有实现接口的也可以)
package com.sjms.test.proxy.impl;
public class Car4 {
public void move() {
System.out.println("开始发车");
}
}
3)定义拦截器,在调用目标方法时,CGlib会回调MethodInterceptor 接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。
package com.sjms.test.proxy.handler;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* cglib 动态代理拦截器实现
* */
public class CglibDynProxyInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object arg0, Method arg1, Object[] params,
MethodProxy methodProxy) throws Throwable {
if (arg1.getName().equals("move")){
System.out.println("cgLib动态代理拦截器开始,拦截方法mmove()......");
//代理类调用父类的方法
return methodProxy.invokeSuper(arg0, params);
}
return null;
}
}
4)定义动态代理工厂,生成动态代理
package com.sjms.test.proxy.factory;
import com.sjms.test.proxy.handler.CglibDynProxyInterceptor;
import net.sf.cglib.proxy.Enhancer;
//生产代理工厂
public class CglibProxyFactory {
public static Object getCarProxy(Object target){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new CglibDynProxyInterceptor());
return enhancer.create();
}
}
5)测试
package com.sjms.test.proxy;
import com.sjms.test.proxy.factory.CglibProxyFactory;
import com.sjms.test.proxy.impl.Car4;
public class Car4CglibTest {
public static void main(String[] args){
//Cglib动态代理原理,就是通过拦截器来新增自己的增值业务
Car4 car = (Car4)CglibProxyFactory.getCarProxy(new Car4());
car.move();
}
}
ps:切面编码实际底层原理使用动态代理模式
cgLib的动态代理原理
CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
CGLIB缺点:对于final方法,无法进行代理。
Java常见23中设计模式之【代理模式】的更多相关文章
- java的23中设计模式
一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ...
- Java开发23中设计模式
设计模式(Design Patterns) 设计模式是一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结.使用设计模式是为了可重用代码,让代码更容易被他人理解,保证代码的可靠性.毫无疑问 ...
- Java进阶篇设计模式之七 ----- 享元模式和代理模式
前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...
- 【java设计模式】(3)---代理模式(案例解析)
设计模式之代理模式 一.概述 1.什么是代理模式? 解释第一遍:代理模式主要由三个元素共同构成: 1)一个接口,接口中的方法是要真正去实现的. 2)被代理类,实现上述接口,这是真正去执行接口中方法的类 ...
- Java设计模式之七 ----- 享元模式和代理模式
前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...
- [转载]Java中继承、装饰者模式和代理模式的区别
[转载]Java中继承.装饰者模式和代理模式的区别 这是我在学Java Web时穿插学习Java设计模式的笔记 我就不转载原文了,直接指路好了: 装饰者模式和继承的区别: https://blog.c ...
- java的23种设计模式之建造者模式
场景和本质 场景 本质 案例 原理 应用场景 场景和本质 场景 我们要建造一个复杂的产品.比如:神州飞船,Iphone.这个复杂的产品的创建.有这样一个问题需要处理:装配这些子组件是不是有个步骤问题? ...
- 菜鸟版JAVA设计模式—从买房子看代理模式
今天学习了代理模式. 相对于适配器模式,或者说装饰器模式,代理模式理解起来更加简单. 代理这个词应该比較好理解,取代去做就是代理. 比方,我们买卖房子,那么我们会找中介,我要卖房子,可是我们没有时间去 ...
- 【Unity与23种设计模式】代理模式(Proxy)
GoF中定义: "提供一个代理者位置给一个对象,好让代理者可以控制存取这个对象." 代理模式多用来优化资源的加载 当资源已经加载过时,使用原来的资源 当资源没有加载过时,开始加载 ...
随机推荐
- Ondemand和Interactive gonernor工作逻辑简述
ondemand 简述: 1.采样时间:sampling_rate,单位us 2.cpu usage是仅统计最新1us的一个smaple周期,以%体现cpu busy程度. 3.一般情况下,next频 ...
- Java实现 蓝桥杯 历届试题 核桃的数量
历届试题 核桃的数量 时间限制:1.0s 内存限制:256.0MB 问题描述 小张是软件项目经理,他带领3个开发组.工期紧,今天都在加班呢.为鼓舞士气,小张打算给每个组发一袋核桃(据传言能补脑).他的 ...
- Java实现 蓝桥杯VIP 算法训练 拦截导弹
1260:[例9.4]拦截导弹(Noip1999) 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 4063 通过数: 1477 [题目描述] 某国为了防御敌国的导弹袭击,发展出一 ...
- Java实现 LeetCode_0048_RotateImage
package javaLeetCode.medium; public class RotateImage_48 { public static void main(String[] args) { ...
- java实现第四届蓝桥杯马虎的算式
马虎的算式 题目描述 小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了. 有一次,老师出的题目是:36 x 495 = ? 他却给抄成了:396 x 45 = ? 但结果却很戏剧性,他的答 ...
- JS变量小总
变量分类:1.栈内存(stack)和堆内存(heap)2.基本类型和引用类型 #栈内存(stack) 一般为静态分配内存,其分配的内存系统自动释放. #堆内存(heap) 一般为动态分配内存,其分配的 ...
- JNI_day02
二级指针 指向指针变量的指针,保存指针的地址 结构体 struct Student //struct Stdent 学生结构体类型 { int id;//成员 char name[20]; int a ...
- Java——String类(常用类)
一.String类——描述字符串 常用的方法简单介绍: 1.charAt() 获取对应位置的字符 2.length() 获取字符串的长度 3.concat() 在字符串的尾部追加内容-----相当于连 ...
- Excel只想显示一部分日期,怎样把其余部分隐藏起来?
问题:只想显示一部分日期,怎样把其余部分隐藏起来? 方法:分列 Step1:选中需要修改的单元格——数据——分列. Step2:固定宽度——点击下一步. Step3:在建立分列处单击鼠标(若想取消 ...
- IE11下文档模式默认值是7, 而且无法更改
IE9以上是支持css3的,但是有的IE11的浏览器里面,文档模式默认值是7,而且是无法改变的,就会导致网页布局错乱 我的IE11的文档模式默认值是11 ,如下图 (打开页面按F12) 对于默认值是 ...