一、代理模式
代理模式:给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。
代理模式角色分为 3种:
Subject(抽象主题角色):定义代理类和真实主题的公共对外方法,通常被设计成接口;
RealSubject(真实主题角色):真正实现业务逻辑的类;
Proxy(代理主题角色):用来代理和封装真实主题;
代理模式的结构比较简单,其核心是代理类,为了让客户端能够一致性地对待真实对象和代理对象,在代理模式中引入了抽象层。
如果根据字节码的创建时机来分类,可以分为静态代理和动态代理:
所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运
行前就确定了。
而动态代理的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代
理类的字节码文件
1.1静态代理
静态代理的工作原理如下:
- 定义一个接口(或抽象类)作为目标接口,目标对象实现这个接口。
- 创建一个代理类,实现目标接口,并持有目标对象的引用。
- 在代理类中重写目标接口的方法,在方法调用前后执行需要的额外操作。
- 客户端使用代理对象来访问目标对象。
代码例子:
静态代理通过 UserServiceProxy实现,代理类同时也需要实现UserService 接口。
UserService:
public interface UserService {public void select(); public void update();
}
UserServiceImpl:
//RealSubject 真实主题(真正的业务类)
public class UserServiceImpl implements UserService{@Overridepublic void select() {System.out.println("查询selectById"); }@Overridepublic void update() {System.out.println("更新update");}}
UserServiceProxy:
//代理
public class UserServiceProxy implements UserService{//包含Subject真实的主题private UserServiceImpl realUserService =new UserServiceImpl();@Overridepublic void select() {long begin=System.currentTimeMillis(); //调用真正的业务逻辑realUserService.select();long end=System.currentTimeMillis();System.out.println("select()执行耗时"+(end-begin)+"毫秒!");}@Overridepublic void update() {realUserService.update(); }
}
测试:
public class Test {public static void main(String[] args) {UserServiceProxy userServiceProxy=new UserServiceProxy();userServiceProxy.select();}
}
通过静态代理,我们达到了功能增强的目的,而且没有侵入原代码,这是静态代理的一个优点。
虽然静态代理实现简单,且不侵入原代码,但是,当场景稍微复杂一些的时候,静态代理的缺点也
会暴露出来。
当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式:
- 只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大
- 新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类
当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护
静态代理的特点:
需要手动编写代理类,工作量较大。
目标对象必须实现接口。
代理类和目标类的关系在编译时就确定了,无法动态改变
1.2动态代理
Java 中两种常见的动态代理方式: JDK 原生动态代理和 CGLIB 动态代理(第三方开源类
库)。
动态代理的工作原理如下:
定义一个接口,作为目标接口。
创建一个InvocationHandler接口的实现类,该类负责处理方法调用并执行额外的操作。
使用Proxy类的静态方法newProxyInstance()生成代理对象,同时指定目标对象和InvocationHandler。
客户端使用代理对象来访问目标对象的方法。
代码例子如下:
OrderService :
public interface OrderService {public void create(double money,int uid);}
OrderServiceImpl:
public class OrderServiceImpl implements OrderService {@Overridepublic void create(double money, int uid) {System.out.println("订单金额:¥"+money);System.out.println("订单id:"+uid);}
}
PerformanceInvocationHandler:
//用于监测方法执行性能的Handler执行器
public class PerformanceInvocationHandler implements InvocationHandler {private Object real;public PerformanceInvocationHandler(Object real) {this.real=real;} @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long begin=System.currentTimeMillis();//真实业务对象当前的执行方法(基于反射的方式)Object returnValue=method.invoke(real, args);long end=System.currentTimeMillis();System.out.println("方式执行耗时"+(end-begin)+"毫秒!");return returnValue;}
}
Test:
public class Test {public static void main(String[] args) {//真实主题对象OrderServiceImpl realOrderService=new OrderServiceImpl();//获取类加载器ClassLoader classLoader=realOrderService.getClass().getClassLoader();//接口列表Class[] interfaces=realOrderService.getClass().getInterfaces();//创建InvocationHandler对象(动态代理的执行逻辑)PerformanceInvocationHandler p=new PerformanceInvocationHandler(realOrderService);//创建一个代理对象(动态代理对象)OrderService orderServiceProxy=(OrderService)Proxy.newProxyInstance(classLoader, interfaces, p);//调用方法orderServiceProxy.create(1345, 0001); };
}
动态代理的特点:
不需要手动编写代理类,代理对象在运行时动态生成。
目标对象可以不实现接口,只需定义目标对象的共同接口。
代理对象和目标对象的关系在运行时确定,可以动态改变。