动态代理

一、静态代理

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

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

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. 看毛片就能AC算法

    KMP && ACA KMP: 吼哇! 反正网上教程满天飞,我就不写了. 发个自己写的模板 /** freopen("in.in", "r", ...

  2. Numpy 系列(十一)- genfromtxt函数

    定义输入 genfromtxt的唯一强制参数是数据的源.它可以是字符串,字符串列表或生成器.如果提供了单个字符串,则假定它是本地或远程文件或具有read方法的打开的类文件对象的名称,例如文件或Stri ...

  3. openstack项目【day23】:keystone组件HTTP协议

    阅读目录 一 为何要学习HTTP协议 二 用户上网过程 三 HTTP协议 part1 http协议概述 part2 请求协议 part3 响应协议 四 抓包分析HTTP协议 一 为何要学习HTTP协议 ...

  4. Docker:Docker 性质及版本选择 [三]

    一.Docker的性质 Docker的组成其实很简单.你需要搭建registry,专属于你自己的私有仓库,然后就是docker的镜像和docker的容器.Docker的镜像,就类似与windos的系统 ...

  5. I/O模型之一:Unix的五种I/O模型

    目录: <I/O模型之一:Unix的五种I/O模型> <I/O模型之二:Linux IO模式及 select.poll.epoll详解> <I/O模型之三:两种高性能 I ...

  6. C#中的Finalize,Dispose,SuppressFinalize的实现和使用介绍

    原文地址:http://www.csharpwin.com/csharpspace/8927r1397.shtml MSDN建议按照下面的模式实现IDisposable接口: public class ...

  7. MySQL安全配置向导mysql_secure_installation详解

    安装完mysql-server 会提示可以运行mysql_secure_installation.运行mysql_secure_installation会执行几个设置:  a)为root用户设置密码  ...

  8. [物理学与PDEs]第5章习题3 第二 Piola 应力张量的对称性

    试证明: 在物质描述下, 动量矩守恒定律等价于第二 Piola 应力张量的对称性. 证明: 由 $$\beex \bea \int_{G_t}\rho\sex{{\bf y}\times\cfrac{ ...

  9. 《Java编程思想第四版完整中文高清版.pdf》-笔记

    D.2.1 安插自己的测试代码 插入下述“显式”计时代码,对程序进行评测: long start = System.currentTimeMillis(); // 要计时的运算代码放在这儿 long ...

  10. remote connect to ubuntu unity

    https://community.nxp.com/thread/220596 putty secure copy protocol can be used to transfer file amon ...