静态代理模式和JDk提供的动态代理类java.lang.reflect.Proxy

本文探讨了代理模式在Java中的应用,包括静态代理模式的实现,以及利用`java.lang.reflect.Proxy`实现的动态代理机制。通过代理模式,可以在不修改原对象的情况下,增加额外的功能或控制对目标对象的访问。

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

代理模式

代理模式是设计模式中的一种,可以在不修改方法本身,在方法调用前后添加一些额外的功能。比如:在操作数据库表方法的前后添加事务功能、在请求action方法前后添加编码设置、在调用方法之前添加日志输出功能。代理模式中分为三个角色:使用者、代理对象和目标对象。代理模式分为两类:静态代理和动态代理。代理模式的特点:1,使用者通过代理类的实例来调用目标对象上的方法。2,代理类和目标对象都实现相同的接口或者继承相同的类。

静态代理模式

我们用静态代理模式实现在方法操作数据库方法前后添加事务操作。工程包结构如下:

代理类和目标对象需要共通实现的接口。
package proxy;

public interface IUserDao {
	int save();
}

目标对象类。
package proxy;

public class UserDaoImpl implements IUserDao {

	@Override
	public int save() {
		System.out.println("保存User信息.");
		return 66;
	}

}

代理类。
package proxy.staticproxy;

import proxy.IUserDao;

public class UserProxy implements IUserDao {

	private Object target;

	public UserProxy(Object target) {
		this.target = target;
	}

	@Override
	public int save() {
		int c = 0;
		System.out.println("开始事务");
		c = ((IUserDao) target).save();
		System.out.println("关闭事务");
		return c;
	}

}

使用者。
package proxy;

import java.lang.reflect.Proxy;

import proxy.dynamic.ProxyFactory;
import proxy.dynamic.TransactionFroxy;
import proxy.staticproxy.UserProxy;

public class Test {
	public static void main(String[] args) {
		/*
		 * 静态代理
		 * 调用者通过代理类来调用目标对象。这样可以在不修改目标对象的情况下对已有目标功能进行扩展。例如本事例在执行save(),在执行数据库操作前后开启事务功能。
		 * 静态代理模式要求代理类和目标类必须实现相同的接口,这样就存在一个两个明显的缺点:
		 * 1,添加一个目标类就要添加一个相应的代理类。
		 * 2,目标类实现的接口发生改动(如增加了方法或修改了参数)需要修改相应的代理类。
		 * 优点:
		 * 一个目标对象对应一个代理类在编译期就确定了,提高了运行效率和代码的可读性。
		 * 
		 */
		IUserDao userDao = new UserDaoImpl();		//目标对象
		IUserDao userProxy = new UserProxy(userDao);	//目标对象的代理类实例
		userProxy.save();				//通过代理类实例调用save方法
		
		
	}
}

动态代理模式

可以看到静态代理模式存在明显的的却点,主要就是一个目标对象要对于一个具体的代理类。动态代理模式利用java.lang.reflect.Proxy来在运行时动态的创建代理类,一个目标对象不再编译期就确定对于的代理类,而是在运行时动态创建相应的代理类。了解反射技术的动态代理就很好理解了。Proxy类API参加下一节。
IUserDao接口和UserDaoImpl类参加上一节。

TransactionFroxy类是一个事务的代理类。注意这个事务代理类可以给所有Dao类中的操作数据库方法添加事务功能。比如:我们有ADao和BDao.....,如果是静态代理需要创建ADaoProxy、BDaoProxyProxy......相应的代理类,动态代理只需要创建一个事务代理类,就可以给ADao、BDao.....中访问数据库的方法添加事务功能。
package proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class TransactionFroxy implements InvocationHandler {
	private Object target;

	public TransactionFroxy(Object target) {
		this.target = target;
	}
	
	public Object create(){
		Object obj = null;
		obj = java.lang.reflect.Proxy.newProxyInstance(this.target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
		return obj;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("开始事务。");
		int c = (Integer) method.invoke(target, args);
		System.out.println("结束事务。");
		return c;
	}

}
使用者
package proxy;

import java.lang.reflect.Proxy;

import proxy.dynamic.ProxyFactory;
import proxy.dynamic.TransactionFroxy;
import proxy.staticproxy.UserProxy;

public class Test {
	public static void main(String[] args) {
		
		/*
		 * 动态代理
		 * 动态代理就是为了解决静态代理的两个缺点。动态代理通过JDK内置的java.lang.reflect.Proxy类在运行时动态生产一个代理类,不必为每个目标对象创建一个代理类
		 * 动态代理是动态生成目标对象的代理类,所以运行效率和可读性会差一些。
		 * 
		 */
		TransactionFroxy tranFroxy = new TransactionFroxy(userDao);
		userProxy = (IUserDao) tranFroxy.create();
		userProxy.save();
		
		// 通过Proxy类生产的动态代理类都继承了Proxy类本身。返回结果:true
		System.out.println(userProxy instanceof java.lang.reflect.Proxy);
		// 返回指定代理类对应的处理程序。返回结果:true
		System.out.println(Proxy.getInvocationHandler(userProxy) instanceof TransactionFroxy);
		// 是否是通过Proxy.newProxyInstance和Proxy.getProxyClass创建的代理类
		System.out.println(Proxy.isProxyClass(userProxy.getClass()));
		
	}
}

java.lang.reflect.Proxy

Proxy提供创建代理类和实例的静态方法,Proxy还是由这些静态方法创建的代理类的超类。还有一个需要注意的地方,Proxy只能根据接口创建代理了,不能根据类创建代理类。

1、Proxy类的字段
protected  InvocationHandler h;

所有由Proxy生成的代理类都默认的继承了Proxy类,h字段代表代理类对应的调用处理成功。在上一节给出的事例中调用处理程序就是TransactionFroxy类。

2、Proxy构造方法
protected Proxy(InvocationHandler h)
生产的动态代理类调用,并传入调用处理程序。

3、getInvocationHandler
public static InvocationHandler getInvocationHandler(Object proxy)
返回指定代理类的处理程序。

4、isProxyClass
public static boolean isProxyClass(Class<?> cl)
是否是通过Proxy.newProxyInstance和Proxy.getProxyClass创建的代理类

5、getProxyClass
public static Class<?> getProxyClass(ClassLoader loader,
                                     Class<?>... interfaces)
获取动态代理类的Class对象,通过获取的Class对象就可以创建代理类对象。代码如下:
	public static Object crateProxy1(Object target, InvocationHandler h) {
		Object obj = null;
		
		Class proxyCls = Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces());
		try {
			obj = proxyCls.getConstructor(InvocationHandler.class).newInstance(h);
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return obj;
	}

6、newProxyInstance
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
创建代理类实例。newProxyInstance可以看作是对getProxyClass进一步的封装。
	public static Object crateProxy(Object target, InvocationHandler h) {
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), h);
	}

参考文章:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值