Java设计模式之代理模式介绍及三种实现解析

本文介绍了代理模式的概念及其在Java中的三种实现方式:静态代理、基于JDK动态代理和Cglib代理。静态代理需要目标对象和代理对象实现相同接口,但会产生大量代理类。动态代理利用反射机制,要求目标对象实现接口。Cglib代理通过继承目标对象创建子类,适用于无接口的情况。在Spring AOP中,动态代理用于有接口的对象,Cglib代理用于无接口的对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java中的三种代理模式的介绍及解析

前言

代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式。
所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网上连接、存储器中的大对象、文件或其它昂贵或无法复制的资源。
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
在Java中,存在以下三种代理模式:

静态代理

在使用静态代理时,被代理对象与代理对象需要一起实现相同的接口或者是继承相同父类,因此要定义一个接口或抽象类.
代理类:

/*
 * 静态代理实现
 * 
 * 代理类
 */
public class DemoDAOProxy implements IDemoDAO{

	// 被代理的目标对象
	private DemoDAOImpl target = new DemoDAOImpl();
	
	@Override
	public int executeInsert() {
		long beginTime = System.currentTimeMillis();
		System.out.println("[增强功能]:executeInsert方法于" + new Date()+"开始执行....");
		
		// 调用被代理对象(target)
		int rows = target.executeInsert();
		
		long endTime = System.currentTimeMillis();
		System.out.println("[增强功能]:executeInsert方法于" + new Date()+"结束执行!!!!");
		System.out.println("[增强功能]:共耗时" + (endTime - beginTime) + "毫秒!");
		return rows;
	}

	@Override
	public int executeUpdate() {
		long beginTime = System.currentTimeMillis();
		System.out.println("[增强功能]:executeInsert方法于" + new Date()+"开始执行....");
		
		// 调用被代理对象(target)
		int rows = target.executeUpdate();
		
		long endTime = System.currentTimeMillis();
		System.out.println("[增强功能]:executeInsert方法于" + new Date()+"结束执行!!!!");
		System.out.println("[增强功能]:共耗时" + (endTime - beginTime) + "毫秒!");
		return rows;
	}
	}
	

被代理类:


/*
 * 被代理类(target)
 */
public class DemoDAOImpl implements IDemoDAO{
	@Override
	public int executeInsert() {
		System.out.println("[数据访问操作]:1.连接数据库");
		System.out.println("[数据访问操作]:2.执行Insert SQL");
		System.out.println("[数据访问操作]:3.处理结果");
		//int number = 1/0;
		return -1;
	}

	@Override
	public int executeUpdate() {
		System.out.println("[数据访问操作]:1.连接数据库");
		System.out.println("[数据访问操作]:2.执行Update SQL");
		System.out.println("[数据访问操作]:3.处理结果");
		return -1;
	}
	
	
}

接口:

public interface IDemoDAO {
	
	public int executeInsert();
	
	public int executeUpdate();
	
}

特点总结:
优点:可以实现对目标代理。
缺点:需要一一代理,所以会产生很多代理类。而且,一旦接口增加方法,所有目标对象与代理对象都需要维护。

动态代理

动态代理工厂
基于JDK的反射机制: 需要Proxy类 + 实现InvocationHandler接口

public class JdkProxyFactory implements InvocationHandler {

	// 目标对象
	private Object target;

	// 构造方法
	// 传入目标对象
	public JdkProxyFactory(Object target) {
		this.target = target;
	}

	// 创建"动态代理对象"
	public Object createProxy() {

		// 1.获取目标对象的Class对象
		Class targetClass = target.getClass();

		// 2. 通过 java.lang.reflect.Proxy 创建一个新的动态代理实例对象
		// 参数1:目标对象的Class对象的ClassLoader
		// 参数2:目标对象的实现接口(数组)
		// 参数3: InvocationHandler接口实现类(当前类)
		Object newProxy = Proxy.newProxyInstance(targetClass.getClassLoader(), 
												 targetClass.getInterfaces(), 
												 this);

		return newProxy;
	}

	/*
	 *  参数1 proxy :当前产生的代理对象
	 * 	参数2 method :目标方法 
	 * 	参数3 args : 目标方法的参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		long beginTime = System.currentTimeMillis();
		System.out.println("[增强功能]:" + method.getName() + "方法于" + new Date() + "开始执行....");
		System.out.println("[增强功能]:目标方法=>" + method);
		System.out.println("[增强功能]:方法参数=>" + Arrays.toString(args));

		// 完成目标方法的执行(反射)
		// method.invoke(目标对象,方法参数);
		Object returnVal = method.invoke(target, args);

		long endTime = System.currentTimeMillis();
		System.out.println("[增强功能]:" + method.getName() + "方法于" + new Date() + "结束执行!!!!");
		System.out.println("[增强功能]:共耗时" + (endTime - beginTime) + "毫秒!");

		return returnVal;

	}

}

特点:
通过接口实现,所以目标对象必须要有“接口”。

Cglib代理

Cglib代理代理工厂
基于Cglib的实现 : 需要Enhancer类 + 实现MethodInterceptor接口

public class CglibProxyFactory implements MethodInterceptor{
	
	// 目标对象
	private Object target;
	
	// 构造方法
	// 传入目标对象
	public CglibProxyFactory(Object target) {
		this.target = target;
	}

	// 创建动态代理对象
	public Object createProxy() {
		
		Enhancer enhancer = new Enhancer();
		
		// 传入目标对象的(Class类型)=>(父类)
		enhancer.setSuperclass(target.getClass()); 
		
		// 设置回调对象:当通过代理对象调用目标方法时,会执行回调对象的intercept()
		enhancer.setCallback(this); 
		
		// 创建动态代理对象
		Object newProxy = enhancer.create();
		return newProxy;
	}

	// 参数1 proxy:
	// 参数2 method: 目标方法
	// 参数3 args :目标方法参数
	@Override
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy arg3) throws Throwable {
		System.out.println("***********************************************");
		Object returnVal = method.invoke(target, args);
		System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
		return returnVal;
	}
}

特点:
通过继承目标类,以目标对象子类的方式实现代理,这种方法也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。

总结

在Spring的AOP编程中:

尽量不要使用静态代理。

如果加入容器的目标对象有实现接口,用JDK代理。

如果目标对象没有实现接口,用Cglib代理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值