静态代理模式和JDk提供的动态代理类java.lang.reflect.Proxy

时间:2021-06-15 15:23:59

代理模式

代理模式是设计模式中的一种,可以在不修改方法本身,在方法调用前后添加一些额外的功能。比如:在操作数据库表方法的前后添加事务功能、在请求action方法前后添加编码设置、在调用方法之前添加日志输出功能。代理模式中分为三个角色:使用者、代理对象和目标对象。代理模式分为两类:静态代理和动态代理。代理模式的特点:1,使用者通过代理类的实例来调用目标对象上的方法。2,代理类和目标对象都实现相同的接口或者继承相同的类。

静态代理模式

我们用静态代理模式实现在方法操作数据库方法前后添加事务操作。工程包结构如下: 静态代理模式和JDk提供的动态代理类java.lang.reflect.Proxy
代理类和目标对象需要共通实现的接口。
package proxy;

public interface IUserDao {
int save();
}

目标对象类。
package proxy;

public class UserDaoImpl implements IUserDao {

@Override
public int save() {
System.out.println("保存User信息.");
return 66;
}

}

代理类。
package proxy.staticproxy;

import proxy.IUserDao;

public class UserProxy implements IUserDao {

private Object target;

public UserProxy(Object target) {
this.target = target;
}

@Override
public int save() {
int c = 0;
System.out.println("开始事务");
c = ((IUserDao) target).save();
System.out.println("关闭事务");
return c;
}

}

使用者。
package proxy;

import java.lang.reflect.Proxy;

import proxy.dynamic.ProxyFactory;
import proxy.dynamic.TransactionFroxy;
import proxy.staticproxy.UserProxy;

public class Test {
public static void main(String[] args) {
/*
* 静态代理
* 调用者通过代理类来调用目标对象。这样可以在不修改目标对象的情况下对已有目标功能进行扩展。例如本事例在执行save(),在执行数据库操作前后开启事务功能。
* 静态代理模式要求代理类和目标类必须实现相同的接口,这样就存在一个两个明显的缺点:
* 1,添加一个目标类就要添加一个相应的代理类。
* 2,目标类实现的接口发生改动(如增加了方法或修改了参数)需要修改相应的代理类。
* 优点:
* 一个目标对象对应一个代理类在编译期就确定了,提高了运行效率和代码的可读性。
*
*/
IUserDao userDao = new UserDaoImpl();//目标对象
IUserDao userProxy = new UserProxy(userDao);//目标对象的代理类实例
userProxy.save();//通过代理类实例调用save方法


}
}

动态代理模式

可以看到静态代理模式存在明显的的却点,主要就是一个目标对象要对于一个具体的代理类。动态代理模式利用java.lang.reflect.Proxy来在运行时动态的创建代理类,一个目标对象不再编译期就确定对于的代理类,而是在运行时动态创建相应的代理类。了解反射技术的动态代理就很好理解了。Proxy类API参加下一节。 IUserDao接口和UserDaoImpl类参加上一节。

TransactionFroxy类是一个事务的代理类。注意这个事务代理类可以给所有Dao类中的操作数据库方法添加事务功能。比如:我们有ADao和BDao.....,如果是静态代理需要创建ADaoProxy、BDaoProxyProxy......相应的代理类,动态代理只需要创建一个事务代理类,就可以给ADao、BDao.....中访问数据库的方法添加事务功能。
package proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class TransactionFroxy implements InvocationHandler {
private Object target;

public TransactionFroxy(Object target) {
this.target = target;
}

public Object create(){
Object obj = null;
obj = java.lang.reflect.Proxy.newProxyInstance(this.target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
return obj;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始事务。");
int c = (Integer) method.invoke(target, args);
System.out.println("结束事务。");
return c;
}

}
使用者
package proxy;

import java.lang.reflect.Proxy;

import proxy.dynamic.ProxyFactory;
import proxy.dynamic.TransactionFroxy;
import proxy.staticproxy.UserProxy;

public class Test {
public static void main(String[] args) {

/*
* 动态代理
* 动态代理就是为了解决静态代理的两个缺点。动态代理通过JDK内置的java.lang.reflect.Proxy类在运行时动态生产一个代理类,不必为每个目标对象创建一个代理类
* 动态代理是动态生成目标对象的代理类,所以运行效率和可读性会差一些。
*
*/
TransactionFroxy tranFroxy = new TransactionFroxy(userDao);
userProxy = (IUserDao) tranFroxy.create();
userProxy.save();

// 通过Proxy类生产的动态代理类都继承了Proxy类本身。返回结果:true
System.out.println(userProxy instanceof java.lang.reflect.Proxy);
// 返回指定代理类对应的处理程序。返回结果:true
System.out.println(Proxy.getInvocationHandler(userProxy) instanceof TransactionFroxy);
// 是否是通过Proxy.newProxyInstance和Proxy.getProxyClass创建的代理类
System.out.println(Proxy.isProxyClass(userProxy.getClass()));

}
}

java.lang.reflect.Proxy

Proxy提供创建代理类和实例的静态方法,Proxy还是由这些静态方法创建的代理类的超类。还有一个需要注意的地方,Proxy只能根据接口创建代理了,不能根据类创建代理类。

1、Proxy类的字段
protected  InvocationHandler h;

所有由Proxy生成的代理类都默认的继承了Proxy类,h字段代表代理类对应的调用处理成功。在上一节给出的事例中调用处理程序就是TransactionFroxy类。

2、Proxy构造方法
protected Proxy(InvocationHandler h)
生产的动态代理类调用,并传入调用处理程序。

3、getInvocationHandler
public static InvocationHandler getInvocationHandler(Object proxy)
返回指定代理类的处理程序。

4、isProxyClass
public static boolean isProxyClass(Class<?> cl)
是否是通过Proxy.newProxyInstance和Proxy.getProxyClass创建的代理类

5、getProxyClass
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
获取动态代理类的Class对象,通过获取的Class对象就可以创建代理类对象。代码如下:
public static Object crateProxy1(Object target, InvocationHandler h) {
Object obj = null;

Class proxyCls = Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces());
try {
obj = proxyCls.getConstructor(InvocationHandler.class).newInstance(h);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}

6、newProxyInstance
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
创建代理类实例。newProxyInstance可以看作是对getProxyClass进一步的封装。
public static Object crateProxy(Object target, InvocationHandler h) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), h);
}

参考文章:
http://www.cnblogs.com/cenyu/p/6289209.html#autoid-1-0-0 http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/builds/latest/html/zh_CN/api/java/lang/reflect/Proxy.html

http://blog.csdn.net/jiuqiyuliang/article/details/38423811