黑马程序员__Java中的代理类

来源:互联网 发布:java mq消息队列 编辑:程序博客网 时间:2024/06/06 04:38

                                                                        ----------------------android培训、java培训、期待与您交流! ----------------------

代理类Proxy
代理类的作用:客户端调用的目标类,需要添加一些功能(如日志、异常运行时间等),但是不能修改目标类代码,这种情况用代理类来实现。
 即,用一类实现目标类中的所以方法。在方法内调用目标类中对应的方法,并在调用前或后添加上功能代码。让客户端调用代理类。
 这里,目标类必须实现了某些接口。而代理类必须实现目标类已实现的接口。
交叉业务: 系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面。就是,多个不同类中的不同方法,都实现了一些相同的功能,如安全、日志、事务等,
 这些功能代码也就是交叉代码,就像个切面切入到这些方法中。若每个类中都写相同的功能代码很麻烦,那么就使交叉业务模块化,只写一份代码。
AOP:面向方面的编程 Aspect oriented program,AOP的目标就是要使交叉业务模块化。
可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的
使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。
动态代理类:
引入:要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情!
概念:JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
特点:
1.JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
如果要为一个没有实现接口的类生成动态代理类,怎么办?---->那么可以使用CGLIB库。
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,
代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中
2.代理对象调用方法时,会委托给InvocationHandler,InvocationHandler中的invoke方法返回的值Object,就是代理对象调用方法后的结果。
   但是,并不是所有的方法都会进行委托。代理类从Object类继承的方法中,只有3个方法 hashCode、equals、toString会进行委托,其他都不。
动态代理类应用:可 生成代理和插入通告的通用方法中,将目标类对象target和新业务对象advice作为参数传入。在InvocationHandler的invoke方法中,advice调用方法来添加新业务。
Proxy中的方法:
构造方法:只有一个 protected  Proxy(InvocationHandler h);
InvocationHandler是个接口,其中只有一个方法:
Object invoke(Object proxy, Method method, Object[] args) 在代理实例上处理方法调用并返回结果。
其中,proxy是代理类的实例,method是代理对象调用的方法,args是方法传入的参数。 
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) 返回代理类的字节码文件,并向其提供类加载器和接口数组。   
loader:累加器,interfaces:目标类实现了的接口。通常累加器会定义为接口的累加器。
例如:获取Collection的代理类字节码--->Proxy.getProxyClass(Collection.class.getLoader(),Collection.class);
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) 直接获取代理类的实例
其中,loader是目标类的加载器,interfaces是目标类实现的所有接口,handler是创建代理对象时传入的参数。
获取代理类对象的三种方法:以获取Collection的代理类为例
Class clazzProxy=Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);

1.先获取动态代理类,然后创建对象。
 Constructor constructor=clazzProxy.getConstructor(InvocationHandler.class);
 class MyInvocationHandler implements InvocationHandler
 {
   public Object invoke(Object proxy,Method method,Object[] args)throws Throwable
 {
 return null;
 }
 }
 Collection proxy1=constructor.newInstance(new MyInvocationHandler());
2.Collection proxy2=constructor.newInstance(new InvocationHandler(){
  public Object invoke(Object proxy,Method method,Object[] args)throws Throwable
  {
  return null;
  }
 });
3.直接创建动态代理类对象。
 Collection proxy3=Proxy.newProxyInstance(
 Collection.class.getClassLoader(),
 new Object[]{Collection.class},
 new InvocationHandler(){
 ArrayList target=new ArrayList();//不能放入invoke方法中。这样的话,代理类每次调用方法都会创建目标类对象target。
 public Object invoke(Object proxy,Method method,Object[] args)throws Throwable
 {
 long beginTime=System.getCurrentTimeMillise();
 Object retValue=method.invoke(target,args);
 long endTime=System.getCurrentTimeMillise();
 System.out.println(method.getName()+"...run time of..."+(endTime-beginTime));
 return retValue;
 }
 });
 proxy3.add("adsg");
 proxy3.size();

可  生成代理和插入通告的通用方法
ArrayList target=new ArrayList();
Advice advice = new MyAdvice();
//代理类对象只能转换成接口
Collection proxyArr=(Collection)getProxy(target,advice);
proxyArr.size();


private static Object getProxy(final Object target,final Advice advice) {
Object proxy=Proxy.newProxyInstance(
target.getClass().getClassLoader(), 
target.getClass().getInterfaces(), 
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
advice.beforeMethod(method);
Object retVal=method.invoke(target,args);
advice.afterMethod(method);
return retVal;
}
});
return proxy;
}
public class MyAdvice implements Advice {
private long beginTime;
public void beforeMethod(Method method) {
beginTime=System.currentTimeMillis();
}
public void afterMethod(Method method) {
long endTime=System.currentTimeMillis();
System.out.println(method.getName()+" running time of "+(endTime-beginTime));
}
}  

                                                                  ----------------------详细请查看:http://edu.csdn.net/heima---------------------------------------

原创粉丝点击