zoukankan      html  css  js  c++  java
  • 【代理模式】

    http://www.cnblogs.com/cenyu/p/6289209.html

    http://www.jb51.net/article/86531.htm

    代理模式包括静态代理和动态代理以及Cglib代理

    静态代理和动态代理的对象都是通过new目标对象赋值给自己得来的。只是对目标对象的同名方法做了拦截拓展而已。

    组成:

    抽象角色:通过接口或抽象类声明真实角色实现的业务方法。

    代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

    真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

    代理对象可以在客户端和目标对象之间起到中介的作用以便保护目标对象并且还可以扩展目标对象的功能。

    静态代理实现:

    首先定义接口或父类,目标对象和代理对象一起实现该接口或父类,然后通过调用相同的方法来调用目标对象的方法。(代理类的构造方法其实没有创建对象,只是把引用指向了目标对象。)

    代码示例:
    接口:IUserDao.java

    /**
     * 接口
     */
    public interface IUserDao {
    
        void save();
    }

    目标对象:UserDao.java

    /**
     * 接口实现
     * 目标对象
     */
    public class UserDao implements IUserDao {
        public void save() {
            System.out.println("----已经保存数据!----");
        }
    }

    代理对象:UserDaoProxy.java

    /**
     * 代理对象,静态代理
     */
    public class UserDaoProxy implements IUserDao{
        //接收保存目标对象
        private IUserDao target;
        public UserDaoProxy(IUserDao target){
            this.target=target;
        }
    
        public void save() {
            System.out.println("开始事务...");
            target.save();//执行目标对象的方法
            System.out.println("提交事务...");
        }
    }

    测试类:App.java

    /**
     * 测试类
     */
    public class App {
        public static void main(String[] args) {
            //目标对象
            UserDao target = new UserDao();
    
            //代理对象,把目标对象传给代理对象,建立代理关系
            UserDaoProxy proxy = new UserDaoProxy(target);
    
            proxy.save();//执行的是代理的方法
        }
    }


    优点;在不修改目标对象功能前提下对目标对象进行功能扩展。
    缺点:代理对象和目标对象要实现一样的接口所以当接口/目标类方法较多时创建代理类较麻烦,每个接口中的方法都得
    实现,但其实你可能只是通过代理对象调用目标对象的一个方法而已。同时一旦接口增加方法,目标对象和代理对象都要维护。

    动态代理实现:

    动态代理模式中不需要定义代理类,代理对象的生成是利用JDK的API,动态的在内存中构建代理对象。

    使用动态代理时,我们需要在委托类和JDK的代理类之间定义一个实现了调用处理器InvocationHandler接口的中介类(实现该接口中的invoke()方法即可)。当我们调用代理对象的方法时这个调用会转送到invoke方法,代理对象也作为参数传入invoke方法。这个中介类很类似于静态代理模式中的代理类。

    package proxyModel;

    public interface God {
    public void outputTest();
    public void outputTest2();
    }

    package proxyModel;

    public class TargetObject implements God{

    @Override
    public void outputTest() {
    System.out.println("目标对象方法执行,仅此而已");
    }

    @Override
    public void outputTest2() {
    System.out.println("增加目标对象方法个数仅此而已");
    }

    }

    package proxyModel;

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

    public class InterMediateClass implements InvocationHandler{
    //中介类跟静态代理中的代理类很类似,都是把创建的目标对象赋值给自己,然后对目标方法进行拦截拓展。
    //他俩的区别是:区别1是中介类不用实现接口方法,接口改变对中介类没有影响。区别2是中介类对目标对象方法的拦截是针对所有方法的
    //调用处理器的实现类/中介的实例
    private Object object;

    //自定义有参构造函数,用于注入一个目标对象
    public InterMediateClass(TargetObject targetObject){
    this.object=targetObject;
    }
    @Override
    //对目标对象方法的拓展可以在invoke方法中实现
    //Object[] arg2表示传入invoke方法的Method的参数
    public Object invoke(Object arg0, Method arg1, Object[] arg2)
    throws Throwable {
    System.out.println("调用前的拦截拓展");
    Object result = arg1.invoke(object, arg2);
    System.out.println("调用结束后的拦截拓展");
    return result;
    }

    }

    package proxyModel;

    import java.lang.reflect.Proxy;

    public class ClientTest {
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    InterMediateClass inter = new InterMediateClass(new TargetObject());

    //创建委托接口的代理类
    God proxy = (God) (Proxy.newProxyInstance(God.class.getClassLoader(), new Class[]{God.class}, inter));//接口类加载器,接口Class类实例,中介类实例。

    // 创建数组,如果在创建的同时不初始化数组则必须指定其大小,不指定数组大小则必须在创建的同时初始化数组


    proxy.outputTest2();
    }

    }

    动态代理原理:

    Proxy类的newProxyInstance方法

    Proxy.newProxyInstance(接口的类加载器,接口的Class类实例,调用处理器的实例(其实是引用的目标类的实例))

    首先用接口加载器和接口class通过getProxyClass获得这个代理类的子类:

    byte[] arrayOfByte = ProxyGenerator.generateProxyClass((String)proxyName(代理名), interface.class(接口class));代理名和接口的class是生成的目标类文件的一切数据来源
    try
    {
    localClass1 = defineClass0(paramClassLoader(接口类加载器), (String)proxyName, arrayOfByte, 0, arrayOfByte.length);

    ProxyGenerator类

    private List<FieldInfo> fields = new ArrayList();
    private List<MethodInfo> methods = new ArrayList();

    private String className;
    private Class[] interfaces;

    generateProxyClass方法

    ProxyGenerator localProxyGenerator = new ProxyGenerator(proxyName(代理名), interface.class(接口class));

    final byte[] arrayOfByte = localProxyGenerator.generateClassFile();

    构造函数:

    private ProxyGenerator(String paramString, Class[] paramArrayOfClass)
    {

    //创建代理生成器对象时,在构造函数中将一切数据来源代理名和接口class赋值给代理生成器对象的属性。
    this.className = paramString;
    this.interfaces = paramArrayOfClass;
    }



    generateClassFile();方法

    this.methods.add(generateConstructor());

    this.methods.add(generateMethod());

    localObject1 = this.interfaces[i].getMethods();
    for (int k = 0; k < localObject1.length; k++)
    addProxyMethod(localObject1[k], this.interfaces[i]);
    }

    addProxyMethod(hashCodeMethod, Object.class);
    addProxyMethod(equalsMethod, Object.class);
    addProxyMethod(toStringMethod, Object.class);

    this.fields.add(new FieldInfo(((ProxyMethod)localObject2).methodFieldName, "Ljava/lang/reflect/Method;", 10));

    this.methods.add(((ProxyMethod)localObject2).generateMethod());

    最终添加到hashmap中的ProxyMethod集合中的每个ProxyMethod都会调用generateMethod()生成对应的MethodInfo(Object中的公共方法和接口中的公共方法)

    getMethod():以Method数组形式获取当前类及所有继承的父类的public修饰的方法。仅包括public

    getDeclaredMethod():获取当前类的所有方法,包括public/private/protected/default修饰的方法。

    生成构造函数MethodInfo

    private MethodInfo generateConstructor()
    throws IOException
    {
    MethodInfo localMethodInfo = new MethodInfo("<init>", "(Ljava/lang/reflect/InvocationHandler;)V", 1);
    DataOutputStream localDataOutputStream = new DataOutputStream(localMethodInfo.code);
    code_aload(0, localDataOutputStream);
    code_aload(1, localDataOutputStream);
    localDataOutputStream.writeByte(183);
    localDataOutputStream.writeShort(this.cp.getMethodRef("java/lang/reflect/Proxy", "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
    localDataOutputStream.writeByte(177);
    localMethodInfo.maxStack = 10;
    localMethodInfo.maxLocals = 2;
    localMethodInfo.declaredExceptions = new short[0];
    return localMethodInfo;
    }

    生成接口中的方法MethodInfo

    private ProxyGenerator.MethodInfo generateMethod()
    throws IOException
    {
    String str = ProxyGenerator.getMethodDescriptor(this.parameterTypes, this.returnType);
    。。。。。。。。。。。。。。。。。
    ProxyGenerator.this.code_aload(0, localDataOutputStream);
    localDataOutputStream.writeByte(180);
    localDataOutputStream.writeShort(ProxyGenerator.this.cp.getFieldRef("java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;"));
    ProxyGenerator.this.code_aload(0, localDataOutputStream);
    。。。。。。。。。。。。。。。。。
    }
    localDataOutputStream.writeByte(185);
    localDataOutputStream.writeShort(ProxyGenerator.this.cp.getInterfaceMethodRef("java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;
    。。。。。。。。。。。。。。。。。
    return localMethodInfo;
    }

    生成静态初始块MethodInfo

    private MethodInfo generateStaticInitializer()
    throws IOException
    {
    MethodInfo localMethodInfo = new MethodInfo("<clinit>", "()V", 8);
    int i = 1;
    short s2 = 0;
    DataOutputStream localDataOutputStream = new DataOutputStream(localMethodInfo.code);
    Iterator localIterator1 = this.proxyMethods.values().iterator();
    while (localIterator1.hasNext())
    {
    List localList = (List)localIterator1.next();
    Iterator localIterator2 = localList.iterator();
    while (localIterator2.hasNext())
    {
    ProxyMethod localProxyMethod = (ProxyMethod)localIterator2.next();
    localProxyMethod.codeFieldInitialization(localDataOutputStream);
    }
    }
    localDataOutputStream.writeByte(177);
    short s3 = s1 = (short)localMethodInfo.code.size();
    localMethodInfo.exceptionTable.add(new ExceptionTableEntry(s2, s3, s1, this.cp.getClass("java/lang/NoSuchMethodException")));
    code_astore(i, localDataOutputStream);
    localDataOutputStream.writeByte(187);
    localDataOutputStream.writeShort(this.cp.getClass("java/lang/NoSuchMethodError"));
    localDataOutputStream.writeByte(89);
    code_aload(i, localDataOutputStream);
    localDataOutputStream.writeByte(182);
    localDataOutputStream.writeShort(this.cp.getMethodRef("java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
    localDataOutputStream.writeByte(183);
    localDataOutputStream.writeShort(this.cp.getMethodRef("java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V"));
    localDataOutputStream.writeByte(191);
    short s1 = (short)localMethodInfo.code.size();
    localMethodInfo.exceptionTable.add(new ExceptionTableEntry(s2, s3, s1, this.cp.getClass("java/lang/ClassNotFoundException")));
    code_astore(i, localDataOutputStream);
    localDataOutputStream.writeByte(187);
    localDataOutputStream.writeShort(this.cp.getClass("java/lang/NoClassDefFoundError"));
    localDataOutputStream.writeByte(89);
    code_aload(i, localDataOutputStream);
    localDataOutputStream.writeByte(182);
    localDataOutputStream.writeShort(this.cp.getMethodRef("java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
    localDataOutputStream.writeByte(183);
    localDataOutputStream.writeShort(this.cp.getMethodRef("java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V"));
    localDataOutputStream.writeByte(191);
    if (localMethodInfo.code.size() > 65535)
    throw new IllegalArgumentException("code size limit exceeded");
    localMethodInfo.maxStack = 10;
    localMethodInfo.maxLocals = ((short)(i + 1));
    localMethodInfo.declaredExceptions = new short[0];
    return localMethodInfo;
    }

    生成的子类为:

    public final class $Proxy0 extends Proxy
    implements God{

    。。。。。。

    public $Proxy0(InvocationHandler paramInvocationHandler)
    throws
    {
    super(paramInvocationHandler);
    }

    public final void outputTest2()
    throws
    {
    try
    {
    this.h.invoke(this, m3, null);
    return;
    }

    。。。。。。

     最后将生成的信息写到输出流中,转换成字节数组返回。

    然后通过class.getConstructor()拿到构造函数(参数是包含InvocationHandler接口的class实例)。

    最后一步,通过cons.newInstance(参数是我们创建的传进来的InvocationHandler实现类的实例)返回这个新的代理类的一个实例return paramConstructor.newInstance(new Object[] { paramInvocationHandler });

    如果指定的类中没有空参数的构造函数,或者要创建的类对象需要通过指定的构造函数进行初始化。这时怎么办呢?这时就不能使用Class类中的newInstance方法了。既然要通过指定的构造函数进行对象的初始化。就必须先获取这个构造函数——Constructor。Constructor代表某个类的构造方法。

    2、获取构造方法:

            1)得到这个类的所有构造方法:如得到上面示例中Person类的所有构造方法

                  Constructor[] cons = Class.forName(“cn.itheima.Person”).getConstructors();

            2)获取某一个构造方法:

                  Constructor con=Person.class.getConstructor(String.class,int.class);

    class.getName():以String形式返回次Class对象所表示的实体类型名称

    Cglib代理模式:

    enhancer.setCallback(this);

     这个回调函数就是给代理类执行时需要运行这个方法intercept,那么穿本类的实例进去,之后就会回调这个方法,实现动态代理。

    KEY_FACTORY.newInstance方法返回一个Object类型,该方法的参数中,包括了父类类名或者接口名,回调类型,版本号等。该方法实际上返回了一个该代理类的一个唯一标识。

    http://www.jianshu.com/p/f8b892e08d26

    新生成的子类是怎么实现重写的?

     

    新生的小心情
  • 相关阅读:
    链路层Introduce
    网络扫描常用命令
    SYN DDOS 防御策略
    Python学习笔记(三)------列表
    Python3.4学习笔记(二)------逻辑操作符,循环体,分支
    Python学习笔记(一)------安装,常识普及
    PHP学习日志一----------web开发 环境安装
    ubuntu中 给chrome安装adobe flash player
    Openwrt折腾日志(二)----------环境搭建及依赖安装
    Openwrt折腾日志(一)----------简介及ubuntu安装
  • 原文地址:https://www.cnblogs.com/jianmianruxin/p/7484418.html
Copyright © 2011-2022 走看看