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中定义: "提供一个代理者位置给一个对象,好让代理者可以控制存取这个对象." 代理模式多用来优化资源的加载 当资源已经加载过时,使用原来的资源 当资源没有加载过时,开始加载 ...
随机推荐
- 蓝桥杯 算法训练 P0505(Java解法)
一个整数n的阶乘可以写成n!,它表示从1到n这n个整数的乘积.阶乘的增长速度非常快,例如,13!就已经比较大了,已经无法存放在一个整型变量中:而35!就更大了,它已经无法存放在一个浮点型变量中.因此, ...
- Java实现 LeetCode 659 分割数组为连续子序列 (哈希)
659. 分割数组为连续子序列 输入一个按升序排序的整数数组(可能包含重复数字),你需要将它们分割成几个子序列,其中每个子序列至少包含三个连续整数.返回你是否能做出这样的分割? 示例 1: 输入: [ ...
- Java实现 LeetCode 558 四叉树交集(四叉树,第一次遇到,研究了半天)
558. 四叉树交集 四叉树是一种树数据,其中每个结点恰好有四个子结点:topLeft.topRight.bottomLeft 和 bottomRight.四叉树通常被用来划分一个二维空间,递归地将其 ...
- 记一次mysql修复错误数据问题
问题描述 之前做的一个服务端配合硬件端的项目,今天突然在微信上跟我讲在管理后台订单列表里的设备编号看不见后3位数字. 原因查找 看了下数据库表发现原因是因为订单表的设备编号长度限制了16位(开发时跟硬 ...
- JSONobject按照put顺序存储和读取
new的时候加true即可: JSONObject jsonObject = new JSONObject(true);
- mybatis 多表联查,多个实体类,如何返回一个List?(表太多,字段太多的问题)
原文:https://ask.csdn.net/questions/674166 自己重新定义一个实体类 把查询结果放到这个实体类中,实体类包含所有的查询结果的字段 一个更好的办法,我发现你这关联表所 ...
- C#数据结构与算法系列(八):栈(Stack)
1.介绍 栈是一个先入后出(FILO-First In Last Out)的有序列表 栈是限制线性表中元素的插入和删除只能在线性表的同一端进行的特殊线性表.允许插入和删除的一端,为变化的一端,称为栈顶 ...
- STM32单片机应用与全案例实践 /stm32自学笔记 第二版 pdf
STM32单片机应用与全案例实践pdf https://pan.baidu.com/s/16WrivuLcHvLTwS__Zcwl6Q 4rj3 stm32自学笔记 第二版 pdf https://p ...
- 解除git文件处于lock状态方法
解决办法: 去git文件夹下删除lock文件就可以
- docker安装,基本使用,实战
[docker概念作用术语] [使用docker的步骤] [docker安装及配置] [环境要求] docker要求centos7 必须要64位,内核3.1及以上 https://docs.docke ...