前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java常用动态代理模式

Java常用动态代理模式

原创
作者头像
用户7999227
修改2021-10-08 15:04:34
3920
修改2021-10-08 15:04:34
举报
文章被收录于专栏:Java小王子Java小王子
动态代理有以下特点:
  1. 在运行期,通过反射机制创建一个实现了一组给定接口的新类;
  2. 在运行时生成的class,必须提供一组interface给它,然后该class就宣称它实现了这些 interface。该class的实例可以当作这些interface中的任何一个来用。但是这个Dynamic Proxy其实就是一个Proxy, 它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
  3. 动态代理也叫做:JDK代理,接口代理
  4. 接口中声明的所有方法都被转移到调用处理器(handler)一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强。

JDK中生成代理对象的API   代理类所在包:java.lang.reflect.Proxy   JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是:

代码语言:javascript
复制
    static Object newProxyInstance(ClassLoader loader, Class [] interfaces, InvocationHandler handler)

  注意该方法是在Proxy类中的静态方法,且接收的三个参数依次为:

  • ClassLoader loader:指定当前目标对象使用的类加载器,用null表示默认类加载器
  • Class [] interfaces:需要实现的接口数组
  • InvocationHandler handler:调用处理器,执行目标对象的方法时,会触发调用处理器的方法,从而把当前执行目标对象的方法作为参数传入

java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。

代码语言:javascript
复制
    // 该方法负责集中处理动态代理类上的所有方法调用。第一个参数是代理类实例,第二个参数是被调用的方法对象,第三个参数是方法参数的数组形式
    // 第三个方法是调用参数。
    Object invoke(Object proxy, Method method, Object[] args)

代码示例:

代码语言:javascript
复制
package model;

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

interface IUserDao {
	void save();
}

class UserDao implements IUserDao {
	public void save() {
		System.out.println("----已经保存数据!----");
	}
}

class ProxyFactory {
	private Object target;

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

	// 给目标对象生成代理对象,其class文件是由 JVM 在运行时动态生成
	public Object getProxyInstance() {
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("开始");
						// 执行目标对象方法,方法参数是target,表示该方法从属于target
						Object returnValue = method.invoke(target, args);
						System.out.println("提交");
						return returnValue;
					}
				});
	}
}

public class Client {
	public static void main(String[] args) {
		// 目标对象
		IUserDao target = new UserDao();
		System.out.println(target.getClass());
		// 代理对象
		IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
		System.out.println(proxy.getClass());
		proxy.save();
	}
}

输出:

代码语言:javascript
复制
class model.UserDao
class model.$Proxy0
开始
----已经保存数据!----
提交

总结:   代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 动态代理有以下特点:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档