zoukankan      html  css  js  c++  java
  • Proxy 代理模式 动态代理 CGLIB

    代理的基本概念

    几个英文单词:
    proxy [ˈprɒksi] n.  代理服务器;代表权;代理人,代替物;委托书;
    invoke [ɪnˈvəʊk] vt. 乞灵,祈求;提出或授引…以支持或证明;召鬼;借助;
    invocation [ˌɪnvəˈkeɪʃn] n.  祈祷;乞求;乞灵;乞求神助;
    subject	[ˈsʌbdʒɪkt] n. 主题,话题;学科,科目;[哲] 主观; 
        adj. 须服从…的;(在君主等)统治下的; 
        v. 提供,提出;使…隶属;

    什么是代理
    我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家"委托"代理为其销售商品。关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁(不要钻牛角尖!),也就是说,"委托者"对我们来说是不可见的;其次,微商代理主要以朋友圈的人为目标客户,这就相当于为厂家做了一次对客户群体的"过滤"。
    我们把微商代理和厂家进一步抽象,前者可抽象为"代理类",后者可抽象为"委托类(被代理类)"。

    通过使用代理,通常有两个优点:
    • 可以隐藏委托类的实现
    • 可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。

    代理模式是一种结构型设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理

    其实方法直接调用就可以完成功能,为什么还要加个代理呢?
    原因是采用代理模式可以有效的将具体的实现与调用方进行解耦,通过面向接口进行编程完全将具体的实现隐藏在内部
    更通俗的说,代理解决的问题是:当两个类需要通信时,引入第三方代理类,将两个类的关系解耦,让我们只了解代理类即可,而且代理的出现还可以让我们完成与另一个类之间的关系的统一管理。但是一个前提,代理类和委托类要实现相同的接口,因为代理真正调用的还是委托类的方法。

    按照代理的创建时期,可以分为两种:

    • 静态代理:若代理类在程序运行前就已经存在,那么这种代理方式被成为静态代理 。静态代理通常是由程序员在Java代码中定义的, 且代理类和委托类会实现同一接口或是派生自相同的父类。
    • 动态代理:在程序运行时运用反射机制动态创建而成。

    静态代理

    静态代理的一般实现过程:
    • 首先创建一个接口
    • 然后创建具体实现类来实现这个接口具体实现类中需要将接口中定义的方法的业务逻辑功能实现
    • 再创建一个代理类同样实现这个接口代理类中接口方法只要调用具体类中的对应方法即可
    这样,我们在需要使用接口中的某个方法时,直接调用代理类的方法即可,而具体的实现隐藏在了底层。
    /**第一步:定义一个接口*/
    interface Iuser {
    	void eat(String s);
    }
    
    /**第二步:创建具体实现类,即被代理类或委托类*/
    class UserImpl implements Iuser {
    	@Override
    	public void eat(String s) {
    		System.out.println("我要吃" + s);
    	}
    }
    
    /**第三步:创建代理类*/
    class UserProxy implements Iuser {
    	private Iuser user;//代理类通常只实现一个接口,因为代理类中持有的通常只是接口的引用,而不是某个委托类的直接引用
    
    	public UserProxy() {
    		this.user = new UserImpl();
    	}
    
    	public UserProxy(Iuser user) {
    		this.user = user;
    	}
    
    	@Override
    	public void eat(String s) {
    		System.out.println("静态代理前置内容");
    		user.eat(s);//利用的就是多态的特性,也是面向接口编程的一种典型的体现
    		System.out.println("静态代理后置内容");
    	}
    }
    
    /**静态代理访问演示*/
    public class Test {
    	public static void main(String[] args) {
    		UserProxy proxy = new UserProxy();//或 UserProxy proxy = new UserProxy(new UserImpl())
    		proxy.eat("苹果");
    	}
    }
    代理类和被代理类都需要实现某个功能接口,代理类里面持有被代理类的引用,代理类可以根据需要添加不同的操作。

    静态代理类的优点:客户端不需要知道实现类是什么、怎么做的,而只需知道代理类即可(不要钻牛角尖)。
    静态代理类的缺点:
    • 代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法,但是因为代理类中接口的方法往往是没什么逻辑的,它通常只是调用了委托类的同名方法而已,所以这就出现了大量重复、冗余的代码
    • 如果接口中增加或修改了某个方法,除了所有委托类需要修改代码外,所有代理类也需要修改代码,增加了代码维护的复杂度
    • 代理对象只服务于一种类型的对象即静态代理类只能为特定的接口服务,如想要为多个接口服务则需要建立多个代理类,这在大型系统中大大增加了复杂度。

    动态代理

    静态代理是在编译时就将接口、实现类、代理类一股脑儿全部手动完成,但如果我们需要很多的代理,每一个都这么手动的去创建实属浪费时间,而且会有大量的重复代码,此时我们就可以采用动态代理。

    动态代理可以在程序运行期间根据需要动态的创建代理类及其实例,来完成具体的功能,主要用的是JAVA的反射机制
    也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的"指示"动态生成的。
    /**第一步:定义一个接口*/
    interface Iuser {
    	void eat(String s);
    }
    
    /**再定义一个接口*/
    interface Irun {
    	String run(int length);
    }
    
    /**第二步:创建具体实现类,即被代理类或委托类*/
    class UserImpl implements Iuser, Irun {
    	@Override
    	public void eat(String s) {
    		System.out.println("我要吃" + s);
    	}
    
    	@Override
    	public String run(int length) {
    		System.out.println("我跑了 " + length + " 米");
    		return "跑步很欢乐";
    	}
    }
    
    /**第三步:定义代理实例的【调用处理器】,这是一个位于代理类与委托类之间的【中介类】,它需要实现【InvocationHandler】接口*/
    class UserHandler implements InvocationHandler {
    	private Object object;//调用处理器持有委托类的引用,但并不限定委托类必须是某一接口或某一类
    
    	public UserHandler(Object object) {//这里是用Object接收的,所以可以传递任何类型的对象
    		this.object = object;
    	}
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		Object returnObj = method.invoke(object, args); //【核心点】通过反射执行某个类的某方法
    		System.out.println("【方法】" + method.getName() + "【参数】" + Arrays.toString(args) + "【返回值】" + returnObj);
    		return returnObj;
    	}
    }
    
    /**第四步:在使用时动态创建动态代理类*/
    public class Test {
    	public static void main(String[] args) {
    		test1();
    		System.out.println("----------------------2---------------------");
    		test2();
    		System.out.println("----------------------3---------------------");
    		test3();
    	}
    
    	private static void test1() {//完全基于接口Iuser的用法
    		Iuser user = new UserImpl();
    		System.out.println("【委托类】" + user.getClass().getName());//UserImpl
    		System.out.println("【委托类实现的接口】" + Arrays.toString(user.getClass().getInterfaces()));//[interface Iuser, interface Irun]
    
    		InvocationHandler handler = new UserHandler(user);
    		Iuser proxy = (Iuser) Proxy.newProxyInstance(Iuser.class.getClassLoader(), new Class[] { Iuser.class }, handler);//可以直接强转为Iuser
    		System.out.println("【代理类实现的接口】" + Arrays.toString(proxy.getClass().getInterfaces()));//[interface Iuser]。因为你只指定了Iuser接口
    		proxy.eat("苹果");
    	}
    
    	private static void test2() {//精简形式
    		Iuser proxy = (Iuser) Proxy.newProxyInstance(Iuser.class.getClassLoader(), new Class[] { Iuser.class }, new UserHandler(new UserImpl()));
    		System.out.println("【代理类实现的接口】" + Arrays.toString(proxy.getClass().getInterfaces()));//[interface Iuser, interface Irun]
    		proxy.eat("香蕉你个巴拉");
    	}
    
    	private static void test3() {//完全基于委托类UserImpl,之所以采用这种方式,是因为委托类实现了多个接口,且我们需要调用不同接口中的方法
    		Object proxy = Proxy.newProxyInstance(UserImpl.class.getClassLoader(), UserImpl.class.getInterfaces(), new UserHandler(new UserImpl()));
    		((Iuser) proxy).eat("你妹");//可以强转为Iuser
    		String returnObj = ((Irun) proxy).run(99);//也可以强转为Irun
    		System.out.println(returnObj);
    	}
    }
    动态代理的实现其实与静态代理类似,都需要创建代理类,但是不同之处也很明显,创建方式不同!不同之处体现在静态代理我们知根知底,我们知道要对哪个接口、哪个实现类来创建代理类,所以我们在编译前就直接实现与实现类相同的接口,直接在实现的方法中调用实现类中的相应同名方法即可;而动态代理不同,我们不知道它什么时候创建,也不知道要创建针对哪个接口、实现类的代理类(因为它是在运行时因需实时创建的)。


    动态代理用到的两个类
    proxy instance:代理实例,即代理类的实例,指得是通过 Proxy.newProxyInstance 产生的对象
    the invocation handler of a proxy instance:代理实例的调用处理器,指的是实现InvocationHandler接口的那个中介类

    接口 InvocationHandler 调用处理器

    java.lang.reflect.InvocationHandler
    InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
    InvocationHandler是代理实例调用处理器实现的接口。
    PS:InvocationHandler的实现类并不是代理类,而只是位于代理类与委托类之间的中介类。

    Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
    每个代理实例都具有一个关联的调用处理器。对代理实例调用方法时,将对方法调用进行编码,并将其指派到,它的调用处理器的 invoke 方法。
    换一种语气描述就是:每个代理类的实例都关联到了一个实现InvocationHandler接口的handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。

    唯一的一个方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; //在代理实例上处理方法调用并返回结果。
    在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
    参数:
    • proxy - 在其上调用方法的代理实例
    • method - 对应于在代理实例上调用的接口方法的 Method 实例。 Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
    • args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类的实例中。
    返回:
    • 从代理实例的方法调用返回的值。
    • 如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。
    • 如果此方法返回的值为 null 并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出 NullPointerException。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,则代理实例上的方法调用将抛出 ClassCastException。

    Proxy 动态代理类

    public class java.lang.reflect.Proxy extends Object implements java.io.Serializable
    Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类

    基本简介

    创建某一接口 Foo 的代理:
    InvocationHandler handler = new MyInvocationHandler(new FooImpl());//FooImpl是实现 Foo 接口的某一委托类
    Foo f = (Foo) Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class })
        .getConstructor(new Class[] { InvocationHandler.class })
        .newInstance(new Object[] { handler });
    或使用以下更简单的方法:
    Foo proxy = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),//定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    		new Class[] { Foo.class },//表示的是我将要给我需要代理的对象提供一组什么接口,之后我这个代理对象就会实现了这组接口
    		handler);//表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

    动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的 调用处理程序 对象,它可以实现接口InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。

    代理类具有的属性(properties)

    A proxy class has the following properties:
    • 代理类是公共的、最终的,而不是抽象的。Proxy classes are public, final, and not abstract.
    //这句话我觉得是有问题的,如下:
    System.out.println("【代理类的修饰符】" + Modifier.toString(proxy.getClass().getModifiers()));//final,并不是public的
    • 未指定代理类的非限定名称 The unqualified name of a proxy class is unspecified。但是,以字符串 "$Proxy" 开头的类名空间应该为代理类保留
    System.out.println("【代理类】" + proxy.getClass().getName());//【$Proxy0】
    • 代理类的超类为(A proxy class extends) java.lang.reflect.Proxy
    System.out.println("【代理类的超类】" + proxy.getClass().getSuperclass());//【class java.lang.reflect.Proxy】
    • 代理类会按同一顺序准确地实现其创建时指定的接口
    • 如果代理类实现了非公共接口,那么它将在与该接口相同的包中定义。If a proxy class implements a non-public interface, then it will be defined in the same package as that interface. 否则,代理类的包也是未指定的 unspecified。注意,包密封 package sealing 将不阻止代理类在运行时在特定包中的成功定义,也不会阻止相同类加载器和带有特定签名的包所定义的类。
    • 由于代理类将实现所有在其创建时指定的接口,所以对其 Class 对象调用 getInterfaces 将返回一个包含相同接口列表的数组(按其创建时指定的顺序),对其 Class 对象调用 getMethods 将返回一个包括这些接口中所有方法的 Method 对象的数组,并且调用 getMethod 将会在代理接口中找到期望的 as would be expected 一些方法。
    System.out.println("【代理类实现的接口】" + Arrays.toString(proxy.getClass().getInterfaces()));//[interface Iuser, interface Irun]
    • 如果 Proxy.isProxyClass 方法传递代理类(由 Proxy.getProxyClass 返回的类,或由 Proxy.newProxyInstance 返回的对象的类),则该方法返回 true,否则返回 false。
    System.out.println("【是否是代理类】" +Proxy.isProxyClass(proxy.getClass()));//true
    • 代理类的 java.security.ProtectionDomain 与由引导类加载器(如 java.lang.Object)加载的系统类相同,原因是代理类的代码由受信任的系统代码生成。此保护域通常被授予 java.security.AllPermission。
    • 每个代理类都有一个可以带一个参数(接口 InvocationHandler 的实现)的公共构造方法,用于设置代理实例的调用处理程序。并非必须使用反射 API 才能访问公共构造方法,通过调用 Proxy.newInstance 方法(将调用 Proxy.getProxyClass 的操作和调用带有调用处理程序的构造方法结合在一起)也可以创建代理实例。

    代理实例具有的属性

    • 提供代理实例 proxy 和一个由其代理类 Foo 实现的接口,表达式 proxy instanceof Foo 将返回 true,并且 (Foo) proxy 的强制转换操作将会成功(而不抛出 ClassCastException):
    //指定代理类实现的接口为:new Class[] { Iuser.class, Irun.class }
    ((Iuser) proxy).eat("苹果");//可以强转为Iuser
    ((Irun) proxy).run(99);//也可以强转为Irun
    • 每个代理实例都有一个关联的调用处理程序,它会被传递到其构造方法中。静态 Proxy.getInvocationHandler 方法将返回与作为其参数传递的代理实例相关的调用处理程序。
    Iuser proxy = (Iuser) Proxy.newProxyInstance(Iuser.class.getClassLoader(), new Class[] { Iuser.class }, handler);
    System.out.println(Proxy.getInvocationHandler(proxy) == handler);//true
    • 代理实例上的接口方法调用将按照该方法的文档描述进行编码,并被指派到调用处理程序的 Invoke 方法。
    • 在代理实例上的 java.lang.Object 中声明的 hashCode、equals 或 toString 方法的调用将按照与编码和指派接口方法调用相同的方式进行编码,并被指派到调用处理程序的 invoke 方法,如上所述。传递到 invoke 的 Method 对象的声明类是 java.lang.Object。代理类不重写从 java.lang.Object 继承的代理实例的其他公共方法,所以这些方法的调用行为与其对 java.lang.Object 实例的操作一样。

    在多代理接口中重复的方法

    Methods Duplicated in Multiple Proxy Interfaces
    当代理类的两个或多个接口包含一个具有相同名称和参数签名的方法时,代理类的接口顺序变得非常重要。在代理实例上调用重复方法时,传递到调用处理程序的 Method 对象没有必要成为其声明类可以从接口(通过该接口调用代理方法)的引用类型指派的对象。此限制存在的原因是,生成的代理类中的相应方法实现无法确定它通过哪一个接口调用。因此,在代理实例上调用重复方法时,第一个接口中的方法的 Method 对象包含接口的代理类列表中的方法(直接或通过超级接口继承),该对象会传递到调用处理程序的 invoke 方法,无论该方法调用通过哪一种引用类型发生。

    如果代理接口包含某一方法,它的名称和参数签名与 java.lang.Object 的 hashCode、equals 或 toString 方法相同,那么在代理实例上调用这样的方法时,传递到调用处理程序的 Method 对象将使 java.lang.Object 成为其声明类。换句话说,java.lang.Object 公共的非最终方法理论上在所有代理接口之前,以便确定哪一个 Method 对象传递到调用处理程序。

    还要注意,当重复方法被指派到调用处理程序时,invoke 方法只可以抛出经过检查的异常类型,该异常类型可以使用所有 代理接口(可以通过它调用)中方法的 throws 子句指派一种异常类型。如果 invoke 方法抛出一个经过检查的异常,该异常没有指派给任何由一个代理接口(可以通过它调用)中的方法声明的异常类型,那么该代理实例上的调用将抛出一个未经检查的 UndeclaredThrowableException。此限制表示并非所有的由传递到 invoke 方法的 Method 对象上调用 getExceptionTypes 返回的异常类型都可以由 invoke 方法成功抛出。

    API

    字段
    • protected InvocationHandler  h  此代理实例的调用处理程序。
    构造方法
    • protected Proxy(InvocationHandler h)  使用其调用处理程序的指定值从子类(通常为动态代理类)构建新的 Proxy 实例。
    公共方法
    • static InvocationHandler    getInvocationHandler(Object proxy)  返回指定代理实例的调用处理程序。
    • static boolean    isProxyClass(Class<?> cl)  当且仅当指定的类通过 getProxyClass 方法或 newProxyInstance 方法动态生成为代理类时,返回 true。
    • static Class<?>    getProxyClass(ClassLoader loader, Class<?>... interfaces)  返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。
    • static Object    newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)  返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
      • 返回值:一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
      • 参数:
        • loader - 定义代理类的类加载器。定义了由哪个ClassLoader对象来对生成的代理对象进行加载
        • interfaces - 代理类要实现的接口列表。表示的是我将要给我需要代理的对象提供一组什么接口,之后我这个代理对象就会实现了这组接口
        • h - 指派方法调用的调用处理程序。表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

    关于 newProxyInstance 方法

    为什么我们可以将newProxyInstance方法返回的Object类型的对象转化为Iuser或Irun类型的对象?
    原因就在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这个接口的对象。
    另外,通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它实际的类型并不是我们的 InvocationHandler 类型,也不是我们定义的那组接口的类型,而是在运行时动态生成的一个对象,并且命名方式都是这样的形式,以$开头,Proxy为中,最后一个数字表示对象的标号。

    我们来看看这两句:
    ((Iuser) proxy).eat("苹果");
    ((Irun) proxy).run(99);
    这里是通过代理对象来调用实现的那种接口中的方法,这个时候程序就会跳转到由这个代理对象关联到的 handler 中的 invoke 方法去执行,而我们的这个 handler 对象又接受了一个 UserImpl 类型的参数,表示我要代理的就是这个真实对象,所以此时就会调用 handler 中的 invoke 方法去执行。

    CGLIB代码生成库简介

    Byte Code Generation Library is high level API to generate and transform JAVA byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept field access. 
    字节码生成库是用于生成和转换JAVA字节码的高级API。它被AOP,测试,数据访问框架用于生成动态代理对象并拦截字段访问。

    JDK从1.3版本起就提供了一个动态代理,它使用起来非常简单,但是有个明显的缺点:需要目标对象实现一个或多个接口
    通常来说,你可以使用JDK动态代理方法来创建代理,对于没有接口的情况或者性能因素,CGLIB是一个很好的选择。
    使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。CGLIB简单易用,且它的运行速度要远远快于JDK的Proxy动态代理。本质上来说,CGLIB通过产生子类覆盖非final方法来进行代理,CGLIB不能代理一个final类或者final方法。

    CGLIB是一个强大的、高性能的代码生成库。它被广泛使用在基于代理的AOP框架(例如Spring AOP和dynaop)提供方法拦截。Hibernate作为最流行的ORM工具也同样使用CGLIB库来代理单端关联(集合懒加载除外,它使用另外一种机制)。EasyMock和jMock作为流行的Java测试库,它们提供Mock对象的方式来支持测试,都使用了CGLIB来对没有接口的类进行代理。

    在实现内部,CGLIB库使用了ASM这一个轻量但高性能的字节码操作框架来转化字节码,产生新类。除了CGLIB,像Groovy和BeanShell这样的脚本语言同样使用ASM来生成Java字节码。ASM使用了一个类似于SAX分析器的机制来达到高性能。我们不建议直接使用ASM,因为这样需要对JVM非常了解,包括类文件格式和指令集。


    CGLIB API
    CGLIB库组织如下所示:
    • net.sf.cglib.core:底层字节码操作类;大部分与ASP相关。
    • net.sf.cglib.transform:编译期、运行期的class文件转换类。
    • net.sf.cglib.proxy:代理创建类、方法拦截类
    • net.sf.cglib.reflect:更快的反射类、C#风格的代理类。
    • net.sf.cglib.util:集合排序工具类
    • net.sf.cglib.beans:JavaBean相关的工具类
    对于创建动态代理,大部分情况下你只需要使用proxy包的一部分API即可。


    一个案例
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    interface LoginService {
    	public boolean checkUser();
    }
    
    class LoginServiceImpl implements LoginService {
    	@Override
    	public boolean checkUser() {
    		System.out.println("LoginServiceImpl  checkUser");
    		return false;
    	}
    }
    
    interface UserService {
    	public String getUserName();
    }
    
    class UserServiceImpl implements UserService {
    
    	@Override
    	public String getUserName() {
    		System.out.println("UserServiceImpl getUserName");
    		return null;
    	}
    
    }
    
    class CglibProxy implements MethodInterceptor {
    	@Override
    	public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
    		System.out.println("*********代理方法执行前************");
    		Object retObj = methodProxy.invokeSuper(proxy, params);
    		System.out.println("*********代理方法执行后************");
    		return retObj;
    	}
    
    	//返回目标对象的代理对象  
    	public Object newProxy(Object target) {
    		Enhancer enhancer = new Enhancer();
    		enhancer.setSuperclass(target.getClass());
    		enhancer.setCallback(this);
    		enhancer.setClassLoader(target.getClass().getClassLoader());
    		return enhancer.create();
    	}
    }
    
    public class Test {
    
    	public static void main(String[] args) {
    		//创建目标对象  
    		LoginService loninService = new LoginServiceImpl();
    		UserService userService = new UserServiceImpl();
    		CglibProxy proxy = new CglibProxy();
    		//创建代理对象  
    		LoginService loninService$Proxy = (LoginService) proxy.newProxy(loninService);
    		UserService userService$Proxy = (UserService) proxy.newProxy(userService);
    		loninService$Proxy.checkUser();
    		userService$Proxy.getUserName();
    	}
    }
    2017-9-6




  • 相关阅读:
    js完美拖拽封装及其案例
    js运动框架封装以及两种案例
    js常见的11种兼容
    Lua 学习笔记(五)函数
    Lua 学习笔记(四)语句与控制结构
    Lua 学习笔记(三)表达式
    Lua 学习笔记(二)语法、类型、值
    Lua 学习笔记(一)环境搭建
    Cocos2d-x 3.2 学习笔记(十六)保卫萝卜 游戏主循环与定时器
    Cocos2d-x 3.2 学习笔记(十五)保卫萝卜 场景与数据
  • 原文地址:https://www.cnblogs.com/baiqiantao/p/7485704.html
Copyright © 2011-2022 走看看