文章目录
代理模式概念
- 为其他对象提供-种代理,以控制对这个对象的访问
- 为其他对象提供一种代理以控制对这个对象的访问。
- 代理对象起到中介作用,可去掉功能服务或增加额外的服务。
常见的代理模式
- 虚拟代理
根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建
例:为了提高用户体验,页面图片在未加载完成时通常使用一张虚拟图片作为替代显示,当真实图片加载完成时再进行替换
- 智能代理
提供对目标对象额外的服务
例:火车票代售处不仅可以购票,还提供了一些其他额外的服务
- 远程代理
为不同地理的对象,提供局域网代表对象
例:通过远程代理可以监控各个店铺,使之能直观的了解店内信息
- 保护代理
控制对一个对象访问的权限
例:普通用户没有注册登录时只能进行浏览,当登录之后则具备其他额外的功能
静态代理
- 代理和被代理对象在代理之前是确定的。
- 他们都实现相同的接口或者继承相同的抽象类。
代码实现
普通方式
- 模拟汽车行驶,计算行驶时间
汽车行驶接口
/**
* 汽车行驶接口
*/
public interface Moveable {
/**
* 移动方法
*
* @throws InterruptedException
*/
void move() throws InterruptedException;
}
Moveable
接口实现
/**
* Moveable实现类Car
*/
public class Car implements Moveable {
/**
* 实现move方法
*/
@Override
public void move() throws InterruptedException {
long begin = System.currentTimeMillis();
System.err.println("汽车开始行驶:" + begin);
Thread.sleep(new Random().nextInt(1000));
System.err.println("汽车行驶中……");
long end = System.currentTimeMillis();
System.err.println("汽车行驶结束[" + (end - begin) + "]毫秒!");
}
}
测试类
public class App {
public static void main(String[] args) throws InterruptedException {
Car car = new Car();
car.move();
}
}
结果
汽车开始行驶:1595256389860
汽车行驶中……
汽车行驶结束[920]
采用继承方式实现静态代理
汽车行驶接口
/**
* 汽车行驶接口
*/
public interface Moveable {
/**
* 移动方法
*
* @throws InterruptedException
*/
void move() throws InterruptedException;
}
Moveable
接口实现Car
/**
* Moveable实现类Car
*/
public class Car implements Moveable {
/**
* 实现move方法
*/
@Override
public void move() throws InterruptedException {
Thread.sleep(new Random().nextInt(1000));
}
}
Car
子类CarTwo
/**
* Car子类CarTwo
*/
public class CarTwo extends Car {
/**
* 重写父类move方法
*
* @throws InterruptedException
*/
@Override
public void move() throws InterruptedException {
long begin = System.currentTimeMillis();
System.err.println("汽车开始行驶:" + begin);
//调用父类move方法
super.move();
System.err.println("汽车行驶中……");
long end = System.currentTimeMillis();
System.err.println("汽车行驶结束[" + (end - begin) + "]毫秒!");
}
}
测试类
public class App {
public static void main(String[] args) throws InterruptedException {
Moveable carTwo = new CarTwo();
carTwo.move();
}
}
结果
汽车开始行驶:1595257271552
汽车行驶中……
汽车行驶结束[594]毫秒!
采用聚合方式实现静态代理
汽车行驶接口
/**
* 汽车行驶接口
*/
public interface Moveable {
/**
* 移动方法
*
* @throws InterruptedException
*/
void move() throws InterruptedException;
}
Moveable
实现类Car
/**
* Moveable实现类Car
*/
public class Car implements Moveable {
/**
* 实现move方法
*/
@Override
public void move() throws InterruptedException {
Thread.sleep(new Random().nextInt(1000));
}
}
Moveable
实现类CarThree
/**
* Moveable实现类CarThree
*/
public class CarThree implements Moveable {
private Car car;
/**
* 提供有参构造方法
*
* @param car
*/
public CarThree(Car car) {
this.car = car;
}
@Override
public void move() throws InterruptedException {
long begin = System.currentTimeMillis();
System.err.println("汽车开始行驶:" + begin);
car.move();
System.err.println("汽车行驶中……");
long end = System.currentTimeMillis();
System.err.println("汽车行驶结束[" + (end - begin) + "]毫秒!");
}
}
测试类
public class App {
public static void main(String[] args) throws InterruptedException {
Car car = new Car();
Moveable carThree = new CarThree(car);
carThree.move();
}
}
结果
汽车开始行驶:1595258131192
汽车行驶中……
汽车行驶结束[447]毫秒!
聚合比继承更适合代理模式
采用继承方式实现功能叠加
- 代理类会无限膨胀
- 继承这种方式不是最理想
JDK动态代理
思考:如果需求变更为记录自行车,火车,摩托车,小轿车,消防车……,记录各种车辆行驶时间,我们需要建立成百上千个代理类,这样则会造成类的无限膨胀
那么有没有一种办法可以去解决这种类膨胀的问题呢?
代理模式-动态代理
动态产生代理,实现对不同类,不同方法的代理
动态代理类图
-
ProxySubject
:代理类 -
RealSubject
:被代理类 -
ProxyHandler
:事务处理器,该类实现InvocationHandler
接口 -
Java动态代理类位于
java.lang.reflect
包下,一般主要涉及到以下两个类:-
Interface InvocationHandler
:该接口中仅定义了–个方法public object invoke(Object obj,Method method,Object[] args)
在实际使用时,第一个参数obj
一般是指代理类,method
是被代理的方法,args
为该方法的参数数组。这个抽象方法在代理类中动态实现。 -
/** * @param obj 被代理的对象 * @param method 被代理的方法 * @param args 代理方法的参数 * @return */ public object invoke(Object obj,Method method,Object[] args)
-
Proxy
:该类即为动态代理类
static Object newProxyInstance(ClassLoader loader,Class[]interfaces,InvocationHandler h)
:返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在接口中声明过的方法)
-
代码实现
汽车行驶接口
/**
* 汽车行驶接口
*/
public interface Moveable {
/**
* 移动方法
*
* @throws InterruptedException
*/
void move() throws InterruptedException;
}
Moveable
实现类Car
/**
* Moveable实现类Car
*/
public class Car implements Moveable {
/**
* 实现move方法
*/
@Override
public void move() throws InterruptedException {
Thread.sleep(new Random().nextInt(1000));
}
}
InvocationHandler
实现类JDKDynamicProxy
package designmode.jdkdynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class JDKDynamicProxy implements InvocationHandler {
/**
* 代理对象
*/
private Object target;
/**
* 提供有参构造
*
* @param target
*/
public JDKDynamicProxy(Object target) {
this.target = target;
}
/**
* @param proxy 被代理对象
* @param method 代理方法
* @param args 代理方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法调用前业务逻辑
long begin = System.currentTimeMillis();
System.err.println("汽车开始行驶:" + begin);
method.invoke(target);
//方法调用后业务逻辑
System.err.println("汽车行驶中……");
long end = System.currentTimeMillis();
System.err.println("汽车行驶结束[" + (end - begin) + "]毫秒!");
return null;
}
}
测试类
package designmode;
import designmode.jdkdynamicProxy.JDKDynamicProxy;
import designmode.proxypattern.Car;
import designmode.proxypattern.Moveable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class App {
public static void main(String[] args) throws InterruptedException {
Car car = new Car();
Class<?> carClass = car.getClass();
//类加载器
ClassLoader loader = carClass.getClassLoader();
//实现的接口
Class<?>[] interfaces = carClass.getInterfaces();
//事务处理器
InvocationHandler h = new JDKDynamicProxy(car);
/**
* 动态创建代理类
* [param:loader]类加载器
* [param:interfaces]实现的接口
* [param:h]事务处理器
* [return]被代理对象
*/
Moveable moveable = (Moveable) Proxy.newProxyInstance(loader, interfaces, h);
//调用动态代理move方法
moveable.move();
}
}
结果
汽车开始行驶:1595306600817
汽车行驶中……
汽车行驶结束[166]毫秒!
JDK动态代理总结
- 所谓
Dynamic Proxy
是这样一种class
:- 它是在运行时生成的
class
- 该
class
需要实现一组interface
- 使用动态代理类时,必须实现
InvocationHandler
接口
- 它是在运行时生成的
- 实现步骤
- 创建一个实现接口
InvocationHandler
的类,它必须实现invoke
方法 - 创建被代理的类以及接口
- 调用
Proxy
的静态方法,创建-个代理类newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
- 通过代理调用方法
- 创建一个实现接口
CGLIB动态代理
JDK动态代理和CGLIB动态代理
JDK
动态代理(通过实现的方式)- 只能代理实现了接口的类
- 没有实现接口的类不能实现
JDK
的动态代理。
CGLIB
动态代理(通过继承的方式实现)- 针对类来实现代理
- 对指定目标产生一个子类,通过方法拦截技术拦截所有父类方法的调用
代码实现
引入依赖
cglib
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
Train
类
package designmode.cglibproxy;
public class Train {
public void move() {
System.err.println("火车行驶中……");
}
}
CglibProxy
(该类实现MethodInterceptor
接口)
package designmode.cglibproxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
/**
* 生成代理类
*
* @param superClass
* @return
*/
public Object getProxy(Class superClass) {
//设置创建子类的类
enhancer.setSuperclass(superClass);
enhancer.setCallback(this);
//创建子类实例
return enhancer.create();
}
/**
* 拦截所有目标类方法的调用
*
* @param o 目标类的实例
* @param method 目标方法的反射对象
* @param objects 方法的参数
* @param methodProxy 代理类的实例
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.err.println("日志记录开始……");
//代理类调用父类的方法
methodProxy.invokeSuper(o, objects);
System.err.println("日志记录结束……");
return null;
}
}
测试类
package designmode.cglibproxy;
public class CglibTest {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
Train train = (Train) cglibProxy.getProxy(Train.class);
train.move();
}
}
结果
日志记录开始……
火车行驶中……
日志记录结束……