静态代理和动态代理

目录

一、什么是代理模式

二、静态代理

1、什么是静态代理

2、静态代理的工作原理

3、静态代理的特点

4、静态代理的应用场景

5、实例代码

三、动态代理

1、什么是动态代理

2、动态代理的工作原理

3、动态代理的特点

4、动态代理的应用场景

5、代码示例


一、什么是代理模式

        代理模式是一种结构型设计模式,它为目标对象提供一种代理,用来控制对目标对象的访问。代理对象在客户端和目标对象之间起到中介的作用。客户端通过代理对象间接地访问目标对象,而不需要直接与目标对象进行交互。可以在不改变目标对象内容的前提下,通过代理对象扩展目标对象的行为逻辑;

        根据代理创建的时期,代理模式可以分为:

  • 静态代理:以硬编码的方式,手动定义创建的代理类;
  • 动态代理:代理类是在运行时动态创建的,在DK的核心类库中,可以使用 Java.lang.reflect.Proxy 类和 InvocationHandler 接来生成动态代理;

        代理模式的应用场景

  • 在 myBatis 框架中,运行期间,为每个Mapper接口都会产生一个动态代理,完成映射 SQL 的数据库操作执行;
  • 在 spring 框架中AOP 面向切面编程是基于动态代理实现;

二、静态代理

1、什么是静态代理

        代理对象与目标对象一起实现相同的接口或者继承相同父类,由程序员创建或特定工具自动生成源代码,即在编译时就已经确定了接口,目标类,代理类等。在程序运行之前,代理类的 .class 文件就已经生成。你可以简单认为代理对象写死持有目标对象。

        静态代理是指在编译时就已经确定了代理对象和目标对象的关系,代理类是通过手动编写代码来实现的。在静态代理中,代理类和目标类都实现相同的接口,代理类持有目标对象,并在方法调用前后进行额外的操作。

2、静态代理的工作原理
  • 定义一个接口(或抽象类)作为目标接口,目标对象实现这个接口。
  • 创建一个代理类,实现目标接口,并持有目标对象的引用。
  • 在代理类中重写目标接口的方法,在方法调用前后执行需要的额外操作。
  • 客户端使用代理对象来访问目标对象。

3、静态代理的特点
  • 需要手动编写代理类,工作量较大。
  • 目标对象必须实现接口。
  • 代理类和目标类的关系在编译时就确定了,无法动态改变。

4、静态代理的应用场景
  • 安全控制:代理类可以在调用目标方法前进行权限检查等安全控制。
  • 远程调用:代理类可以封装网络通信相关的细节,使得调用远程方法就像调用本地方法一样简单。
  • 性能监控:代理类可以收集方法的执行时间、调用次数等信息,用于性能监控和统计分析。

5、实例代码

        首先定义一个业务接口

public interface UserService {
	public void select();
	public void update();
}

        然后定义一个该接口的实现类

public class UserServiceImpl implements UserService {

	@Override
	public void select() {
		System.out.println("查询 selectById");
	}

	@Override
	public void update() {
		System.out.println("更新 update");	
	}

}

        然后手动创建一个静态代理类

// 代理
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();
	}

}

        首先这个代理类也实现了业务接口,所以它跟实现类一样要定义接口中的所有方法,它在调用完业务方法后又增加了一些自定义的逻辑。代理类中包含了一个 UserServiceImpl 的实例,realUserService,即被代理的真实业务类。代理类通过它来执行真实的业务逻辑。

        然后重写select()方法,在这个方法中调用真正的业务逻辑,并且在前后添加自定义的逻辑计算耗时,最后打印出来。update()调用 realUserService 的 update 方法,update 方法的代理没有做任何增强,只是简单地传递调用。

        最后在测试类中进行测试:

public interface Test01 {
	public static void main(String[] args) {
		UserServiceProxy userServiceProxy = new UserServiceProxy();
		userServiceProxy.select();
		userServiceProxy.update();
	}
}

        创建一个代理工厂对象,调用两个方法执行传递调用执行。

三、动态代理

1、什么是动态代理

        动态代理是指在运行时生成代理对象,而无需手动编写代理类。Java的动态代理机制是基于反射实现的,通过使用java.lang.reflect.Proxy类java.lang.reflect.InvocationHandler接口来实现动态代理。

        在动态代理中,代理类的创建和方法调用都是在运行时完成的。代理对象是在内存中动态创建的,并实现了目标对象的接口,同时持有目标对象的引用。在方法调用时,代理对象通过调用InvocationHandler接口中的方法来处理请求,可以在方法调用前后执行额外的操作。

2、动态代理的工作原理
  • 定义一个接口,作为目标接口。
  • 创建一个InvocationHandler接口的实现类,该类负责处理方法调用并执行额外的操作。
  • 使用Proxy类的静态方法newProxyInstance()生成代理对象,同时指定目标对象和InvocationHandler
  • 客户端使用代理对象来访问目标对象的方法。

3、动态代理的特点
  • 不需要手动编写代理类,代理对象在运行时动态生成。
  • 目标对象可以不实现接口,只需定义目标对象的共同接口。
  • 代理对象和目标对象的关系在运行时确定,可以动态改变。

4、动态代理的应用场景
  • AOP(面向切面编程):动态代理可以在目标方法执行前后执行额外的操作,如权限检查、事务管理等。它是实现AOP的一种常见方式。
  • 延迟加载:动态代理可以在目标方法被调用时才进行加载和初始化,实现延迟加载的效果。
  • 日志记录:动态代理可以在目标方法执行前后记录日志信息。

5、代码示例

        首先定义了一个业务接口

public interface UserService {
	public void select();
	public void update();
	public void createUser(int age,String name);
}

        然后定义了一个该接口的实现类

public class UserServiceImpl implements UserService {

	@Override
	public void select() {
		System.out.println("查询 selectById");
	}

	@Override
	public void update() {
		System.out.println("更新 update");
	}

	@Override
	public void createUser(int age, String name) {
		System.out.println("学生姓名:" + name + ",学生年龄:" + age);

	}

}

        然后创建一个用于监听方法测试性能的Handler执行器

// 用于监听方法测试性能的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;
		
	}

}

        首先 PerformanceInvocationHandler 实现了 InvocationHandler 接口,这个接口是用于实现动态代理的核心接口。动态代理允许在运行时生成代理类,并在代理类中执行一些额外的逻辑,例如性能监控、日志记录等。

        PerformanceInvocationHandler 持有一个 Object 类型的引用 real,这是被代理的真实业务对象。也就是用于传入咱们刚才定义的实现类。通过构造方法将实际业务对象传递给 PerformanceInvocationHandler,以便在代理对象中调用真实的业务逻辑。

        然后是invoke方法,invoke 方法是 InvocationHandler 接口的核心方法。每当代理对象调用某个方法时,都会触发 invoke 方法的执行。其中三个参数分别代表的是 proxy 是代理对象,method 是当前调用的方法对象,args 是传递给该方法的参数。

        记录方法开始执行时的时间,然后通过使用反射调用 real 对象的实际方法(也就是刚才定义的实现类)。method.invoke(real, args) 会执行 real (实现类)对象中与 method 对应的方法,传递参数 args,并返回该方法的执行结果。相当于是调用real.method(args)。这是代理模式的核心部分,代理对象通过反射调用真实业务对象的方法。

        最后记录执行后的时间然后输出,返回方法的执行结果。

        最后定义一个测试类用于测试动态代理:

public class Test01 {
	public static void main(String[] args) {
		// 真实主题对象
		UserServiceImpl realUserService = new UserServiceImpl();
		
		// 获取类加载器
		ClassLoader classLoader = realUserService.getClass().getClassLoader();
		
		// 接口列表
		Class[] interfaces = realUserService.getClass().getInterfaces();
		
		// 创建InvocationHandler对象(动态代理的执行逻辑)
		PerformanceInvocationHandler h = new PerformanceInvocationHandler(realUserService);
		
		// 创建一个代理对象(动态代理对象)
		UserService userServiceProxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, h);
		
		// 调用方法
		userServiceProxy.createUser(18, "张睿泽");;
	}
}

        首先创建真实主题对象,然后创建类加载器(classLoader)用于加载动态代理类。动态代理类是在运行时生成的,使用的类加载器通常与真实业务对象相同

        interfaces 是真实业务对象实现的接口列表。动态代理需要这些接口来创建代理对象,因为代理对象会实现这些接口并代理其方法调用

        然后是创建一个InvocationHandler对象,PerformanceInvocationHandler 是一个 InvocationHandler 的实现类,用于定义代理对象的执行逻辑。h 是 PerformanceInvocationHandler 的实例,持有 realUserService,即真实业务对象的引用。当代理对象调用方法时,实际会调用 h.invoke() 方法,这样可以在调用真实方法前后添加一些逻辑(如性能监控)。

        创建动态代理对象,Proxy.newProxyInstance()方法用于创建动态代理对象。这里面的参数分别为:

  • classLoader:类加载器,用于加载代理类。
  • interfaces:代理对象实现的接口列表。
  • h:InvocationHandler 实现,用于定义代理对象的执行逻辑。

        userServiceProxy 是动态代理对象,它实现了 UserService 接口,并代理 UserServiceImpl 的方法调用。

        最后调用了createUser()有参方法,实际上会触发 PerformanceInvocationHandler 的 invoke 方法。在invoke方法中调用的是真实的UserServiceImpl的createUser方法。

        至此,动态代理步骤实现完成。

  • 18
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值