设计模式之动态代理模式实战

昨天分享了静态代理的概念及存在的缺点,所以今天讲的动态代理模式十分重要。动态代理在我们工作当中应用相当广泛,如Srping AOP就是动态代理的在开源框架的比较出名的应用。

动态代理有两种试,一是通过JDK自带的API实现动态代理,二是通过别的字节码框架实现,如cglib。

需要注意的是JDK只能针对接口实现动态代理,不能代理普通类,使用具有局限性。而cglib可以代理接口及所有的普通类。

下面拿昨天保存用户信息的例子继续用动态代理来实现。

用户接口

public interface UserInterface {

boolean saveUser(User user);

}

用户接口实现

public class UserInterfaceImpl implements UserInterface {

@Override

public boolean saveUser(User user) {

System.out.println("保存用户: " + user.getName());

return true;

}

}

public class Test {

public static void main(String[] args) {

// JDK动态代理

testJDKProxy();

// Cglib接口代理

testCglibInterfaceProxy();

// Cglib类代理

testCglibClassProxy();

}

private static void testJDKProxy() {

User user = new User();

user.setName("tom");

UserProxy.getUserProxy().saveUser(user);

}

static class UserProxy {

private static final InvocationHandler USER_HANDLE = new InvocationHandler() {

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("JDK接口动态代理-开始保存用户");

Object result = method.invoke(new UserInterfaceImpl(), args);

System.out.println("JDK接口动态代理-保存用户结果: " + result);

System.out.println();

return result;

}

};

public static UserInterface getUserProxy() {

UserInterface userInterface = (UserInterface) Proxy.newProxyInstance(UserProxy.class.getClassLoader(),

new Class[] { UserInterface.class }, USER_HANDLE);

return userInterface;

}

}

private static void testCglibInterfaceProxy() {

User user = new User();

user.setName("tom");

UserCglibProxy.getUserProxy().saveUser(user);

}

static class UserCglibProxy {

private static final net.sf.cglib.proxy.InvocationHandler USER_HANDLE = new net.sf.cglib.proxy.InvocationHandler() {

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("Cglib接口动态代理-开始保存用户");

Object result = method.invoke(new UserInterfaceImpl(), args);

System.out.println("Cglib接口动态代理-保存用户结果: " + result);

System.out.println();

return result;

}

};

public static UserInterface getUserProxy() {

UserInterface userInterface = (UserInterface) net.sf.cglib.proxy.Proxy.newProxyInstance(

UserCglibProxy.class.getClassLoader(), new Class[] { UserInterface.class }, USER_HANDLE);

return userInterface;

}

}

private static void testCglibClassProxy() {

User user = new User();

user.setName("tom");

UserInterfaceImpl userImpl = (UserInterfaceImpl) ClassCgLibProxy.getUserProxy(new UserInterfaceImpl());

userImpl.saveUser(user);

}

static class ClassCgLibProxy {

private static final MethodInterceptor USER_HANDLE = new MethodInterceptor() {

@Override

public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

System.out.println("Cglib类动态代理-开始保存用户");

Object result = proxy.invokeSuper(obj, args);

System.out.println("Cglib类动态代理-保存用户结果: " + result);

System.out.println();

return result;

}

};

public static Object getUserProxy(Object target) {

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(target.getClass());

enhancer.setCallback(USER_HANDLE);

return enhancer.create();

}

}

}

结果输出:

JDK接口动态代理-开始保存用户

保存用户: tom

JDK接口动态代理-保存用户结果: true

Cglib接口动态代理-开始保存用户

保存用户: tom

Cglib接口动态代理-保存用户结果: true

Cglib类动态代理-开始保存用户

保存用户: tom

Cglib类动态代理-保存用户结果: true

从例子看出,使用也并不复杂,动态代理与静态代理最主要的区别在于,静态代理是编译期间就确定好的代理关系,而动态代理是运行期间由JVM通过反射等技术生成的代理对象,不存在class文件,代理类与被代理类之间的关系是继承关系,所以,普通类final的方法是不能被动态代理的。

原文发布于微信公众号 - Java技术栈(javastack)

原文发表时间:2017-06-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏JMCui

Redis学习一(基础入门).

一、前言     Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、key-Value 的数据库、并提供多...

3855
来自专栏Leetcode名企之路

jvm类加载机制

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。

1283
来自专栏用户2442861的专栏

《Java虚拟机原理图解》 1.1、class文件基本组织结构

http://blog.csdn.net/luanlouis/article/details/39892027

912
来自专栏Java技术分享圈

杨老师课堂之JavaSe 部分面试题

​ JVM 是 JavaVirtual Machine 的缩写,全称是 Java 虚拟机。Java 语言的一个非常重要的 特性就是跨平台性,而 Java 虚...

893
来自专栏无题

堆外内存概要

DirectByteBuffer JDK中使用 DirectByteBuffer对象来表示堆外内存,每个 DirectByteBuffer对象在初始化时,都会创...

2424
来自专栏专注 Java 基础分享

虚拟机类加载机制

虚拟机把字节码文件从磁盘加载进内存的这个过程,我们可以粗糙的称之为「类加载」,因为「类加载」不仅仅是读取一段字节码文件那么简单,虚拟机还要进行必要的「验证」、「...

4667
来自专栏二进制文集

JDK源码分析 多线程

对于JDK源码分析的文章,仅仅记录我认为重要的地方。源码的细节实在太多,不可能面面俱到地写清每个逻辑。所以我的JDK源码分析,着重在JDK的体系架构层面,具体源...

1052
来自专栏眯眯眼猫头鹰的小树杈

猫头鹰的深夜翻译:理解java的classloader

Java ClassLoader是java运行系统中一个至关重要但是经常被忽略的组件。它负责在运行时寻找并加载类文件。创建自定义的ClassLoader可以彻底...

1394
来自专栏向治洪

java基础Haep(堆)和Stack(栈)区别

简单的可以理解为: heap:是由malloc之类函数分配的空间所在地。地址是由低向高增长的。  stack:是自动分配变量,以及函数调用的时候所使用的一些空...

2107
来自专栏乐百川的学习频道

设计模式(二十三) 模板模式

模板模式也是一种行为型模式,而且它非常好理解。当我们解决问题需要固定几个步骤, 这些步骤的顺序不能改变,而步骤的具体实现可以变化的时候,就可以使用模板模式。模板...

1676

扫码关注云+社区

领取腾讯云代金券