- 浏览: 73715 次
- 性别:
- 来自: z驻马店
文章分类
最新评论
这两天没有什么工作任务,也不想去看所谓的业务,就利用闲来的时间复习一下java基础的东西吧。
下午复习了java动态代理,这里记下来。
java动态代理表面上并没有什么难的,难的是怎么去应用。
在讲动态代理之前,要问一个问题为什么要用动态代理?
考虑这样一个场景,在项目当中,我们通常有这样的需求,就是只有登陆的会员才具有下载,发表文章等权限,下载,发表文章等都对应着某些方法(如download()),在调用这些方法之前,我们都要先判断当前用户的是否有权去调用。最普通的做法是在download()中添加权限判断的代码:
download(){
权限判断.....
下载....
}
如果这样做,问题就来了,如果只有少数的几个操作需要权限判断那还行,只要挨个添加权限判断的代码就行了。但是一个项目中需要权限判断的地方海量去了,你一个个的去添加那还不累死?这个时候就要想办法减轻开发量,解决方法用两种,一种是通过过滤器(Filter),另外一种就是使用代理。
这里讲的是代理,代理又分为静态代理和动态代理,先说说静态代理:
我们提供一个代理类,该代理类拥有与目标类所要被调用的方法 相同的方法(方法签名),该代理类所生成的代理对象并含有目标对象的引用,调用代理对象的download方法时,会先判断权限,然后在调用目标对象的方法:
目标类:class TragetClass{
download(){
下载......
}
}
代理类:class ProxyClass{
TragetClass target;
download(){
权限判断......
下载......
}
}
静态代理和前面讲的常规方法有相同的弊端,就是代码量太大,有一万个目标方法,就要有一万个代理方法,太坑爹了。
不过幸好,java中利用reflect反射实现了动态代理,我们只需要写很少的代码就可以完成静态代理中一万个代理方法所实现的功能。
java动态代理用到了一个类(Proxy)和一个接口(InvocationHandler):
类Proxy.该类用于创建目标类的代理对象。
Proxy类常用的方法有:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) 该方法是一个static的方法,用于返回目标对象的代理对象。
参数loader就是加载目标类的classloader。
参数interfaces就是目标类所实现的接口。jdk动态代理是通过实现目标类所实现的接口来产生代理类并生成代理对象的。
参数handler,就是接口InvocationHandler实现类的对象,我们要自己去实现该接口,并实现其方法:
Object invoke(Object proxy, Method method, Object[] args) 。InvocationHandler用官方话说就是:是代理实例的调用处理程序 实现的接口。用我的话来说就是,代理对象调用某个方法时,就会调用handler的invoke方法,该方法中拥有目标对象的引用,而且该方法中拥有权限判断等需要在目标方法被调用之前或之后进行的操作。在该方法中,会先进行权限判断,然后再真真正正的去调用目标对象对应的方法。
要实现动态代理,首要条件是目标类是面向接口的。比如说鸭子Duck类,它实现了两个接口Brid和Animal。
public interface Animal { public void eat(); public void run(); }
public interface Bird { public void fly(); }
public class Duck implements Animal, Bird { @Override public void eat() { System.out.println("duck eat"); } @Override public void run() { System.out.println("duck run"); } @Override public void fly() { System.out.println("duck fly"); } }
目标类已经实现了,下面是动态代理的实现部分:
首先是InvocationHandler的实现类:
public class MyInvocationHandler implements InvocationHandler{ //target就是目标对象 private Object target; public void setObject(Object target) { this.target = target; } //proxy就是代理对象 //method就是对应于在代理对象上调用的接口方法的 Method 实例,调用method.invoke()方法时才真真的去调用目标类的方法 //args是要往目标方法中传入的参数,一般来源于代理对象调用方法时传入的参数 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //method.getName()可以返回要调用的目标方法的名称 System.out.println("---------------目标方法:"+method.getName()+"执行之前do some thing---------------------"); //调用目标类的目标方法,returnObj是目标方法返回的值 Object returnObj = method.invoke(target, args); System.out.println("---------------目标方法:"+method.getName()+"执行之后do some thing---------------------"); return returnObj; } }
下面是生成代理对象的方法类:
public class GetProxyObj { private Object obj; private MyInvocationHandler handler; public GetProxyObj(Object obj,MyInvocationHandler handler){ this.obj = obj; handler.setObject(obj); this.handler = handler; } //用于返回目标对象的代理类 public Class getProxyClass(){ //obj.getClass().getClassLoader() 返回目标对象的classloader // obj.getClass().getInterfaces()返回目标类所实现的接口数组 Class clazz = Proxy.getProxyClass(obj.getClass().getClassLoader(), obj.getClass().getInterfaces()); return clazz; } //用于返回目标对象的代理对象 //obj.getClass().getClassLoader() 返回目标对象的classloader // obj.getClass().getInterfaces()返回目标类所实现的接口数组 //handler就是前面介绍的InvocationHandler实现类的实例对象 public Object getProxyObject(){ return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler); } }
测试类:
public class TestUtil { @Test public void testGetObject(){ Duck duck = new Duck(); MyInvocationHandler handler = new MyInvocationHandler(); GetProxyObj obj = new GetProxyObj(duck,handler); System.out.println("代理类:"+obj.getProxyClass()); //jdk动态代理是通过实现目标类所实现的接口来生成的, //所以Proxy.newProxyInstance生成的对象只能被转换为接口类型比如Animal或Bird,而不是目标类duck Animal animal = (Animal)obj.getProxyObject(); animal.run(); Bird bird = (Bird)obj.getProxyObject(); bird.fly(); } }
输出信息:
代理类:class $Proxy4 ---------------目标方法:run执行之前do some thing--------------------- duck run ---------------目标方法:run执行之后do some thing--------------------- ---------------目标方法:fly执行之前do some thing--------------------- duck fly ---------------目标方法:fly执行之后do some thing---------------------
发表评论
-
Java RMI之HelloWorld篇(转)
2012-08-30 16:49 976Java RMI 指的是远程方法调用 (Remote Meth ... -
java获得classpath的方法(转)
2012-07-05 11:44 1013ClassLoader 提供了两个方法用于从装载的类路径中取得 ... -
javascript 两个相同的字符串,js判断却不一致
2012-04-07 18:06 4639今天做项目时遇到一个奇怪的问题,struts2+ajax,返回 ... -
debug单步调试的用法
2012-03-20 08:56 1100f5 run into 进入方法内部f6 执行下一行代码f7 ... -
dwr错误
2012-03-20 08:58 826一、dwr遇到这种错误: org.directwebremot ... -
往eclipse中导入项目
2012-03-20 08:57 39761. 怎么从svn服务器上把项目下载下来 首先新 ... -
qc错误
2012-02-07 12:37 947如果QC报出如 “在 "BEGIN-OF-STAT ... -
取表中字段值重复的一条数据
2011-12-28 17:20 984表 t_a, 有三个字段 id,name,age 有 ... -
java多线程相关
2011-12-26 09:40 706自己写的关于java多线程方面的总结和笔记 -
Dom4j使用
2011-09-29 19:37 1351先来一段网上的废话: om4j是一个Java的XML API ... -
Myeclipse选择版本时产生的错误
2011-09-26 15:49 1066当出现以下错误时,很可能是因为你原来使用的Jdk版本和后来使用 ...
相关推荐
我做java web 多年的小记,希望能打大家有用
时间和日期中常用到的几个类: java.util.Date, java.util.Calendar, java.util.GregorainCalendar, java.text.DateFormat, java.text.SimpleDateFormat
【咬人草小记,阅读附答案】 咬人草小记阅读答案.docx
linux+java+python3+numpy+stl的3d打印
流程图与控制流图课堂小记.流程图与控制流图课堂小记.流程图与控制流图课堂小记.流程图与控制流图课堂小记.流程图与控制流图课堂小记.流程图与控制流图课堂小记.流程图与控制流图课堂小记.流程图与控制流图课堂小记....
哎,虽然自己熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,做笔试题时发现有一题是关于这个的,于是花个时间整理下transient关键字的使用,涨下姿势~~~...
TCP-IP小记
很全面的,很实用的,看完提高不少,不管新手老手,都绝对有用
随笔小记.doc
python进行爬虫小记,主要用于python快速入门理解。
c语言理论知识小记
环境: Linux s12084 2.6.9-67.ELsmp #1 SMP Wed ...小记一下。以备以后参考。 boost 库做得真好。在windows 平台, linux 平台下编译都很顺利。hp aCC 也宣称对 boost 1.35 完全支持 。 全部编译是很痛苦的过程
GeoStudio学习小记
海居小记
asp.net Jmail组件使用小记
redis安全学习小记1
NULL 博文链接:https://zfwdl2005.iteye.com/blog/1308748
本草缘·种植小记
vuex使用方法,小记总结