一天一种JAVA设计模式之八:代理模式

365 阅读13分钟

写在前面的话

复习、总结23种设计模式

获取详细源码请点击我

上一篇

# 一天一种JAVA设计模式之七:装饰模式

代理模式

记重点

jdk动态代理和cglib动态代理

定义

为其他对象提供一种代理以控制对这个对象的访问

代理模式的通用类图

image.png

Subject抽象主题角色

抽象主题类尅是抽象类也可以是接口,是一个最普通的业务类型定义,没有特殊要求

package com.design.pattern.proxy.test02;  
  
// Subject抽象主题角色  
public interface Subject {  
  
    void request();  
}

RealSubject真实主题角色

也叫做委托角色,被代理角色,它才是冤大头,是业务逻辑的具体执行者

package com.design.pattern.proxy.test02;  
  
// 真实主题角色  
public class RealSubject implements Subject{  
  
    @Override  
    public void request() {  
        System.out.println("do sth.");  
    }  
  
}

Proxy代理主题角色

也叫做委托类、代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后工作

package com.design.pattern.proxy.test02;  
  
// Proxy代理主题角色  
public class Proxy implements Subject {  
  
    private Subject subject;  

    public Proxy(Subject subject) {  
        this.subject = subject;  
    }  

    @Override  
    public void request() {  
        before();  
        subject.request();  
        after();  
    }  

    private void before() {  
        System.out.println("预处理...");  
    }  

    private void after() {  
        System.out.println("善后...");  
    }  
  
}

测试类

package com.design.pattern.proxy.test02;  
  
// 测试类  
public class Client {  

    public static void main(String[] args) {  
        // 真实对象  
        Subject realSubject = new RealSubject();  
        // 代理对象  
        Subject proxy = new Proxy(realSubject);  
        proxy.request();  
    }  
  
}

静态代理

定义

静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。

以打游戏+找代练为例实战

定义打游戏的接口

package com.design.pattern.proxy.test01;  
    // 打游戏  
    public interface IGamePlayer {  

    // 游戏登录  
    void login(String username, String password);  

    // 打怪  
    void killBoss();  

    // 升级  
    void upgrade();  
}

具体的游戏玩家

package com.design.pattern.proxy.test01;  
  
// 具体的游戏玩家  
public class GamePlayer implements IGamePlayer {  

    private String nickname;  

    public GamePlayer(String nickname) {  
        this.nickname = nickname;  
    }  

    @Override  
    public void login(String username, String password) {  
        System.out.println("登录名为" + username + "的用户" + nickname + "登录成功");  
    }  

    @Override  
    public void killBoss() {  
        System.out.println(nickname + "正在打boss...");  
    }  

    @Override  
    public void upgrade() {  
        System.out.println(nickname + "又升了一级");  
    }  
}

不找游戏代练,自己打游戏

package com.design.pattern.proxy.test01;  
  
// 自己打游戏  
public class Client {  
    public static void main(String[] args) {  
        IGamePlayer gamePlayer = new GamePlayer("豆豆");  
        System.out.println("开始时间:" + System.currentTimeMillis());  
        gamePlayer.login("username1", "password1");  
        gamePlayer.killBoss();  
        gamePlayer.upgrade();  
        System.out.println("结束时间:" + System.currentTimeMillis());  
    }  
}

找个游戏代练

package com.design.pattern.proxy.test03;  
  
import com.design.pattern.proxy.test01.IGamePlayer;  
  
// 游戏代练  
public class GamePlayerProxy implements IGamePlayer {  
  
    private IGamePlayer iGamePlayer;  

    public GamePlayerProxy(IGamePlayer iGamePlayer) {  
        this.iGamePlayer = iGamePlayer;  
    }  

    @Override  
    public void login(String username, String password) {  
        iGamePlayer.login(username, password);  
    }  

    @Override  
    public void killBoss() {  
        iGamePlayer.killBoss();  
    }  

    @Override  
    public void upgrade() {  
        iGamePlayer.upgrade();  
    }  
}

让游戏代练帮你打游戏

package com.design.pattern.proxy.test03;  
  
import com.design.pattern.proxy.test01.GamePlayer;  
import com.design.pattern.proxy.test01.IGamePlayer;  
  
// 让游戏代练帮你打游戏  
public class Client {  
  
    public static void main(String[] args) {  
        IGamePlayer gamePlayer = new GamePlayer("豆豆");  
        // 定义一个游戏代练  
        IGamePlayer proxy = new GamePlayerProxy(gamePlayer);  

        System.out.println("开始时间:" + System.currentTimeMillis());  
        proxy.login("username1", "password1");  
        proxy.killBoss();  
        proxy.upgrade();  
        System.out.println("结束时间:" + System.currentTimeMillis());  
    }  
}

总结:

  • 静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现接口或继承相同的父类

缺点:

  • 因为代理对象需要和被代理对象实现相同的接口或父类,所以会有太多的代理类
  • 一旦接口中增加了方法后,被代理对象和代理对象都需要维护(非常麻烦,不方便)

jdk动态代理

代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理

package com.design.pattern.proxy.jdk04.test05;  
  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.util.Arrays;  
  
public class GamePlayerIH implements InvocationHandler {  
  
    // 被代理实例,invoke方法里面method需要使用这个被代理对象  
    private Object target;  

    public GamePlayerIH(Object target) {  
        this.target = target;  
    }  

    /**  
    * 核心方法,它完成对真实方法的调用  
    *  
    * @param proxy 代表动态生成的 动态代理 对象实例  
    * @param method 代表被调用委托类的接口方法,和生成的代理类实例调用的接口方法是一致的,它对应的Method 实例  
    * @param args 代表调用接口方法对应的Object参数数组,如果接口是无参,则为null; 对于原始数据类型返回的他的包装类型。  
    */  
    @Override  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        System.out.println("被动态代理类回调执行, 代理类 proxyClass =" + proxy.getClass());  
        System.out.println("方法名: " + method.getName() + "方法. 方法返回类型:" + method.getReturnType());  
        System.out.println("接口方法入参数组: " + (args == null ? "null" : Arrays.toString(args)));  

        System.out.println("前置通知...");  
        // 调用被代理对象的真实方法  
        Object result = method.invoke(target, args);  
        System.out.println("后置通知...");  
        return result;  
    }   
}
package com.design.pattern.proxy.jdk04.test05;  
  
import com.design.pattern.proxy.test01.GamePlayer;  
import com.design.pattern.proxy.test01.IGamePlayer;  
  
import java.lang.reflect.Field;  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Proxy;  
import java.util.Properties;  
  
public class Client {  
  
    public static void main(String[] args) throws Exception {  
        // 打开保存JDK动态代理生成的类文件  
        saveGeneratedJdkProxyFiles();  

        // 定义一个游戏玩家  
        GamePlayer gamePlayer = new GamePlayer("doudou");  
        // 定义一个handler  
        InvocationHandler handler = new GamePlayerIH(gamePlayer);  
        // 动态生产一个代理者  
        IGamePlayer proxy = (IGamePlayer) Proxy.newProxyInstance(  
            gamePlayer.getClass().getClassLoader(),  
            new Class<?>[]{IGamePlayer.class},  
            handler);  

        System.out.println("开始时间:" + System.currentTimeMillis());  
        proxy.login("username1", "password1");  
        proxy.killBoss();  
        proxy.upgrade();  
        System.out.println("结束时间:" + System.currentTimeMillis());  
    }  

    /**  
    * 设置保存Java动态代理生成的类文件到我们的module下
    */  
    public static void saveGeneratedJdkProxyFiles() throws Exception {  
        Field field = System.class.getDeclaredField("props");  
        field.setAccessible(true);  
        Properties props = (Properties) field.get(null);  
        props.put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");  
    }  
}

程序运行时动态生成的代理类

//  
// Source code recreated from a .class file by IntelliJ IDEA  
// (powered by FernFlower decompiler)  
//  
  
package com.sun.proxy;  
  
import com.design.pattern.proxy.test01.IGamePlayer;  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  
import java.lang.reflect.UndeclaredThrowableException;  
  
public final class $Proxy0 extends Proxy implements IGamePlayer {  
    private static Method m1;  
    private static Method m2;  
    private static Method m5;  
    private static Method m4;  
    private static Method m3;  
    private static Method m0;  

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

    public final boolean equals(Object var1) throws {  
        try {  
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});  
        } catch (RuntimeException | Error var3) {  
            throw var3;  
        } catch (Throwable var4) {  
            throw new UndeclaredThrowableException(var4);  
        }  
    }  

    public final String toString() throws {  
        try {  
            return (String)super.h.invoke(this, m2, (Object[])null);  
        } catch (RuntimeException | Error var2) {  
            throw var2;  
        } catch (Throwable var3) {  
            throw new UndeclaredThrowableException(var3);  
        }  
    }  

    public final void upgrade() throws {  
        try {  
            super.h.invoke(this, m5, (Object[])null);  
        } catch (RuntimeException | Error var2) {  
            throw var2;  
        } catch (Throwable var3) {  
            throw new UndeclaredThrowableException(var3);  
        }  
    }  

    public final void killBoss() throws {  
        try {  
            super.h.invoke(this, m4, (Object[])null);  
        } catch (RuntimeException | Error var2) {  
            throw var2;  
        } catch (Throwable var3) {  
            throw new UndeclaredThrowableException(var3);  
        }  
    }  

    public final void login(String var1, String var2) throws {  
        try {  
            super.h.invoke(this, m3, new Object[]{var1, var2});  
        } catch (RuntimeException | Error var4) {  
            throw var4;  
        } catch (Throwable var5) {  
            throw new UndeclaredThrowableException(var5);  
        }  
    }  

    public final int hashCode() throws {  
        try {  
            return (Integer)super.h.invoke(this, m0, (Object[])null);  
        } catch (RuntimeException | Error var2) {  
            throw var2;  
        } catch (Throwable var3) {  
            throw new UndeclaredThrowableException(var3);  
        }  
    }  

    static {  
        try {  
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));  
            m2 = Class.forName("java.lang.Object").getMethod("toString");  
            m5 = Class.forName("com.design.pattern.proxy.test01.IGamePlayer").getMethod("upgrade");  
            m4 = Class.forName("com.design.pattern.proxy.test01.IGamePlayer").getMethod("killBoss");  
            m3 = Class.forName("com.design.pattern.proxy.test01.IGamePlayer").getMethod("login", Class.forName("java.lang.String"), Class.forName("java.lang.String"));  
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");  
        } catch (NoSuchMethodException var2) {  
            throw new NoSuchMethodError(var2.getMessage());  
        } catch (ClassNotFoundException var3) {  
            throw new NoClassDefFoundError(var3.getMessage());  
        }  
    }  
}

第二种创建jdk动态代理的方法

创建Person接口,用于定义委托类和代理类之间的约束行为

package com.design.pattern.proxy.jdk04.test06;  
  
/**  
* 创建Person 接口 用于定义 委托类和代理类之间的约束行为  
*/  
public interface Person {  
    /**  
    * @param name 人名  
    * @param dst 工作目的地  
    */  
    void goWorking(String name, String dst);  

    /**  
    * 获取名称  
    *  
    * @return  
    */  
    String getName();  

    /**  
    * 设置名称  
    *  
    * @param name  
    */  
    void setName(String name);  
}

动态代理委托类实现, 实现接口Person。被动态生成的代理类代理

package com.design.pattern.proxy.jdk04.test06;  
  
/**  
* 动态代理委托类实现, 实现接口 Person。 被动态生成的代理类代理  
*/  
public class SoftwareEngineer implements Person {  
  
    private String name;  

    public SoftwareEngineer() {  
    }  

    public SoftwareEngineer(String name) {  
        this.name = name;  
    }  

    @Override  
    public void goWorking(String name, String dst) {  
        System.out.println("name =" + name + ",去" + dst + "工作");  
    }  

    public String getName() {  
        return name;  
    }  

    public void setName(String name) {  
        this.name = name;  
    }  
  
}

增强类

package com.design.pattern.proxy.jdk04.test06;  
  
/**  
* 监控类  
*/  
public class MonitorUtil {  
    private static ThreadLocal<Long> tl = new ThreadLocal<>();  

    public static void start() {  
        tl.set(System.currentTimeMillis());  
    }  

    /**  
    * 结束时打印耗时  
    *  
    * @param methodName 方法名  
    */  
    public static void finish(String methodName) {  
        long finishTime = System.currentTimeMillis();  
        System.out.println(methodName + "方法执行耗时" + (finishTime - tl.get()) + "ms");  
    }  
}

PersonInvocationHandler类实现InvocationHandler接口,这个类中持有一个被代理对象(委托类)的实例target。该类别JDK Proxy类回调InvocationHandler 接口中有一个invoke方法,当一个代理实例的方法被调用时,代理方法将被编码并分发到 InvocationHandler接口的invoke方法执行。

package com.design.pattern.proxy.jdk04.test06;  
  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.util.Arrays;  
  
/**  
* PersonInvocationHandler 类 实现InvocationHandler接口,这个类中持有一个被代理对象(委托类)的实例target。该类别JDK Proxy类回调  
* InvocationHandler 接口中有一个invoke方法,当一个代理实例的方法被调用时,代理方法将被编码并分发到 InvocationHandler接口的invoke方法执行。  
*/  
public class PersonInvocationHandler<T> implements InvocationHandler {  
    /**  
    * 被代理对象引用,invoke 方法里面method 需要使用这个 被代理对象  
    */  
    T target;  

    public PersonInvocationHandler(T target) {  
        this.target = target;  
    }  

    /**  
    * @param proxy 代表动态生成的 动态代理 对象实例  
    * @param method 代表被调用委托类的接口方法,和生成的代理类实例调用的接口方法是一致的,它对应的Method 实例  
    * @param args 代表调用接口方法对应的Object参数数组,如果接口是无参,则为null; 对于原始数据类型返回的他的包装类型。  
    */  
    @Override  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        /**  
        * 在转调具体目标对象之前,可以执行一些功能处理  
        */  
        System.out.println("被动态代理类回调执行, 代理类 proxyClass =" + proxy.getClass() + " 方法名: " + method.getName() + "方法. 方法返回类型:" + method.getReturnType() + " 接口方法入参数组: " + (args == null ? "null" : Arrays.toString(args))); /**  
        * 代理过程中插入监测方法,计算该方法耗时  
        */  
        MonitorUtil.start();  
        Thread.sleep(1);  
        /** 调用被代理对象的真实方法,*/  
        Object result = method.invoke(target, args);  
        MonitorUtil.finish(method.getName());  
        return result;  
    }  
  
}

动态代理对象步骤

  1. 创建一个与代理对象相关联的 InvocationHandler,以及真实的委托类实例
  2. Proxy类的getProxyClass静态方法生成一个动态代理类stuProxyClass,该类继承Proxy类,实现 Person.java接口;JDK动态代理的特点是代理类必须继承Proxy类
  3. 通过代理类 proxyClass 获得他的带InvocationHandler 接口的构造函数 ProxyConstructor
  4. 通过 构造函数实例 ProxyConstructor 实例化一个代理对象,并将 InvocationHandler 接口实例传递给代理类。
package com.design.pattern.proxy.jdk04.test06;  
  
  
import sun.misc.ProxyGenerator;  
  
import java.io.FileOutputStream;  
import java.lang.reflect.Constructor;  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Proxy;  
import java.nio.file.Path;  
import java.nio.file.Paths;  
import java.util.Arrays;  
  
public class Client {  
  
    public static void main(String[] args) {  
        /**  
        * 动态代理对象步骤  
        * 1、 创建一个与代理对象相关联的 InvocationHandler,以及真实的委托类实例  
        * 2、Proxy类的getProxyClass静态方法生成一个动态代理类stuProxyClass,该类继承Proxy类,实现 Person.java接口;JDK动态代理的特点是代理类必须继承Proxy类  
        * 3、通过代理类 proxyClass 获得他的带InvocationHandler 接口的构造函数 ProxyConstructor  
        * 4、通过 构造函数实例 ProxyConstructor 实例化一个代理对象,并将 InvocationHandler 接口实例传递给代理类。  
        */  
        try {  
            run();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  

    private static void run() throws Exception {  
        // 这是我们真实对象  
        Person persontwo = new SoftwareEngineer("豆豆");  

        // 1、创建 InvocationHandler 实例并设置代理的目标类对象  
        InvocationHandler handler = new PersonInvocationHandler<>(persontwo);  

        // 2、 创建代理类,是一个字节码文件, 把 proxyClass 保存起来就能看到 他继承Proxy 类,实现Person接口  
        Class<?> proxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), Person.class);  

        // 代理类信息  
        System.out.println("package = " + proxyClass.getPackage()  
            + " SimpleName = " + proxyClass.getSimpleName()  
            + " name =" + proxyClass.getName()  
            + " CanonicalName = " + proxyClass.getCanonicalName()  
            + " 实现的接口 Interfaces = " + Arrays.toString(proxyClass.getInterfaces())  
            + " superClass = " + proxyClass.getSuperclass()  
            + " methods =" + Arrays.toString(proxyClass.getMethods()));  

        // 3、通过 proxyClass 获得 一个带有InvocationHandler参数的构造器constructor  
        Constructor<?> ProxyConstructor = proxyClass.getConstructor(InvocationHandler.class);  
        
        // 4、通过构造器创建一个 动态代理类 实例  
        Person stuProxy = (Person) ProxyConstructor.newInstance(handler);  

        // 检测生成的类是否是代理类  
        System.out.println("stuProxy isProxy " + Proxy.isProxyClass(stuProxy.getClass()));  

        // 获取 代理类关联的 InvocationHandler 是哪个  
        InvocationHandler handlerObject = Proxy.getInvocationHandler(stuProxy);  

        System.out.println(handlerObject.getClass().getName());  

        stuProxy.goWorking(stuProxy.getName(), "广州");  
        // 保存代理类  
        String pathdir = "/Users/benjamin/IntelliJIdeaProjects/springboot-mydemo/demo/jdkdynamicclasses";  
        saveClass("$PersonProxy0", proxyClass.getInterfaces(), pathdir);  
    }  
  
    /**  
    * 生成代理类 class 并保持到文件中  
    *  
    * @param className 生成的代理类名称  
    * @param interfaces 代理类需要实现的接口  
    * @param pathdir 代理类保存的目录路径,以目录分隔符结尾  
    */  
    public static void saveClass(String className, Class<?>[] interfaces, String pathdir) {  
        /**  
        * 第一个参数是 代理类 名 。  
        * 第二个参数是 代理类需要实现的接口  
        */  
        byte[] classFile = ProxyGenerator.generateProxyClass(className, interfaces);  

        /**  
        * 如果目录不存在就新建所有子目录  
        */  
        Path path1 = Paths.get(pathdir);  
        if (!path1.toFile().exists()) {  
            path1.toFile().mkdirs();  
        }  

        String path = pathdir + className + ".class";  
        try (FileOutputStream fos = new FileOutputStream(path)) {  
            fos.write(classFile);  
            fos.flush();  
            System.out.println("代理类class文件写入成功");  
        } catch (Exception e) {  
            System.out.println("写文件错误");  
        }  
    }  
  
}

cglib动态代理

静态代理和jdk动态代理都要求目标对象实现接口,

cglib动态代理,使用以目标对象子类的方式实现代理,(当目标对象是一个单独的对象,没有实现任何接口时使用).

Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,为其提供方法的interception(拦截),例如大家所熟知的Spring AOP。

​ Cglib包的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类。

Cglib子类代理需要注意的是:

  • 需要引入cglib的jar包
  • 代理的类不能是final,否则报错
  • 目标对象的方法如果有final/static,那么不会被拦截,即不会执行目标对象额外的业务方法。

实现步骤:

步骤1:引入jar包

<dependency>  
    <groupId>cglib</groupId>  
        <artifactId>cglib</artifactId>  
    <version>2.2.2</version>  
</dependency>

DEMO-1

创建被代理的类

package com.design.pattern.proxy.cglib05.test09;  
  
public class SqlService {  
    public void executeSql1() throws InterruptedException {  
        System.out.println("Sql 开始执行.....");  
        Thread.sleep(1000);  
        System.out.println("Sql 执行结束.....");  
    } 
    public void executeSql2() throws InterruptedException {  
        System.out.println("Sql2 开始执行.....");  
        Thread.sleep(1000);  
        System.out.println("Sql2 执行结束.....");  
    }
}

自定义MethodInterceptor

package com.design.pattern.proxy.cglib05.test09;  
  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
  
import java.lang.reflect.Method;  
  
public class SqlFacadeCglib implements MethodInterceptor {  
  
    /**  
    * 被代理的对象  
    */  
    private Object target;  

    public SqlFacadeCglib(Object target) {  
        this.target = target;  
    }  

    /**  
    * 实现回调方法  
    *  
    * @param obj 代理的对象  
    * @param method 被代理对象的方法  
    * @param args 参数集合  
    * @param proxy 生成的代理类的方法  
    */  
    @Override  
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {  
        // 开始执行时间  
        Long startTime = System.currentTimeMillis();  
        // //调用业务类(父类中)的方法  
        Object result = proxy.invokeSuper(obj, args);  
        // 执行结束  
        Long endTime = System.currentTimeMillis();  
        System.out.println(target.getClass().getName()  
        + "执行executeSql耗时" + (endTime - startTime) + "ms");  
        return result;  
    }  
}

测试

package com.design.pattern.proxy.cglib05.test09;  
  
import net.sf.cglib.core.DebuggingClassWriter;  
import net.sf.cglib.proxy.*;  
  
import java.lang.reflect.Method;  
  
public class CglibTest {  

    public static void main(String[] args) throws InterruptedException {  
        // 将class 文件保存  
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\WorkspaceIdea\\01src\\java-design-pattern\\ProxyPattern08\\src\\main\\java");  

        SqlService sqlService = new SqlService();  
        SqlFacadeCglib sqlFacadeCglib = new SqlFacadeCglib(sqlService);  

        //创建加强器,用来创建动态代理类  
        Enhancer enhancer = new Enhancer();  
        //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)  
        enhancer.setSuperclass(sqlService.getClass());  
        
        // 可以为不同的method使用不同的callback
        enhancer.setCallbackFilter(new CallbackFilter() {  
            @Override  
            public int accept(Method method) {  
                // 使用第一个callback
                return 0;  
            }  
        });  

        enhancer.setCallbackTypes(new Class<?>[]{MethodInterceptor.class});  

        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦  
        enhancer.setCallback(sqlFacadeCglib);  
        // 创建动态代理类对象并返回  
        SqlService sqlServiceProxy = (SqlService) enhancer.create();  
        // 调用  
        sqlServiceProxy.executeSql1();  
        System.out.println("--------------------------");  
        System.out.println(sqlServiceProxy.getClass().getName());  
    }  
  
}

DEMO-2

package com.design.pattern.proxy.cglib05.test10;  
  
import java.util.Arrays;  
import java.util.List;  
  
public class DBQuery {  
  
    public DBQuery() {  
    }  

    public DBQuery(Integer i) {  
        System.out.println("Here's in DBQuery Constructor");  
    }  

    public String getElement(String id) {  
        return id + "_CGLib";  
    }  

    public List<String> getAllElements() {  
        return Arrays.asList("Hello_CGLib1", "Hello_CGLib2");  
    }  

    public String methodForNoop() {  
        return "Hello_Noop";  
    }  

    public String methodForFixedValue(String param) {  
        return "Hello_" + param;  
    }  

    public final String sayHello() {  
        return "Hello Everyone!";  
    }  
}
package com.design.pattern.proxy.cglib05.test10;  
  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
  
import java.lang.reflect.Method;  
  
public class DBQueryProxy implements MethodInterceptor {  
  
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {  
        System.out.println("Here in interceptor !");  
        return methodProxy.invokeSuper(o, objects);  
    }  
}
package com.design.pattern.proxy.cglib05.test10;  
  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
  
import java.lang.reflect.Method;  
  
public class DBQueryProxy2 implements MethodInterceptor {  

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {  
        System.out.println("Here in interceptor 2!");  
        return methodProxy.invokeSuper(o, objects);  
    }  
}
package com.design.pattern.proxy.cglib05.test10;  
  
import net.sf.cglib.proxy.FixedValue;  
  
public class DBQueryProxyFixedValue implements FixedValue {  
  
    public Object loadObject() throws Exception {  
        System.out.println("Here in DBQueryProxyFixedValue ! ");  
        return "Fixed Value";  
    }  
  
}
package com.design.pattern.proxy.cglib05.test10;  
  
import net.sf.cglib.proxy.Callback;  
import net.sf.cglib.proxy.CallbackFilter;  
import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.NoOp;  
  
import java.lang.reflect.Method;  
  
public class TestCGLibProxy {  
  
    public static void main(String[] args) {  
        DBQueryProxy dbQueryProxy = new DBQueryProxy();  
        DBQueryProxy2 dbQueryProxy2 = new DBQueryProxy2();  
        Callback noopCb = NoOp.INSTANCE;  
        Callback fixedValue = new DBQueryProxyFixedValue();  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(DBQuery.class);  
        enhancer.setCallbacks(new Callback[]{dbQueryProxy, dbQueryProxy2, noopCb, fixedValue});  
        enhancer.setCallbackFilter(new CallbackFilter() {  
            public int accept(Method method) {  
                if (method.getName().equals("getElement")) {  
                    return 0;  
                } else if (method.getName().equals("getAllElements")) {  
                    return 1;  
                } else if (method.getName().equals("methodForNoop")) {  
                    return 2;  
                } else if (method.getName().equals("methodForFixedValue")) {  
                    return 3;  
                } else {  
                    return 0;  
                }  
            }  
        });  
        DBQuery dbQuery = (DBQuery) enhancer.create();  
        System.out.println("========Inteceptor By DBQueryProxy ========");  
        System.out.println(dbQuery.getElement("Hello"));  
        System.out.println();  
        System.out.println("========Inteceptor By DBQueryProxy2 ========");  
        System.out.println(dbQuery.getAllElements());  
        System.out.println();  
        System.out.println("========Return Original Value========");  
        System.out.println(dbQuery.methodForNoop());  
        System.out.println();  
        System.out.println("========Return Fixed Value========");  
        System.out.println(dbQuery.methodForFixedValue("myvalue"));  
    } 
}

jdk动态代理和cglib动态代理的区别

底层原理不同 JDK 动态代理是利用反射机制生成一个实现代理接口的匿名类, 在调用具体方法前调用 InvokeHandler 来处理 而 CGLIB 动态代理是利用 ASM 开源包,加载代理对象类的 class 文件 通过修改其字节码生成子类来处理

可作用范围不同 JDK 动态代理只能对实现了接口的类生成代理,而不能针对类 CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 因为是继承,所以该类或方法不能声明成 final 类型

JDK动态代理特点 代理对象必须实现一个或多个接口 以接口的形式接收代理实例,而不是代理类

CGLIB动态代理特点 代理对象不能被 final 修饰 以类或接口形式接收代理实例

JDK与CGLIB动态代理的性能对比 生成代理实例性能:JDK > CGLIB 代理实例运行性能:JDK > CGLIB

下一篇

# 一天一种JAVA设计模式之七:装饰模式