代理proxy
2015-06-11 20:21
453 查看
代理:在运行时,创建,实现特定接口的,新类
代理类的方法:
1.实现接口的所有方法
2.Object类的equals,toString,hashCode方法
需求:构造一个实现某接口的代理类的对象
思路:
1.反射中获取到类的对象后,可以通过调用newInstance()或者获取到特定Constructor后进行调用,来创建一个此类的实例对象
2.但是,接口不能实例化
3.目标:运行时定义一个新类,条件:有给定接口,方法:使用代理类。场景:void func(Class cInterface)中构造一个实现cInterface接口的对象
步骤:
1.创建一个代理类对象Proxy.newProxyInstance():
Objectproxy=Proxy.newProxyInstance(null,new Class[]{Comparable.class},handler);
类似于反射中的newInstance,但代理类的构造实例的方法是静态的,需要提供三个参数:
1).类加载器,null表示使用默认加载器
2).Class对象数组,是需要实现的接口的对象的数组
3).调用处理器
2.提供调用处理器
实现InvocationHandler接口,实现Object invoke(Object proxy,Method m,Object[] args)方法
普通类在调用某个方法时是直接调用此方法。而代理类的实例对象调用某个方法时,首先调用的是invoke方法。在invoke方法中使用反射的
m.invoke(target,args);
proxy是进行调用的代理实例,m是调用方法的对象,args是方法的参数列表
可以在invoke(...)方法中处理代码,在结尾返回时使用return m.invoke(target,args);
特点:
1.一个代理类只有一个实例域:传入newProxyInstance/getProxyClass中的调用处理器handler,所有需要处理的数据都必须存储在handler中。
2.代理类只委托Object类的equals,toString,hashCode方法,其他方法由代理类自己实现
3.JVM中生成代理类的类名以$Proxy开头
4.对特定类加载器和接口的组合,只会生成一个代理类。
5.代理类一定是public 和final的。如果代理类实现的所有接口都是public,则代理类不属于特定的包;否则所有非public接口必须属于一个包,代理类也属于这个包。
6.可以使用Proxy的static 方法isProxyClass(Class c)判断一个类是不是代理类
创建一个代理类的类的对象:
ClassproxyClass=Proxy.getProxyClass(null,new Class[]{ [interfaces] });
AOP面向方面的编程:使交叉业务模块化,将切面代码移动到原始方法的周围
代理类的每个方法会调用目标类的相同方法。并在调用方法时加上新增的功能的代码
代理类必须实现至少一个接口(JVM可以通过接口知晓代理类有哪些方法)
代理类的各个方法除了调用目标的相应方法并返回目标方法的返回值,还可以在代理方法中调用目标方法的代码的前后添加额外功能
示意代码:
Target{
voidfunc(){//…}
}
Proxy{
privateTarget t;
voidfunc(){t.func();}
}
获取代理类的类的对象
Proxy
static Class<?>getProxyClass(ClassLoader loader,Class<?>…interfaces)
类加载器可以选用和接口相同的类加载器,或者填null选择默认
Class c1=Proxy.getProxyClass(Comparable.class.getClassLoader(),Comparable.class);
Classc2=Proxy.getProxyClass(null,Runnable.class);
构造一个代理类的对象,不能直接对Class对象使用newInstance(),因为代理类没有空参数的构造函数
Object proxy=ctor.newInstance(newInvocationHandler(){
publicvoid invoke(Object proxy,Method method,Object[] args)throws Throwable{
returnnull;
}
})
直接创建动态类的实例对象
Proxy.newProxyInstance(loader,Class…interfaces,invocationHandler);
注意创建动态类对象时候应当强转成接口的类型,方便使用。否则在调用某方法时可能会因为声明类型没有对应方法而出错
代理类只把Object的equals,hashCode,toString方法委托给handler
实现InvocationHandler接口需要覆盖
Object invoke(Object proxy,Methodmethod,Object[] args){}
import java.lang.reflect.*;
import java.util.*;
interface Advice{
void beforeMethod();
void afterMethod();
void inCatch();
void beforeMethod(Object target,Method method,Object[] args);
void afterMethod(Object target,Method method,Object[] args);
void inCatch(Object target,Method method,Object[] args,Exception e);
void beforeMethod(Method method,Object[] args);
void afterMethod(Method method,Object[] args);
void inCatch(Method method,Object[] args,Exception e);
}
class AdviceAdapter implements Advice{
public void beforeMethod() {}
public void afterMethod() {}
public void inCatch() {}
public void beforeMethod(Object target, Method method, Object[] args) {}
public void afterMethod(Object target, Method method, Object[] args) {}
public void inCatch(Object target, Method method, Object[] args, Exception e) {}
public void beforeMethod(Method method, Object[] args) {}
public void afterMethod(Method method, Object[] args) {}
public void inCatch(Method method, Object[] args, Exception e) {}
}
class ShowMethodInfoAdvice extends AdviceAdapter{
private long start;
public void beforeMethod(Object target, Method method, Object[] args) {
System.out.print(target.getClass().getName()+"."+method.getName()+"(");
if(null!=args){
for(int i=0;i<args.length;++i){
System.out.print(args[i]);
if(i!=args.length-1){
System.out.print(", ");
}
}
}
System.out.println(")\tstarts at "+(start = System.currentTimeMillis()));
}
public void afterMethod(Method method, Object[] args) {
long end=System.currentTimeMillis();
System.out.println("This method ends at "+end+", cost "+(end-start));
}
}
public class ProxyTest {
public static void main(String[] args) {
TreeSet<String> al=new TreeSet<String>();
Collection c=(Collection)getProxyInstance(al,new ShowMethodInfoAdvice());
c.add("Rex");
c.add("milk");
c.add("metal");
}
public static <T,U extends Advice> Object getProxyInstance(final T target,final U advice){
Object newProxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
advice.beforeMethod(target, method, args);
Object ret = method.invoke(target, args);
advice.afterMethod(method, args);
return ret;
}
});
return newProxy;
}
/*
public static Object getProxyInstance(final Object target,final Advice advice){
Object newProxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
advice.beforeMethod(target, method, args);
Object ret = method.invoke(target, args);
advice.afterMethod(method, args);
return ret;
}
});
return newProxy;
}*/
public Object getProxyInstance(final Object target,final Advice advice,final Class ... interfaces){
return null;
}
}
代理类的方法:
1.实现接口的所有方法
2.Object类的equals,toString,hashCode方法
需求:构造一个实现某接口的代理类的对象
思路:
1.反射中获取到类的对象后,可以通过调用newInstance()或者获取到特定Constructor后进行调用,来创建一个此类的实例对象
2.但是,接口不能实例化
3.目标:运行时定义一个新类,条件:有给定接口,方法:使用代理类。场景:void func(Class cInterface)中构造一个实现cInterface接口的对象
步骤:
1.创建一个代理类对象Proxy.newProxyInstance():
Objectproxy=Proxy.newProxyInstance(null,new Class[]{Comparable.class},handler);
类似于反射中的newInstance,但代理类的构造实例的方法是静态的,需要提供三个参数:
1).类加载器,null表示使用默认加载器
2).Class对象数组,是需要实现的接口的对象的数组
3).调用处理器
2.提供调用处理器
实现InvocationHandler接口,实现Object invoke(Object proxy,Method m,Object[] args)方法
普通类在调用某个方法时是直接调用此方法。而代理类的实例对象调用某个方法时,首先调用的是invoke方法。在invoke方法中使用反射的
m.invoke(target,args);
proxy是进行调用的代理实例,m是调用方法的对象,args是方法的参数列表
可以在invoke(...)方法中处理代码,在结尾返回时使用return m.invoke(target,args);
特点:
1.一个代理类只有一个实例域:传入newProxyInstance/getProxyClass中的调用处理器handler,所有需要处理的数据都必须存储在handler中。
2.代理类只委托Object类的equals,toString,hashCode方法,其他方法由代理类自己实现
3.JVM中生成代理类的类名以$Proxy开头
4.对特定类加载器和接口的组合,只会生成一个代理类。
5.代理类一定是public 和final的。如果代理类实现的所有接口都是public,则代理类不属于特定的包;否则所有非public接口必须属于一个包,代理类也属于这个包。
6.可以使用Proxy的static 方法isProxyClass(Class c)判断一个类是不是代理类
创建一个代理类的类的对象:
ClassproxyClass=Proxy.getProxyClass(null,new Class[]{ [interfaces] });
AOP面向方面的编程:使交叉业务模块化,将切面代码移动到原始方法的周围
代理类的每个方法会调用目标类的相同方法。并在调用方法时加上新增的功能的代码
代理类必须实现至少一个接口(JVM可以通过接口知晓代理类有哪些方法)
代理类的各个方法除了调用目标的相应方法并返回目标方法的返回值,还可以在代理方法中调用目标方法的代码的前后添加额外功能
示意代码:
Target{
voidfunc(){//…}
}
Proxy{
privateTarget t;
voidfunc(){t.func();}
}
获取代理类的类的对象
Proxy
static Class<?>getProxyClass(ClassLoader loader,Class<?>…interfaces)
类加载器可以选用和接口相同的类加载器,或者填null选择默认
Class c1=Proxy.getProxyClass(Comparable.class.getClassLoader(),Comparable.class);
Classc2=Proxy.getProxyClass(null,Runnable.class);
构造一个代理类的对象,不能直接对Class对象使用newInstance(),因为代理类没有空参数的构造函数
Object proxy=ctor.newInstance(newInvocationHandler(){
publicvoid invoke(Object proxy,Method method,Object[] args)throws Throwable{
returnnull;
}
})
直接创建动态类的实例对象
Proxy.newProxyInstance(loader,Class…interfaces,invocationHandler);
注意创建动态类对象时候应当强转成接口的类型,方便使用。否则在调用某方法时可能会因为声明类型没有对应方法而出错
代理类只把Object的equals,hashCode,toString方法委托给handler
实现InvocationHandler接口需要覆盖
Object invoke(Object proxy,Methodmethod,Object[] args){}
import java.lang.reflect.*;
import java.util.*;
interface Advice{
void beforeMethod();
void afterMethod();
void inCatch();
void beforeMethod(Object target,Method method,Object[] args);
void afterMethod(Object target,Method method,Object[] args);
void inCatch(Object target,Method method,Object[] args,Exception e);
void beforeMethod(Method method,Object[] args);
void afterMethod(Method method,Object[] args);
void inCatch(Method method,Object[] args,Exception e);
}
class AdviceAdapter implements Advice{
public void beforeMethod() {}
public void afterMethod() {}
public void inCatch() {}
public void beforeMethod(Object target, Method method, Object[] args) {}
public void afterMethod(Object target, Method method, Object[] args) {}
public void inCatch(Object target, Method method, Object[] args, Exception e) {}
public void beforeMethod(Method method, Object[] args) {}
public void afterMethod(Method method, Object[] args) {}
public void inCatch(Method method, Object[] args, Exception e) {}
}
class ShowMethodInfoAdvice extends AdviceAdapter{
private long start;
public void beforeMethod(Object target, Method method, Object[] args) {
System.out.print(target.getClass().getName()+"."+method.getName()+"(");
if(null!=args){
for(int i=0;i<args.length;++i){
System.out.print(args[i]);
if(i!=args.length-1){
System.out.print(", ");
}
}
}
System.out.println(")\tstarts at "+(start = System.currentTimeMillis()));
}
public void afterMethod(Method method, Object[] args) {
long end=System.currentTimeMillis();
System.out.println("This method ends at "+end+", cost "+(end-start));
}
}
public class ProxyTest {
public static void main(String[] args) {
TreeSet<String> al=new TreeSet<String>();
Collection c=(Collection)getProxyInstance(al,new ShowMethodInfoAdvice());
c.add("Rex");
c.add("milk");
c.add("metal");
}
public static <T,U extends Advice> Object getProxyInstance(final T target,final U advice){
Object newProxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
advice.beforeMethod(target, method, args);
Object ret = method.invoke(target, args);
advice.afterMethod(method, args);
return ret;
}
});
return newProxy;
}
/*
public static Object getProxyInstance(final Object target,final Advice advice){
Object newProxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
advice.beforeMethod(target, method, args);
Object ret = method.invoke(target, args);
advice.afterMethod(method, args);
return ret;
}
});
return newProxy;
}*/
public Object getProxyInstance(final Object target,final Advice advice,final Class ... interfaces){
return null;
}
}
相关文章推荐
- QCustomPlot使用手册(四)
- Linux IO模型(6.11)
- Oracle学习(十三)之管理表空间以及数据库闪回设置
- aam中的搜索迭代
- 给surfaceview设置默认背景
- CentOS7 安装 OpenSSL 1.0.1m 和 OpenSSH 6.8p1
- 第一个maven构建
- WGS84,GCJ02, BD09坐标转换
- GIS空间分析 面状要素中轴线提取
- 存储管理器实验
- ubuntu下安装eclipse,配置jdk环境变量仍然报错
- 设置自定义input框内只能输入数字
- POJ 2104 区间第K大值(划分树做法)
- Android耳机线控详解,蓝牙耳机按钮监听(仿酷狗线控效果)
- 构建之法——典型用户和场景+软件设计与实现+用户体验
- poj1094
- C语言介绍(linux)
- 第一章:nagios 下载&安装
- 类作用域中名字查找的思考(《C++ primer》第四版P382)
- 2015年 6月11日 前端面试