---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
一、代理的概念与作用
程序中的代理:要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如:异常处理,日志,计算方法的运行时间,事务管理等等。
编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
如果采用工厂模式和配置文件的方法进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类,还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易。
代理框架图如下:
面向方面的编程(Aspect oriented program,简称AOP),AOP的目标就是要使交叉业务模块化,这与直接在方法中编写切面代码的运行效果是一样的,如下图所示:
代理技术正好解决这种问题,代理是实现AOP功能的核心和关键技术。
动态代理技术:
- 要为系统中的各种接口增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情,写成千上百个代理类是不现实的。
- JVM可以在运行期间动态生成类的字节码,这种动态生成的类往往被用作代理类。即动态代理。
- JVM生成的动态类必须实现一个或多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理。
- CGLIB库可以动态生成一个类的子类,一个类的子类也可以用做该类的代理,所以如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
- 代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置上加上系统功能代码:
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中。
二、代码示例
例1:演示创建动态类及查看其方法列表信息
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
public class ProxyDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Class proxy=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(proxy.getName());
System.out.println("-------Constructors List ---------");
//按照以下格式输出构造函数列表,带参数
//$Proxy0
//$Proxy0(参数列表)
Constructor[] constructors=proxy.getConstructors();
for(Constructor constructor:constructors){
String name=constructor.getName();
System.out.println(name);
StringBuilder stringBuilder=new StringBuilder();
Class[] parames=constructor.getParameterTypes();
stringBuilder.append(name);
stringBuilder.append('(');
for(Class parame:parames){
stringBuilder.append(parame.getName()).append(",");
}
if(parames!=null&¶mes.length!=0)//为什么只用null判断不行呢???
stringBuilder.deleteCharAt(stringBuilder.length()-1);
stringBuilder.append(')');
System.out.println(stringBuilder.toString());
}
System.out.println("-------Methods List ---------");
//和上面的格式相同
Method[] methods=proxy.getMethods();
for(Method method:methods){
String name=method.getName();
//System.out.println(name);
StringBuilder stringBuilder=new StringBuilder();
Class[] parames=method.getParameterTypes();
stringBuilder.append(name);
stringBuilder.append('(');
for(Class parame:parames){
stringBuilder.append(parame.getName());
stringBuilder.append(",");
}
if(parames!=null&¶mes.length!=0)//为什么只用null判断不行呢???
stringBuilder.deleteCharAt(stringBuilder.length()-1);
stringBuilder.append(')');
System.out.println(stringBuilder.toString());
}
}
}
输出结果是:
例2:创建动态类的实例对象
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
public class ProxyDemo2 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Class proxy=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
Constructor constructor=proxy.getConstructor(InvocationHandler.class);
//第一种创建实例对象的方法
class MyInvocationHandler implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
Collection collection1=(Collection)constructor.newInstance(new MyInvocationHandler());
//第二种创建实例对象的方法
Collection collection2=(Collection)constructor.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});
//第三种创建实例对象的方法,直接用Proxy自带的方法,newProxyInstance()
Collection collection3=(Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(),//第一个参数:类加载器
new Class[]{Collection.class},//与目标相同的接口
new InvocationHandler() {//参数:一个对象
ArrayList target=new ArrayList();
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
Object retVal=method.invoke(target, args);//此处可以修改参数哟!
return retVal;
}
});
collection3.add("123");
collection3.add("123");
collection3.add("123");
System.out.println(collection3.size());
System.out.println(collection3.getClass().getName());//为什么返回的类名不是ArrayList?因为只有这三个hashCode,equals,toString从Object继承的方法交给Handler处理,其余的方法Proxy有处理的方式。
}
}
运行结果是:
关于以上代码的工作图:
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------