jdk动态代理使用及原理
jdk动态代理的使用
1.创建实现InvocationHandler接口的类,实现invoke(Object proxy, Method method, Object[] args)接口,其中invoke()执行的方法就为代理实例对象执行的方法。
其中proxy为代理对象,method为方法,args为方法的参数。
要想在原类方法上在进行再处理(如记录日志等),需要用构造方法把接口子类的实例传入,用method.invoke(原对象,args),则执行invoke里的函数原函数。
2.创建代理实例对象
public static <T> T getProxy(Class<T> inf){
return (T) Proxy.newProxyInstance(inf.getClassLoader(),new Class[]{inf},new ProxyInvocationHandler());
}
其中inf为借口,第一个参数为借口的类加载器,第二个参数为接口的Class数组,第三个为代理的执行体。
最后根据返回的接口代理实例对象执行相应的方法即可。
/**
* 被代理接口
*/
public interface Myinterface {
public List<Object> queryList();
public String getName();
} /**
* 代理方法,Mybatis中接口无实例类,
* 所以此处理并不是在方法执行前后加日志等处理
* 而是生成数据库操作执行体
*/
public class MapperProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//当方法名为queryList时
if (method.getName().equals("queryList")) {
List list = new ArrayList();
list.add("方法名为queryList()的代理执行结果");
list.add(2);
list.add("autumn");
return list;
}
//当放回类型为String时
if (method.getReturnType().toString().equals(String.class.toString())){
return "查询数据库返回的字符串";
}
return null;
}
} /**
* 根据接口名称获取代理实例
*/
public class SqlSession {
/**
* 获取接口代理对象实例
* @param inf 接口
* @param <T> 该接口的代理对象实例
* @return
*/
public static <T> T getMapper(Class<T> inf){
return (T)Proxy.newProxyInstance(inf.getClassLoader(),new Class[]{inf},new MapperProxy());
}
} /**
* 测试接口无子类代理对象
*/
public class Demo {
public static void main(String[] args) {
Myinterface inf = SqlSession.getMapper(Myinterface.class);
List<Object> result = inf.queryList();
System.out.println("返回结果:"+result);
System.out.println("----------------------------------------");
System.out.println("返回结果:"+inf.getName());
System.out.println("----------------------------------------");
}
}
还有一种用法是传递接口的子类实例对象,在子类的实例对象方法执行前后加上其他操作(如日志处理等),传送门。
jdk动态代理原理
jdk动态代理主要是一个构造函数newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)的原理
/**
* 车类接口
*/
public interface Moveable {
public void move();
} /**
* 车类接口具体实现类
*/
public class Car implements Moveable { @Override
public void move() {
try {
Thread.sleep(new Random().nextInt(3*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("car is running...");
}
} /**
* 模拟jdk中的InvocationHandler接口
*/
public interface InvocationHandler { public void invoke(Object o, Method m);
} /**
* 代理实例的处理方法
* 在原本的实例基础上进行增加功能
* 接口也可以无子类,直接通过接口方法名调用代理的invoke方法
*/
public class TimeHandler implements InvocationHandler { private Object target; public TimeHandler(Object target) {
super();
this.target = target;
} @Override
public void invoke(Object o, Method m) {
try {
long starttime = System.currentTimeMillis();
System.out.println("开始计时....");
m.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("计时结束,用时"
+ (endtime - starttime) + "毫秒");
} catch (Exception e) {
e.printStackTrace();
}
} } public class Proxy { /**
* 根据接口动态生成接口的子类对象并实现方法体,执行方法为h的invoke
* @param infce 被代理接口
* @param h 被代理类的方法执行体
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{
String rt = "\r\n";
String methodStr = "";
for(Method m : infce.getMethods()){
methodStr += " @Override" + rt +
" public void " + m.getName() + "() {" + rt +
" try{" + rt +
" Method md = " + infce.getName() + ".class.getMethod(\""
+ m.getName() + "\");" + rt +
" h.invoke(this,md);" +rt+
" }catch(Exception e){ e.printStackTrace();}" + rt +
" }" ;
} String str =
"package com.qy.dymanic.jdkproxycode;" + rt +
"import java.lang.reflect.Method;" + rt +
"import com.qy.dymanic.jdkproxycode.InvocationHandler;" + rt+
"public class $Proxy0 implements " + infce.getName() + " {" + rt +
" public $Proxy0(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
" private InvocationHandler h;" + rt+
methodStr + rt +
"}" ;
//产生代理类的java文件
String filename = System.getProperty("user.dir") +"/bin/com/qy/dymanic/jdkproxycode/$Proxy0.java";
File file = new File(filename);
FileUtils.writeStringToFile(file, str); //编译
//拿到编译器
JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
//文件管理者
StandardJavaFileManager fileMgr =
complier.getStandardFileManager(null, null, null);
//获取文件
Iterable units = fileMgr.getJavaFileObjects(filename);
//编译任务
CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
//进行编译
t.call();
fileMgr.close(); //load 到内存
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class c = cl.loadClass("com.qy.dymanic.jdkproxycode.$Proxy0"); Constructor ctr = c.getConstructor(InvocationHandler.class);
return ctr.newInstance(h);
} } /**
* 模拟jdk动态代理源码
* @throws Exception
*/
public static void main(String[] args) throws Exception {
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class,h);
m.move();
}
会在bin目录下生成两个文件
其中生成的$Proxy0.java代码如下,此类为动态生成的接口的代理实例类。
package com.qy.dymanic.jdkproxycode;
import java.lang.reflect.Method;
import com.qy.dymanic.jdkproxycode.InvocationHandler;
public class $Proxy0 implements com.qy.dymanic.jdkproxycode.Moveable { public $Proxy0(InvocationHandler h) {
this.h = h;
} private InvocationHandler h; @Override
public void move() {
try{
Method md = com.qy.dymanic.jdkproxycode.Moveable.class.getMethod("move");
h.invoke(this,md); //这个是重点!!!InvocationHandler调用它的invoke(代理类,方法名)
}catch(Exception e){ e.printStackTrace();} } }
jdk动态代理使用及原理的更多相关文章
- (转)细说JDK动态代理的实现原理
原文:http://blog.csdn.net/mhmyqn/article/details/48474815 关于JDK的动态代理,最为人熟知的可能要数Spring AOP的实现,默认情况下,Spr ...
- JDK动态代理的实现原理
学习JDK动态代理,从源码层次来理解其实现原理参考:http://blog.csdn.net/jiankunking/article/details/52143504
- JDK动态代理案例与原理分析
一.JDK动态代理实现案例 Person接口 package com.zhoucong.proxy.jdk; public interface Person { // 寻找真爱 void findlo ...
- jdk动态代理与cglib代理、spring aop代理实现原理
原创声明:本博客来源与本人另一博客[http://blog.csdn.net/liaohaojian/article/details/63683317]原创作品,绝非他处摘取 代理(proxy)的定义 ...
- jdk动态代理与cglib代理、spring aop代理实现原理解析
原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...
- 何为代理?jdk动态代理与cglib代理、spring Aop代理原理浅析
原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...
- 代理模式(静态代理、JDK动态代理原理分析、CGLIB动态代理)
代理模式 代理模式是设计模式之一,为一个对象提供一个替身或者占位符以控制对这个对象的访问,它给目标对象提供一个代理对象,由代理对象控制对目标对象的访问. 那么为什么要使用代理模式呢? 1.隔离,客户端 ...
- jdk动态代理与cglib代理、spring Aop代理原理-代理使用浅析
原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...
- 解析JDK动态代理实现原理
JDK动态代理使用实例 代理模式的类图如上.关于静态代理的示例网上有很多,在这里就不讲了. 因为本篇讲述要点是JDK动态代理的实现原理,直接从JDK动态代理实例开始. 首先是Subject接口类. p ...
随机推荐
- STL make_heap push_heap pop_heap sort_heap
make_heap: default (1) template <class RandomAccessIterator> void make_heap (RandomAccessItera ...
- 404 Not Found 探秘Nginx转发处理流程
一.问题描述 访问一个链接地址后报404 Not Found nginx/1.10.2 1 112.95.211.154 - - [08/Mar/2018:15:22:21 +0800] " ...
- vue-cli脚手架build目录中的webpack.base.conf.js配置文件
转载自:http://www.cnblogs.com/ye-hcj/p/7082620.html webpack.base.conf.js配置文件// 引入nodejs路径模块 var path = ...
- iOS 关于BTC 一些知识点
1.BTC 用这个网 可以校验 自己的库生成的助记词 地址 是否是合法正常的 https://iancoleman.io/bip39/ 2.知晓 BTC 钱包是否有钱 和交易记录 https://te ...
- Ubuntu14.04+caffe+cuda7.5 环境搭建以及MNIST数据集的训练与测试
Ubuntu14.04+caffe+cuda 环境搭建以及MNIST数据集的训练与测试 一.ubuntu14.04的安装: ubuntu的安装是一件十分简单的事情,这里给出一个参考教程: http:/ ...
- SiteMesh使用(2.4.2)
SiteMesh是一个网页布局和修饰的框架.我理解的是在一个母版页上引入页面各个位置的信息,从而拼接成一个页面展示出来.它定义了一个过滤器,把页面统一加上头部和底部. 我的项目是在springmvc中 ...
- 【c++ primer, 5e】函数指针
简单的示例: #include <iostream> using namespace std; int sum(int x, int y) { return x + y; } int ma ...
- U盘中了磁碟机病毒怎么办
问题: U盘在中毒了的电脑上使用后,里面的文件夹均消失了,这是因为里面的文件夹属性被改为隐藏属性.通过查看显示隐藏文件夹发现,所有隐藏了的文件夹的隐藏属性被锁定,无法通过鼠标右键查看文件夹属性的方法改 ...
- nfs挂载
安装: yum install nfs-utils rpcbind 配置共享目录:vim /etc/exports /xxx/cloudcms *(insecure,rw,async,no_root_ ...
- JAVA-JVM垃圾回收算法
哪些对象可以回收,有两种算法: 1. 引用计数算法,对象被引用计数器加1,对象被释放计数器减1.计数器为0的对象是可以被回收的. 此种方法优点:简单.缺点:会存在互相引用的两个对象,但实际这两个对象都 ...