- 浏览: 170366 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
yinvent:
谢谢,终于找到一个可以用的例子!
struts2学习之一简单范例 -
锅巴49:
学习了,不错.
使用 Spring 2.5 注释驱动的 IoC 功能 -
fooky:
你好,今天在配置spring secutiry3,想让系统先从 ...
spring security 配置文件小结(逐步深化到url级别) -
lj508:
你好啊 请教你个问题
我用那个纯jsp上传时
怎么运行时根本没 ...
Sturt2学习之十二---文件上传 -
641216927:
我还是一个struts2新手。
有个问题请教一下:
同时在t ...
struts2学习之一简单范例
java语言反射与动态代理学习笔记(动态代理部分)。(学习材料张龙:“反射机制与动态代理”、jdk帮助文档、book:JAVA.2核心技术)
一、代理模式:
代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式一般涉及到的角色有
抽象角色:声明真实对象和代理对象的共同接口
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装(面向对象的三大特性(继承、多态、封装)之一:)
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
代理模式也是《设计模式》(由4个人书写很有名)中的23中模式之一。
1、程序Subject.java
// 抽象角色 abstract public class Subject { abstract public void request(); }
2、程序RealSubject.java
public class RealSubject extends Subject { public RealSubject() { } public void request() { System.out.println("From real subject."); } }
3、程序ProxySubject.java
//代理角色 public class ProxySubject extends Subject { private RealSubject realSubject; // 以真实角色作为代理角色的属性 public ProxySubject() { } public void request() // 该方法封装了真实对象的request方法 { preRequest(); if (realSubject == null) { realSubject = new RealSubject(); } realSubject.request(); // 此处执行真实对象的request方法 postRequest(); } private void preRequest() { // something you want to do before requesting } private void postRequest() { // something you want to do after requesting } }
4、程序Client.java
//客户端调用 public class Client { public static void main(String[] args) { Subject sub = new ProxySubject(); sub.request(); } }
二、另外,如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个 代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。
1、Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
(1)Interface InvocationHandler:该接口中仅定义了一个方法
public object invoke(Object obj,Method method, Object[] args)
在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。 这个抽象方法在代理类中动态实现。
(2)Dynamic Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容
protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。h是实现了 InvocationHandler 接口的对象。
static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):h是实现了 InvocationHandler 接口的对象,返回代理类的一个实例,返回后的动态代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)以下实例中的Client.java类中就是用了该方法。
(3)所谓Dynamic Proxy动态代理类是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该类的实例当作这些interface中的任何一个来用。(此处就是运用了类的动态多态性,用类的实例来赋值给该类的某个接口的意思)当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个h,由它接管实际的工作。
(4)所以在使用动态代理类时,我们必须实现接口InvocationHandler(即重写invoke方法)
程序 Subject.java
//抽象角色(之前是抽象类,此处应改为接口): public interface Subject { abstract public void request(); }
程序 RealSubject.java
//具体角色 public class RealSubject implements Subject { public RealSubject() { } public void request() { System.out.println("From real subject."); } }
程序 DynamicSubject.java
//代理处理器
/**
* 该代理类的内部属性为Object类,实际使用时通过该类的构造函数DynamicSubject(Object obj)对其赋值;
* 此外,在该类还实现了invoke方法,该方法中的 method.invoke(sub,args);
* 其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象,
* args为执行被代理对象相应操作所需的参数。
* 通过动态代理类,我们可以在调用之前或之后执行一些相关操作
*/
public class DynamicSubject implements InvocationHandler
{
private Object sub;
public DynamicSubject()
{
}
public DynamicSubject(Object obj)
{
sub = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable//该方法java会去调用,我们程序中没有调用到
{
System.out.println("before calling " + method);//可以自己写一些方法执行前操作
method.invoke(sub, args);
System.out.println("after calling " + method);//可以自己写一些方法执行后的操作!
return null;
}
}
程序 Client.java
//客户端 public class Client { static public void main(String[] args) throws Throwable { RealSubject rs = new RealSubject(); // 在这里指定被代理类 InvocationHandler ds = new DynamicSubject(rs);//生成一个上文所说的h Class<?> cls = rs.getClass(); // 以下是一次性生成代理 Subject subject = (Subject) Proxy.newProxyInstance( cls.getClassLoader(), cls.getInterfaces(), ds); subject.request();//调用过程:request--->上一行的ds------>ds会动态调运它invoke----->invoke方法内真实对象 } }
Subject subject 指的是代理类
通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系
动态代理是指客户通过代理类来调用其它对象的方法
动态代理使用场合:
a、调试
b、远程方法调用(RMI)
调运顺序:客户---->代理接口(代理)---->接口(对象)
2总结:动态代理步骤
(1).创建一个实现接口InvocationHandler的类,它必须覆写invoke方法(一般为建立一个DynamicSubjet类)
(2).创建被代理的类以及接口
(3).通过Proxy的静态方法
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)创建一个代理
(4).通过代理调用方法
3.程序实践
VectorProxy.java
public class VectorProxy implements InvocationHandler { private Object proxyobj; public VectorProxy(Object obj) { proxyobj = obj; } public static Object factory(Object obj) { Class<?> cls = obj.getClass(); return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), new VectorProxy(obj)); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before calling " + method); if (args != null) { for (int i = 0; i < args.length; i++) { System.out.println(args[i] + ""); } } Object object = method.invoke(proxyobj, args); System.out.println("after calling " + method); return object; } public static void main(String[] args) { List<String> v = (List<String>) factory(new Vector<String>(10)); v.add("New"); v.add("York"); System.out.println(v.toString); v.remove(0); System.out.println(v); } }
若修改该程序的main函数中的System.out.println(v.toString);为System.out.println(v.getClass);发现程序在执行中不会再去执行invoke方法了,而是直接打印出结果而已
为什么呢?参考jdk5.0的文档可以发现在java.lang.reflect.Proxy类中说明如下:
An invocation of the hashCode, equals, or toString methods declared in java.lang.Object on a proxy instance will be encoded and dispatched to the invocation handler's invoke method in the same manner as interface method invocations are encoded and dispatched, as described above. The declaring class of the Method object passed to invoke will be java.lang.Object. Other public methods of a proxy instance inherited from java.lang.Object are not overridden by a proxy class, so invocations of those methods behave like they do for instances of java.lang.Object.
翻译如下:
在代理实例上的 java.lang.Object 中声明的 hashCode、equals 或 toString 方法的调用将按照与编码和指派接口方法调用相同的方式进行编码,并被指派到调用处理程序的 invoke 方法,如上所述。传递到 invoke 的 Method 对象的声明类是 java.lang.Object。代理类不重写从 java.lang.Object 继承的代理实例的其他公共方法,所以这些方法的调用行为与其对 java.lang.Object 实例的操作一样。
即对于 java.lang.Object 中声明的 hashCode、equals 或 toString 方法的调用将按照invoke 方法,其他方法就像以前方法一样,正常进行,不代理。
- reflect.rar (11.8 KB)
- 下载次数: 11
发表评论
-
浅克隆和深克隆及序列化
2009-09-17 13:45 1425一、相关概念: 1、浅复制与深复制概念浅复制(浅克隆):被复 ... -
java访问权限修饰符(表格)
2009-09-17 13:29 1203做个表格以免忘记,程序中不写访问权限时默认为friendly ... -
关于排序方法的选择
2009-09-15 09:13 839package com.softeem.jbs.lesson4 ... -
java中注意点总结(二)
2009-09-14 14:11 9001、两线程程序对初始为零的非负整数,一增一减, 同时每次对变量 ... -
java中注意点总结(一)
2009-09-11 22:15 10441、关于String 语句:String s=new S ... -
java(内存、异常)2-异常机制及throw与throws的区别
2009-09-02 09:49 1541异常机制及throw与throw ... -
java编码处理
2009-04-27 16:59 1191java编码处理:(java在内存中使用的是uniocode编 ... -
java5.0新特性总结--Annotation系统学习整理笔记
2009-03-25 16:04 2686Java Annotation特性与使用 ... -
java5、0新特性学习总结
2009-03-25 13:29 1391一泛型编译时类型安全运行时更小抛出ClassCastExcep ... -
java(日期处理)
2009-03-20 17:39 2516第一部分关于JAVA的Date (参考关于JAVA的Date总 ... -
log4j
2009-03-20 11:42 804文章一 Log4j由三个重要的组件构成:日志信息的优先级,日 ... -
java(Annotation)转自quguilai
2009-03-20 11:07 1008什么是Annotation?(转自quguilai)2007- ... -
java(IO)第二部分
2009-03-20 09:26 949java(IO)第二部分 一、合并流SequenceI ... -
java(IO操作)第一部分
2009-03-19 21:19 1812java(IO操作)第一部分 --------I/O流 一、 ... -
java(内存、异常)
2009-03-19 15:17 931... -
jdk、jre、jvm及j2se安装
2009-03-05 14:03 3401jdk、jre、jvm及j2se安装 ... -
java语言反射与动态代理学习笔记1(反射部分)
2009-03-05 13:33 1689java语言反射与动态代理学习笔记(反射部分)。(学习 ...
相关推荐
java语言反射与动态代理学习笔记
java反射与动态代理
java注解和反射的个人学习笔记
Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习...
Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记
java学习笔记java学习笔记.zipjava学习笔记.zipjava学习笔记.zipjava学习笔记.zipjava学习笔记.zipjava学习笔记.zipjava学习笔记.zipjava学习笔记.zipjava学习笔记.zipjava学习笔记.zipjava学习笔记.zipjava学习笔记...
JAVA学习笔记JAVA学习笔记JAVA学习笔记JAVA学习笔记JAVA学习笔记JAVA学习笔记JAVA学习笔记JAVA学习笔记JAVA学习笔记
Java基础 java学习笔记 Java Java基础Markdown学习笔记,可转换成PDF、Word等格式
java学习笔记,java基础知识,只用于个人学习。
Java语言程序设计学习笔记,配套的md文件,查找起来方便一些
Java软件开发魔典资源库 学习笔记 Java软件开发魔典资源库 学习笔记 Java软件开发魔典资源库 学习笔记 Java软件开发魔典资源库 学习笔记 Java软件开发魔典资源库 学习笔记 Java软件开发魔典资源库 学习笔记 Java软件...
基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码.zip 基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码.zip 基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码....
java学习笔记.doc java学习笔记 java学习 学习笔记 java
java学习笔记java反射机制
在学习java过程中的笔记。
java语言学习笔记指南资源目录:【】3.Java语言Switch语句详解1.JavaSwitch语句概述【】3.Java语言Switch语句详解3.Java语言Switch语句详解课程资料源码【】3.Java语言Switch语句详解课程资料源码【】4.Java判断与...
java学习——java中的反射学习笔记
java学习笔记(非常详细的介绍Java语言)。 可快速入门,也可当手册使用。 下载后用记事本或者文本编辑器打开即可。
java学习笔记java学习笔记java学java学习笔记习笔记