动态代理

一、静态代理

代理的背后一般至少有一个实际对象,代理的外部功能和实际对象一般是一样的,

用户与代理打交道,不直接接触实际对象。代理存在的价值:

1)节省成本比较高的实际对象创建开销,按需延迟加载,创建代理时

并不正真创建实际对象,而只是保存实际对象的地址,在需要时再加载或者创建。

2)执行权限检查,代理检查权限后再调用实际对象。

3)屏蔽网络的差异性和复杂性,代理在本地,而实际对象在其他服务器上,调用

本地代理时,本地代理请求其他服务器。

静态代理示例:

public class SimpleStaticProxy {
//服务接口
static interface IService {
void sayHello();
}
//服务类
static class RealService implements IService {
@Override
public void sayHello() {
System.out.println("hi");
}
}
//代理类
static class TraceProxy implements IService {
private IService realService; public TraceProxy(IService realService) {
this.realService = realService;
} @Override
public void sayHello() {
System.out.println("Start say hi");
realService.sayHello();
System.out.println("End say hi");
}
} public static void main(String[] args) {
RealService service = new RealService();
TraceProxy traceProxy = new TraceProxy(service);
traceProxy.sayHello();
}
}

静态代理缺陷:如果每个类都需要代理,我们需要为每个类都创建代理类,

实现所有接口,这个工作量相当大。

二、Java SDK代理

所谓动态代理,代理类是动态生成的。

1.用法

public class SimpleJDKDynamicProxy {
interface IService {
void sayHello();
void sayGoodBye();
}
static class RealService implements IService {
@Override
public void sayHello() {
System.out.println("hi");
}
@Override
public void sayGoodBye() {
System.out.println("GoodBye world!");
}
}
static class SimpleInvocateHandler implements InvocationHandler {
private Object realObj;
public SimpleInvocateHandler(Object realObj) {
this.realObj = realObj;
}
/**
* @param proxy 表示代理对象本身,注意它不是被代理的对象,这个参数用处不大
* @param method 表示正在被调用的方法
* @param args 表示方法的参数
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Start " + method.getName());
Object result = method.invoke(realObj, args);
System.out.println("End " + method.getName());
return result;
}
}
public static void main(String[] args) {
IService realService = new RealService();
IService proxyService = (IService) Proxy.newProxyInstance(IService.class.getClassLoader(),
new Class<?>[]{IService.class}, new SimpleInvocateHandler(realService));
proxyService.sayHello();
proxyService.sayGoodBye();
}
}
/**
* @param loader 类加载器
* @param interfaces 代理类要实现的接口列表
* @param h 该接口定义了invoke方法,对代理接口所有的方法调用都会转给该方法
* @return 可以转换为interfaces数组中的某个接口类型,注意只能转换为接口不能转换为具体的类
* */
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h);

2.基本原理

创建proxyService的代码可以用如下的代码代替:

//创建代理类定义,类定义会被缓存
Class<?> proxyCls = Proxy.getProxyClass(IService.class.getClassLoader(), new Class<?>[] { IService.class });
//获取代理类的构造方法
Constructor<?> ctor = proxyCls.getConstructor(new Class<?>[] { InvocationHandler.class });
InvocationHandler handler = new SimpleInvocationHandler(realService);
//创建代理类对象
IService proxyService = (IService) ctor.newInstance(handler);
    final class $Proxy0 extends Proxy implements SimpleJDKDynamicProxyDemo.IService {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject) {
return((Boolean) this.h.invoke(this, m1,
new Object[] { paramObject })).booleanValue();
}
public final void sayHello() {
this.h.invoke(this, m3, null);
}
public final String toString() {
return (String) this.h.invoke(this, m2, null);
}
public final int hashCode() {
return ((Integer) this.h.invoke(this, m0, null)).intValue();
}
static {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName(
"laoma.demo.proxy.SimpleJDKDynamicProxyDemo$IService")
.getMethod("sayHello",new Class[0]);
m2 = Class.forName("java.lang.Object")
.getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object")
.getMethod("hashCode", new Class[0]);
}
}

三、cglib动态代理

Java SDK动态代理的局限,它只能为接口创建代理,返回的代理对象也只能转换到某个接口类型。

public class SimpleCGLibDemo {
static class RealService {
public void sayHello() {
System.out.println("hello");
}
}
static class SimpleInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("start " + method.getName());
Object result = methodProxy.invokeSuper(object, args);
System.out.println("end " + method.getName());
return result;
}
}
private static <T> T getProxy(Class<T> cls) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(cls);
enhancer.setCallback(new SimpleInterceptor());
return (T) enhancer.create();
}
public static void main(String[] args) {
RealService proxy = getProxy(RealService.class);
proxy.sayHello();
}
}

cglib是通过继承实现的,具体原理略。

Java笔记(二十一) 动态代理的更多相关文章

  1. Java笔记(二十一)……String与StringBuffer

    String类 String类是一个特殊的类,叫做只读类,一旦创建了对象,便不可被改变,同样"abc"既为一个常量,也为一个对象,也是不可以改变的 String s1 = &quo ...

  2. Java核心技术点之动态代理

    本篇博文会从代理的概念出发,介绍Java中动态代理技术的使用,并进一步探索它的实现原理.由于个人水平有限,叙述中难免出现不清晰或是不准确的地方,希望大家可以指正,谢谢大家:) 一.概述 1. 什么是代 ...

  3. Java Proxy和CGLIB动态代理原理

    动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询.测试框架的后端mock.RPC,Java注解对象获取等.静态代理的代理关系在编译时就确定了,而动态代理的代理关 ...

  4. java反射机制与动态代理

    在学习HadoopRPC时.用到了函数调用.函数调用都是採用的java的反射机制和动态代理来实现的,所以如今回想下java的反射和动态代理的相关知识. 一.反射 JAVA反射机制定义: JAVA反射机 ...

  5. Spring学习笔记之aop动态代理(3)

    Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点: 1.在该系统中有多少的dao就的写多少的proxy,麻烦 2.如果目标接口有方法的改动,则proxy也需要改动. Person ...

  6. python3.4学习笔记(二十一) python实现指定字符串补全空格、前面填充0的方法

    python3.4学习笔记(二十一) python实现指定字符串补全空格.前面填充0的方法 Python zfill()方法返回指定长度的字符串,原字符串右对齐,前面填充0.zfill()方法语法:s ...

  7. Java反射机制以及动态代理

    Java反射机制以及动态代理 Java反射机制 含义与功能 Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类 ...

  8. java 代理模式二:动态代理

    java动态代理: java动态代理类位于java.lang.reflect包下,一般主要涉及两个类: 1.Interface InvocationHandler 该接口中仅定义了一个方法:Objec ...

  9. Java 代理模式 (二) 动态代理

    代理模式 代理(Proxy)是一种设计模式, 提供了对目标对象另外的访问方式:即通过代理访问目标对象. 这样好处: 可以在目标对象实现的基础上,增强额外的功能操作.(扩展目标对象的功能). 代理模式的 ...

  10. Java中的JDK动态代理

    所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...

随机推荐

  1. 值得推荐的C/C++框架和库 (真的很强大) c

    http://m.blog.csdn.net/mfcing/article/details/49001887 值得推荐的C/C++框架和库 (真的很强大) 发表于2015/10/9 21:13:14 ...

  2. ajax实现长连接

    项目需求:需要实时的读取日志文件里的数据,并且使用Echart实时更新折线图. 使用ajax实现客户端与服务器端的数据传输. 目的:我想通过ajax与服务器建立一个长连接,服务器会不断的传输数据给前台 ...

  3. checkbox,三种状态设置

    多选按钮的  选中.未选中.半选中(常用于子项有选中,未全选) <input id="ckeckbox" type="checkbox"> $('# ...

  4. PageRank算法--从原理到实现

    本文将介绍PageRank算法的相关内容,具体如下: 1.算法来源 2.算法原理 3.算法证明 4.PR值计算方法 4.1 幂迭代法 4.2 特征值法 4.3 代数法 5.算法实现 5.1 基于迭代法 ...

  5. Geometric regularity criterion for NSE: the cross product of velocity and vorticity 3: $u\times \f{\om}{|\om|}\cdot \f{\vLm^\be u}{|\vLm^\be u|}$

    在 [Chae, Dongho; Lee, Jihoon. On the geometric regularity conditions for the 3D Navier-Stokes equati ...

  6. MySQL5.6.39修改密码

    5.6.39 苹果->系统偏好设置->最下边点mysql 在弹出页面中 关闭mysql服务(点击stop mysql server) step2: 进入终端输入:cd /usr/local ...

  7. 《我是一只IT小小鸟读后感》

    在我步入大学前,并未了解何为IT,真是毫无知晓.由于种种原因最终还是选择了软件工程专业,是 对是错,是福是祸,不知该不该去考虑,但即已然 选择了这条路,便得付出一些努力,这个世界总 是有许多在默默努力 ...

  8. 使用echarts-for-react 绘制折线图 报错:`series.type should be specified `

    解决办法: 在动态获取值的函数前面加 访问器属性  get ,去获取对象的属性 @inject('commonStore', 'reportUIStore') @observer class Line ...

  9. 更改 Ubuntu默认Python版本的问题

    一般Ubuntu默认版本为2.x,之前运行一些程序,将默认版本修改为3.5,现在想修改为2.7. 之前的方法有些忘记,现在重新记录一下: 1.查看你系统中有哪些Python的二进制文件可供使用, ls ...

  10. 【洛谷P1303A*Bprublem】

    题目描述 求两数的积. 输入输出格式 输入格式: 两行,两个数. 输出格式: 积 输入输出样例 输入样例#1: 1 2 输出样例#1: 2 说明 每个数字不超过10^2000,需用高精 这道题还是比较 ...