[102]技术-设计模式[代理模式]

代理模式

对于client -> server 访问模式,如果我想在client 访问 server时候多做一些工作,那么可以是用代码,交互模式就变为client-> serverProxy -> server.
其具体的java 伪代码如下:

public interface iA
{
    public void do();
}
public class RealA implement iA
{
    public void do()
   {
     //dosomething....
   }
}

public  ProxyA implement iA  //运用代理后客户端访问接口不变所以需要继承相同的接口。
{
    RealA a;
    public void do()
   {
        //create A if a is not create
       //dosomething  before .....
       a.do();
       //dosomething  after .....
   }
}

main()
{
     iA a = new ProxyA();
}

动态代理模式

现在我们知道了简单的代理模式,如果A有多个实现类,比如RealA,RealA1,RealA2,难道我要对每个RealA? 类写一个代理类嘛?且就算你写了 ProxyRealA,ProxyRealB,我们也不太好统一调用。
代理有一个目的就是client -> proxy -> server这种模式中的server 封装成一种统一调用,不用管其内部实现的复杂性。
那么我们有没有办法在程序运行时候自动生成ProxyReal呢?
其大概伪代码如下:

InvocationHanderAimpl implements  InvacationHandler
{
    /**
    * 这个方法实现就是类似ProxyA.do()方法类似的功能,在调用具体方法前后做一些处理。
*/ public Object invoke(Object proxy, Method method, Object[] args) { ... do something before invoke. method.invoke(proxy,args); .. do something after invoke. } } main() { // getProxyInstance() 为iA a = new ProxyA();动态代理版本。 // InvocationHandler 代表了该代理类具体行为,即执行方法前后如何处理。 iA dynamicProxyObj = getProxyInstance(A.class,Aimpl.class,InvocationHandler); dynamicProxyObj .do(); }

动态代理的两种具体实现

  • jdk 的版本
public class ProxyHandler implements InvocationHandler   
{   
  private Object proxied;   
     
  public ProxyHandler( Object proxied )   
  {   
    this.proxied = proxied;   
  }   
     
  public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable   
  {   
    //在转调具体目标对象之前,可以执行一些功能处理
    //转调具体目标对象的方法
    return method.invoke( proxied, args);  
    //在转调具体目标对象之后,可以执行一些功能处理
  }    
} 

main()
{
    RealA  realA= new RealA  ();   
    iA  proxiedA= (A)Proxy.newProxyInstance(A.class.getClassLoader(), 
     new Class[]{iA.class}, 
     new ProxyHandler(realA));
     iA.do();
}

这里重点注意:
1.invocationHandler的实现。
2.newProxyInstance 的方法参数,interfaces只接收接口类型,即iA.class ,不接收RealA.class

//proxy.java
    public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h){
}
  • cglib版实现
    关于cglib,从网上找到英文版的介绍:

Cglib is an open source library that capable creating and loading class files in memory during Java run time. To do that it uses Java byte-code generation library ‘asm’, which is a very low level byte code creation tool,其开源类库为:net.sf.cglib.proxy.*。

我们先看看源码如何创建Cglib代理类的

package com.thoughtworks.proxy.factory;

.......
import net.sf.cglib.core.CodeGenerationException;
import net.sf.cglib.core.DefaultNamingPolicy;
import net.sf.cglib.core.Predicate;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.InvocationHandler;
import net.sf.cglib.proxy.Proxy;
.......
public class CglibProxyFactory extends AbstractProxyFactory {
{
public  T createProxy(Invoker invoker, Class... types) {
        Class type = this.getSingleClass(types); //type =null ,说明types对象全部是接口,没有一个类
        if(type == null) {
            //全部是接口使用标准jdk的代理方式创建代理类,即proxy.newProxyInstance();
            return standardProxyFactory.createProxy(invoker, types);
        } else if(type.isPrimitive()) {
            throw new IllegalArgumentException("Cannot subclass primitive type");
        } else {
            Class[] interfaces = this.getInterfaces(types);
            Enhancer enhancer = new Enhancer();

            while(true) {
                enhancer.setSuperclass(type);
                enhancer.setInterfaces(interfaces);
                enhancer.setCallback(new CglibProxyFactory.CGLIBInvocationHandlerAdapter(invoker));

                Object proxy;
                try {
                    proxy = enhancer.create();
                    return proxy;
                } catch (CodeGenerationException var8) {
                    Throwable wrapper = var8.getCause();
                    if(wrapper != null && wrapper.getCause() instanceof SecurityException && enhancer.getNamingPolicy() != this.namingPolicy) {
                        enhancer.setNamingPolicy(this.namingPolicy);
                        continue;
                    }
                } catch (IllegalArgumentException var9) {
                    ;
                } catch (NoSuchMethodError var10) {
                    ;
                }

                proxy = this.createWithConstructor(type, enhancer);
                return proxy;
            }
        }
    }
}

其具体如何创建和使用CglibProxy可以参考博客:http://blog.csdn.net/ljphhj/article/details/20483171

两种方式的优缺点:

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理!

说在后面的话

这篇文章只是简单的介绍proxy干了一件什么事情。
从具体的技术层面还有以下疑问:
1.ClassLoader 装载的是哪个类?如果是一个接口的话类是如何加载进来的。
2.Cglib与jdk Proxy类的区别。
这两个问题以后待分析。

参考

https://stackoverflow.com/questions/10664182/what-is-the-difference-between-jdk-dynamic-proxy-and-cglib

关于cglib:
https://www.programcreek.com/java-api-examples/index.php?api=net.sf.cglib.proxy.MethodInterceptor
https://github.com/cglib/cglib/wiki/Tutorial

你可能感兴趣的