简介:代理模式是一种非常重要的设计模式,在 Java 语言中有着广泛的应用,包括Spring AOP 的核心设计思想,都和代理模式有密切关系。什么场景使用代理模式?代理模式实现原理是什么?本节课程将带你领略代理模式的奥妙。
1. 代理模式概念介绍
1.1 代理模式定义:为其他对象提供一种代理,以控制对这个对象的访问。代理对象起到中介的作用,可以去掉功能服务或增加额外的服务。
如:火车票代售处是火车站的代理。
1.2 几种常见的代理模式
远程代理:为不同地理的对象提供局域网代表对象。
虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建
如一张大的图片未加载成功时先用一张小的图片代替就是虚拟代理的一种应用。
保护代理:控制对一个对象的访问权限。
如发帖功能中,控制用户的访问权限,登录和不登录的用户具有不同的权限。
智能引用代理:提供对目标对象的一些额外服务。
2. 常用代理模式原理(智能引用为例)
2.1 静态代理概念及实现
静态代理:代理和被代理对象在代理之前是确定的。他们都实现相同的接口或者继承相同的抽象类。
模拟场景:汽车行驶,通过代理实现汽车行驶的基本功能+行驶计时功能
2.1.1 初始代码:
public interface Movable {
public void move();
}
import java.util.Random;
public class Car implements Movable {
public void move() {
long starttime=System.currentTimeMillis();
System.out.println("汽车开始行驶....");
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中...");
} catch (InterruptedException e) {
e.printStackTrace();
}
long endtime=System.currentTimeMillis();
System.out.println("汽车行驶结束...汽车行驶时间为:"+(endtime-starttime)+"毫秒!");
}
}
public class Client {
//测试类
public static void main(String[] args) {
Car car=new Car();
car.move();
}
}
输出:
汽车开始行驶....
汽车行驶中...
汽车行驶结束...汽车行驶时间为:979毫秒!
2.1.2 修改一
使用继承方式实现代理
public interface Movable {
public void move();
}
public class Car implements Movable {
public void move() {
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
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)+"毫秒!");
}
}
public class Client {
//测试类
public static void main(String[] args) {
Car car=new Car2();
car.move();
}
}
输出:
汽车开始行驶....
汽车行驶中...
汽车行驶结束...汽车行驶时间为:977毫秒!
2.1.3 修改二
使用聚合方式实现代理
public interface Movable {
public void move();
}
public class Car implements Movable {
public void move() {
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Car3 implements Movable {
private Car car;
public Car3(Car car) {
super();
this.car=car;
}
public void move() {
long starttime=System.currentTimeMillis();
System.out.println("汽车开始行驶....");
car.move();
long endtime=System.currentTimeMillis();
System.out.println("汽车行驶结束...汽车行驶时间为:"+(endtime-starttime)+"毫秒!");
}
}
public class Client {
//测试类
public static void main(String[] args) {
Car car=new Car();
Movable car3=new Car3(car);
car3.move();
}
}
输出:
汽车开始行驶....
汽车行驶中...
汽车行驶结束...汽车行驶时间为:414毫秒!
2.2 聚合比继承更适合代理模式
使用继承的方式实现功能的叠加会导致代理类无限地膨胀下去。
使用聚合方式实现代理组合:(时间代理和日志代理的叠加)
public interface Movable {
public void move();
}
import java.util.Random;
public class Car implements Movable {
public void move() {
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class CarTimeProxy implements Movable {
private Movable m;
public CarTimeProxy(Movable m) {
super();
this.m=m;
}
public void move() {
long starttime=System.currentTimeMillis();
System.out.println("汽车开始行驶....");
m.move();
long endtime=System.currentTimeMillis();
System.out.println("汽车行驶结束...汽车行驶时间为:"+(endtime-starttime)+"毫秒!");
}
}
public class CarLogProxy implements Movable {
private Movable m;
public CarLogProxy(Movable m) {
super();
this.m=m;
}
public void move() {
System.out.println("日志开始....");
m.move();
System.out.println("日志结束...");
}
}
public class Client {
//测试类
public static void main(String[] args) {
Car car=new Car();
CarTimeProxy ctp=new CarTimeProxy(car);
CarLogProxy clp=new CarLogProxy(ctp);
clp.move();
System.out.println("---------------");
CarLogProxy clp2=new CarLogProxy(car);
CarTimeProxy ctp2=new CarTimeProxy(clp2);
ctp2.move();
}
}
输出:
日志开始....
汽车开始行驶....
汽车行驶中...
汽车行驶结束...汽车行驶时间为:967毫秒!
日志结束...
---------------
汽车开始行驶....
日志开始....
汽车行驶中...
日志结束...
汽车行驶结束...汽车行驶时间为:27毫秒!
2.3 了解JDK动态代理
public interface Movable { //被代理接口
public void move();
}
import java.util.Random;
public class Car implements Movable { //被代理类
public void move() {
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target=target;
}
/*
*参数:
*proxy:被代理的对象
*method:被代理对象的方法
*args:方法的参数
*返回值:Object 方法的返回值
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long starttime=System.currentTimeMillis();
System.out.println("汽车开始行驶....");
method.invoke(target);
long endtime=System.currentTimeMillis();
System.out.println("汽车行驶结束...汽车行驶时间为:"+(endtime-starttime)+"毫秒!");
return null;
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.sql.Time;
public class test { //调用Proxy的静态方法,创建一个代理类
public static void main(String[] args) {
Car car=new Car();
InvocationHandler h=new TimeHandler(car);
InvocationHandler l=new LogHandler(car);
Class<?> cls=car.getClass();
/*
* loader:类加载器
* interface:实现接口
* h InvocationHandler
*
* 动态代理实现思路
* 实现功能:通过Proxy类的NewProxyInstance方法返回代理对象
* 1.声明一段源码(动态产生代理)
* 2.编译源码(JDK Compiler API),产生新的类(代理类)
* 3.将这个类load到内存当中,产生一个新的对象(代理对象)
* 4.return 代理对象
*/
Movable m=(Movable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
m.move();
System.out.println("-----------------------------");
Movable m2=(Movable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), l);
m2.move();
}
}
输出:
汽车开始行驶....
汽车行驶中...
汽车行驶结束...汽车行驶时间为:168毫秒!
2.4 使用cglib动态产生代理
public class Train {
public void move() {
System.out.println("火车行驶中....");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor {
private Enhancer enhance=new Enhancer();
//得到代理类
public Object getProxy(Class clazz) {
//设置创建子类的类
enhance.setSuperclass(clazz);
enhance.setCallback(this);
return enhance.create();
}
/*
* 拦截所有目标类方法的调用
* obj 目标类的实例
* m 目标方法的反射对象
* args 方法的参数
* proxy 代理类的实例
*/
public Object intercept(Object obj, Method m, Object[] args,
MethodProxy proxy) throws Throwable {
//代理类调用父类的方法
System.out.println("日志开始...");
proxy.invokeSuper(obj, args);
System.out.println("结束日志...");
return null;
}
}
输出:
日志开始...
火车行驶中....
结束日志...
3. 自定义类模拟JDK动态代理的实现(视频中写了底层源码,跟不上)
3.1 模拟JDK动态代理实现思路分析及简单实现
3.2 完善动态代理实现
3.3 动态代理实现添加InvocationHandler
4. 代理模式总结