代理的概念与作用
生活中的代理商就体现了代理的概念。武汉人从武汉的代理商手中买联想电脑和直接跑到北京联想总部买电脑,你觉得最终的主体业务目标有什么区别吗?基本上一样吧,都解决了核心问题,但是,一点区别都没有吗?从代理商哪里买真的一点好处都没有吗?代理商的批发和运输优势,比自己直接到北京总部买成本要低吧
编程中的代理能做什么呢?
对一个类进行代理,可以对类进行功能的扩展,比如日志、事务、安全等额外的功能
静态代理
代理模式一般涉及到的角色有
抽象角色:声明目标对象和代理对象的共同角色
代理角色:代理对象内部含有对目标对象的引用,同时代理对象提供与目标对象相同的接口以便在任何时刻都能代替目标对象。同时,代理对象可以附加其他操作
目标角色:代理角色所代表的真实角色
/**
静态代理演示
*/
//目标角色和代理角色共同实现的接口(基础功能)
interface Subject
{
void sayHello();
}
//目标角色(联想北京总部)
class RealSubject implements Subject
{
public void sayHello()
{
System.out.println("hello");
}
}
//代理角色(本地代理商)
class ProxySubject implements Subject
{
private RealSubject realSubject = null;
ProxySubject()
{
if(null == realSubject)
{
realSubject = new RealSubject();
}
}
public void sayHello()
{
long begTime = System.currentTimeMillis();
realSubject.sayHello();
long endTime = System.currentTimeMillis();
System.out.println("used Time :" + (endTime - begTime));
}
}
//测试
class ProxyTest
{
public static void main(String[] args)
{
Subject sub = new ProxySubject();
sub.sayHello();
}
}
静态代理的弊端:
为各种类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情,写成百上千个代理类,是不是太麻烦
所以有了动态代理解决方案,JVM可以在运行时动态生成类的代理类,即动态代理类
动态代理
动态代理类并不是事先写好的类,而是JVM运行时,动态生成了代理类
Proxy
可以生成动态代理类
Constructor:
protected Proxy(InvocationHandler h) //接收一个InvocationHandler对象
Method:
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) //获取动态代理类的字节码,指定一个类加载器(一般和目标类的类加载器相同),指定要实现的接口(和目标类实现相同的接口,从而产生的动态代理类和目标类具有相同的方法)
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) //直接生成动态代理类对象,常用。猜想是想先获取动态代理类的字节码,然后通过反射产生对象(Proxy只有一个带参的构造函数)
InvocationHandler
InvocationHandler是一个接口,且只有一个invoke方法:
Object invoke(Object proxy, Method method, Object[] args) //当运行动态代理类中的方法时,实际就是执行了动态代理类中的InvocationHandler的invoke方法:在proxy代理类上执行method,method需要的参数是args
import java.util.*;
import java.lang.reflect.*;
/**
直接创建动态代理类对象
*/
class ProxyTest2
{
public static void main(String[] args)
{
//目标类(联想北京总部)是ArrayList,final修饰的原因是:target在匿名InvocationHandler实现类中用到了
final ArrayList target = new ArrayList();
//一步创建动态代理对象(本地代理商)
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(), //动态代理类的类加载器(设置和目标类的类加载器相同)
target.getClass().getInterfaces(), //动态代理类要实现的接口(和目标类实现的接口相同)
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Object retVal = null;
System.out.println("方法前的额外功能");
try
{
retVal = method.invoke(target, args);
}
catch(Exception e)
{
System.out.println("catch块中也可以增加额功能");
}
System.out.println("方法后的额外功能");
return retVal;
}
});
//动态代理类与ArrayList实现了相同的接口
Collection alProxy = (Collection)proxy;
alProxy.add("aaa");
alProxy.add("bbb");
alProxy.add("ccc");
System.out.println(alProxy.size());
}
}
创建动态代理的通用方法
import java.util.*;
import java.lang.reflect.*;
/**
创建动态代理的通用方法
*/
class ProxyTest
{
public static void main(String[] args) throws Exception
{
ArrayList target = new ArrayList();
MyAdvice myAdvice = new MyAdvice();
Collection proxy = (Collection)getProxy(target, myAdvice);
proxy.add("aaaa");
proxy.add("bbbb");
proxy.add("cccc");
System.out.println(proxy.size());
}
//获取动态代理对象,传入目标和Advice实现类
public static Object getProxy(final Object target, final Advice myAdvice)
{
//产生动态代理类
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(), //类加载器与被代理类相同
target.getClass().getInterfaces(), //实现的接口与被代理类相同
new InvocationHandler(){ //InvocationHandler实现类
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Exception
{
myAdvice.beforeMethod(method);
//从被代理的类(target)上执行方法
Object retVal = method.invoke(target, args);
myAdvice.afterMethod(method);
return retVal;
}
});
return proxy;
}
}
import java.lang.reflect.*;
/**
通常具备的方法:
方法执行前、方法执行后、catch块内
*/
interface Advice
{
//void beforeMethod(Method method, Object[] args),不只可以接受method,还可以接收args
void beforeMethod(Method method);
void afterMethod(Method method);
}
import java.lang.reflect.*;
/**
Advice实现类
*/
class MyAdvice implements Advice
{
long begTime = 0;
long endTime = 0;
public void beforeMethod(Method method)
{
begTime = System.currentTimeMillis();
}
public void afterMethod(Method method)
{
endTime = System.currentTimeMillis();
System.out.println(method.getName() + "方法用时:" + (endTime - begTime) + "毫秒");
}
}
---------------------- ASP.Net+Android+IOS开发</a>、 .Net培训、期待与您交流! ----------------------