java中代理模式总结

来源:互联网 发布:cog数据库官网 编辑:程序博客网 时间:2024/06/01 14:08

java代理模式用处有很多

比如用于延迟处理,hibernate中关联实体的延迟加载;

比如面向切面编程即AOP,简单的说就是想扩充一个类的功能而又不改变原始类的代码;

建议将代码运行后,再看讲解。

1、静态代理:

首先有一个类:Subject 继承了SubjectInterface 接口

public interface SubjectInterface {
public void sayHello();
}

public class Subject implements SubjectInterface {
private String hello;
@Override
public void sayHello(){
System.out.println("Hello!");
}
}

以上的类仅仅包含一个sayHello方法,此时我想在执行sayHello之前及之后做些其他事情,比如权限验证和结果处理,具体实现如下:

建立代理类:MyStaticProxy 也继承了SubjectInterface接口,并且包含了一个类型为被代理对象的字段

public class MyStaticProxy implements SubjectInterface {
private Subject subject;
public MyStaticProxy(Subject subject){
this.subject = subject;
}
public MyStaticProxy(){
}
@Override
public void sayHello() {
if(subject==null){
subject = new Subject();
}
before();
subject.sayHello();
after();
}
private void before(){
System.out.println("-----before-----");
}
private void after(){
System.out.println("-----after------");
}
}

测试一下:

public class ProxyTest1 {
public static void main(String[] args) throws Exception {
System.out.println("静态代理执行sayHello方法:");
//创建代理对象
SubjectInterface si = new MyStaticProxy();
si.sayHello();

}

}

结果如下:

-----before-----
Hello!
-----after------

在ProxyTest1类中创建代理对象时并未真正创建Subject实例,而是在执行sayHello方法时创建,这样的好处就是如果我没有用到sayHello这个方法,我就不用开销内存和时间去创建Subject实例,这就是hibernate关联实体延迟加载的底层实现,最重要的是不用更改源代码扩充了功能

这种方法有一个缺陷就是如果有很多类需要功能扩充或者进行拦截处理,我们岂不是在MyStaticProxy 类中增加很多字段和方法,没错这时就用到了动态代理

2、动态代理

继续使用Subject 类作为被代理对象

创建处理类MyProxyHandler 继承InvocationHandler 接口

注意:此类并不是代理对象,但其里面的invoke方法是代理类最终执行的方法

该接口就只有public Object invoke(Object proxy, Method method, Object[] args);方法,用来规范我们的代码(看不懂先别急)

method是被执行的方法,args就是该方法需要的参数,proxy就是动态生成的代理对象


public class MyProxyHandler implements InvocationHandler {
private Object target;
public MyProxyHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result ;
}
private void before(){
System.out.println("-----before-----");
}
private void after(){
System.out.println("-----after------");
}

字段target是被代理的对象实例,此例中是Subject


然后我们创建一个类测试一下,继续使用ProxyTest1类:

先别看这个类,先看它下面的运行结果。

public class ProxyTest1 {
public static void main(String[] args) throws Exception {
System.out.println("静态代理执行sayHello方法:");
//创建代理对象
SubjectInterface si = new MyStaticProxy();
si.sayHello();

System.out.println("***********************************************************************************");
//创建被代理对象
SubjectInterface subject = new Subject();
//初始化代理对象
InvocationHandler handler=new MyProxyHandler(subject);
//产生代理对象
SubjectInterface ori = (SubjectInterface) Proxy.newProxyInstance(Subject.class.getClassLoader(), Subject.class.getInterfaces(), handler);
System.out.println("动态代理执行sayHello方法:");
ori.sayHello();
System.out.println("****************************************************************************************");
System.out.println("产生的代理类:");
Class temp = ori.getClass();

Method[] methods = temp.getDeclaredMethods();
System.out.print(Modifier.toString(temp.getModifiers()));
System.out.print(" class "+temp.getName()+" extends "+temp.getSuperclass().getName()+" implemtents ");
for(Class cls:temp.getInterfaces()){
System.out.print(cls.getName()+" ");
}

System.out.println("{");
System.out.println("\t//这里的m*就是被代理对象的方法实例(Method实例)");
Field[] fields = temp.getDeclaredFields();
for(Field f:fields){
System.out.print("\t"+Modifier.toString(f.getModifiers()));
System.out.print(" "+f.getType().getName());
System.out.println(" "+f.getName()+";");
Class obj = f.getType();
}
Constructor[] constructors = temp.getDeclaredConstructors();
for(Constructor c:constructors){
System.out.print("\t"+Modifier.toString(c.getModifiers()));
System.out.print(" "+c.getName()+"(");
Class[] params = c.getParameterTypes();
for(Class param:params){
System.out.print(param.getName()+" handler");
}
System.out.println("){}");
}
for(Method m:methods){
System.out.print("\t"+Modifier.toString(m.getModifiers()));
System.out.print(" "+m.getReturnType().getName());
System.out.print(" "+m.getName()+"(");
Class[] params = m.getParameterTypes();
for(Class param:params){
System.out.print(param.getName()+" param");
}
System.out.println("){}");
}
System.out.println("}");
System.out.println("//这里面的第一个参数Object proxy就是它自己,究竟为什么把它自己传递进来,我也搞不懂");
System.out.println("执行sayHello时实际执行:handler.invoke("+temp.getName()+",m*,param);");
/*public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println(proxy.getClass().getName());
before();
method.invoke(target, args);
after();
return null;
}*/
}
}


静态代理执行sayHello方法:
-----before-----
Hello!
-----after------
***********************************************************************************
动态代理执行sayHello方法:
-----before-----
Hello!
-----after------
****************************************************************************************
产生的代理类:
public final class sun.proxy.$Proxy0 extends java.lang.reflect.Proxy implemtents my_proxy.SubjectInterface {
//这里的m*就是被代理对象的方法实例(Method实例)
private static java.lang.reflect.Method m3;
private static java.lang.reflect.Method m1;
private static java.lang.reflect.Method m0;
private static java.lang.reflect.Method m2;
public sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler handler){}
public final void sayHello(){}
public final int hashCode(){}
public final boolean equals(java.lang.Object param){}
public final java.lang.String toString(){}
}
//这里面的第一个参数Object proxy就是它自己,究竟为什么把它自己传递进来,我也搞不懂
执行sayHello时实际执行:handler.invoke(sun.proxy.$Proxy0,m*,param);

红色字体就是我们调用动态代理方法的过程:

1、创建被代理对象

2、创建最终实现的类对象

3、动态创建代理对象,此时的代理对象是JVM自动创建的

4、所有执行的方法,转为执行MyProxyHandler.invoke(...)方法

Proxy.newProxyInstance(Subject.class.getClassLoader(), Subject.class.getInterfaces(), handler);就是创建了真正的代理对象

具体类就是控制台输出的结果,就是sun.proxy.$Proxy0这个奇怪的东西




0 0
原创粉丝点击