自学内容网 自学内容网

代理模式-动态代理

一、代理模式

代理模式:给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。
代理模式角色分为 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{
@Override
public void select() {
System.out.println("查询selectById");
}
@Override
public void update() {
System.out.println("更新update");
}

}

UserServiceProxy:

//代理
public class UserServiceProxy implements UserService{

//包含Subject真实的主题
private UserServiceImpl realUserService =new UserServiceImpl();
@Override
public void select() {
long begin=System.currentTimeMillis();
//调用真正的业务逻辑
realUserService.select();
long end=System.currentTimeMillis();
System.out.println("select()执行耗时"+(end-begin)+"毫秒!");
}

@Override
public 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 {
@Override
public 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;
}
@Override
public 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);
};
}

动态代理的特点:

不需要手动编写代理类,代理对象在运行时动态生成。

目标对象可以不实现接口,只需定义目标对象的共同接口。

代理对象和目标对象的关系在运行时确定,可以动态改变。


原文地址:https://blog.csdn.net/2301_76207358/article/details/142356623

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!