代理模式之jdk动态代理

对代理模式还不懂的朋友可以先看看这篇静态代理模式:静态代理模式

动态代理是指动态的生成代理类 真实对象和接口是已经存在了的

1、动态代理和静态代理的角色是一样的;

2、动态代理的代理类是动态生成的;

动态代理分为两类,一类是基于几口的动态代理,一个是基于类的动态代理

a) 基于接口的动态代理-----jdk动态代理

b) 基于类的动态代理----cglib

4、jdk动态代理

关键的两个类: proxy类 和 invocationHandler接口

invocationHandler 是代理实例的 调用处理程序 实现的接口,

有一个方法是invoke (object proxy , Method method object [ ] args );

该方法 在代理实例上 处理方法调用 并返回结果;

proxy -- 被代理的对象;

method -- 对应的是代理实例调用的接口方法的Method实例;(被代理的方法)

args -- 方法调用所需要的参数数组

proxy 提供用于创建动态代理类和实例的静态方法

//伪代码

其中有个重要的方法 newProxyInstance(类加载器, 代理类要实现的接口,invocationHandler)

代码示例:

//出租的抽象接口
public interface Rent {
	void Rent();
}
//被代理的角色
public class Host implements Rent{
	@Override
	public void Rent() {
		System.out.println("房东要租房");
	}
}
//代理类
public class ProxyInvocationHandler implements InvocationHandler {
		private Object target;
		public void setTarget(Object target) {
			this.target = target;
		}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		seeHouse();
		Object result = method.invoke(target, args);
		fare();
		return result;	
	}
	public Object getProxy(){
		/**
		 * 利用jdk的Proxy这个类来为我们动态的生成代理类
		 * this.getClass().getClassLoader(),  通过这个本身这个类的类加载器来加载新的代理类
		 * target.getClass().getInterfaces(), 得到抽象类的接口
		 * this  需要的是InvocationHandler  而proxy这个类实现了InvocationHandler
		 */
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), 
				target.getClass().getInterfaces(), this);	
	}
	public void seeHouse(){
		System.out.println("中介带房东看房");
	}
	public void fare(){
		System.out.println("中介收取一波中介费");
	}
}
//测试类
public class Test {
	public static void main(String[] args) {
			Host host = new Host();
			ProxyInvocationHandler ih = new ProxyInvocationHandler(); 
			ih.setTarget(host);
			Rent r = (Rent)ih.getProxy();
			r.Rent();
	}
}

代码输出结果:

中介带房东看房 房东要租房 中介收取一波中介费 项目中稍作改进:

我们增加UserService和UserServiceImpl实现类;

在ProxyInvocationHandler中 我们模拟增加打印日志的功能,增加log();

public class ProxyInvocationHandler implements InvocationHandler {
		private Object target;
		public void setTarget(Object target) {
			this.target = target;
		}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		seeHouse();
		Object result = method.invoke(target, args);
		log(method.getName());
		fare();
		return result;
	}
	public Object getProxy(){
		/**
		 * 利用jdk的Proxy这个类来为我们动态的生成代理类
		 * this.getClass().getClassLoader(),  通过这个本身这个类的类加载器来加载新的代理类
		 * this.getClass().getInterfaces(),   得到实现
		 * this  需要的是InvocationHandler  而proxy这个类实现了InvocationHandler
		 */
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), 
				target.getClass().getInterfaces(), this);
		
	}
	public void log(String  MethodName){
		System.out.println("执行了:"+MethodName+"方法");
	}
	public void seeHouse(){
		System.out.println("中介带房东看房");
	}
	public void fare(){
		System.out.println("中介收取一波中介费");
	}
}

测试类改为:

public class Test {
	public static void main(String[] args) {
			UserService user = new UserServiceImpl();
			ProxyInvocationHandler ih = new ProxyInvocationHandler(); 
			ih.setTarget(user);
			UserService r = (UserService)ih.getProxy();
			r.add();
	}
}

输出结果为:

中介带房东看房
增加一名新用户
执行了:add方法
中介收取一波中介费

可以看到 打印了 执行了:add方法 这就是我们常用的SpringAOP来做日志管理的原理;

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java开发必知必会

Spring注解编程时用junit测试时,显示jdK版本过低问题,更改版本后仍然不行的解决方法

Spring注解编程时,用Junit测试时报错JDK版本过低,更换JDK版本后, 会报错不支持本JDK版本的解决方法;;;;

28230
来自专栏业余草

java打包exe程序需要注意的几个地方

这两天使用java写了一个小程序。然后想使用exe4j给打包成一个exe的程序。出现了一个启动的异常,这里分享一下使用exe4...

23130
来自专栏Java开发必知必会

java小案例-回忆经典之飞机大战游戏(附源码免费下载)

代码的编译软件:Eclipse   如果你用的也是eclipse的话  直接导入文件 就可以  ,如果不是的话,自己建一个项目,将代码copy里面就ok了.

80320
来自专栏JavaEdge

设计模式实战-策略模式(Strategy Pattern)

1.Q群【Java开发技术交流】:https://jq.qq.com/?_wv=1027&k=5UB4P1T

19830
来自专栏Java开发必知必会

黑客常用dos命令详解

https://blog.csdn.net/CSDN___LYY/article/details/77802438

42230
来自专栏业余草

关于eclipse启动时报Failed to create the Java Virtural Machine.错误的解决方案

最近媳妇在学习android的开发,我给她把环境搭好以后。在网上下载了一个最新的eclpse,在启动的时候报错:Failed to create the Jav...

11820
来自专栏Nicky's blog

JDK动态代理源码学习

继上一篇博客设计模式之代理模式学习之后http://blog.csdn.net/u014427391/article/details/75115928,本博客介...

13310
来自专栏Java开发必知必会

JDK8之后-JVM运行时数据区域

首先弄清几个概念: 1.方法区(method area)只是JVM规范中定义的一个概念,用于存储类信息、常量池、静态变量、JIT编译后的代码等数据,具体放在...

38020
来自专栏业余草

tomcat7的数据库连接池tomcatjdbc的25个优势

tomcat的JDBC连接池org.apache.tomcat.jdbc.pool更换或替代吗Apache Commons ...

16430
来自专栏Java开发必知必会

java小案例-回忆经典之像素鸟游戏(附源码免费下载)

代码的编译软件:Eclipse   如果你用的也是eclipse的话  直接导入文件 就可以  ,如果不是的话,自己建一个项目,将代码copy里面就ok了.

81920

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励