动态代理

一、静态代理

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

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

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. svn客户端更改用户名

    你是用的小乌龟做客户端吗?在文件夹里点右键,选择TortoiseSVN->Setings->SavedData里面有个authentication data,点击后面的Clear就好了下次 ...

  2. epoll ET(边缘触发) LT(水平触发)

    EPOLL事件有两种模型: Edge Triggered (ET) 边缘触发只有数据到来,才触发,不管缓存区中是否还有数据.Level Triggered (LT) 水平触发只要有数据都会触发. 首先 ...

  3. 应用调试(二)GDB

    title: 应用调试(二)GDBdate: 2019/1/17 21:00:10 toc: true 应用调试(二)GDB gdb下载工具安装交叉工具链设置GDB介绍编译GDBtarget/host ...

  4. css预编译语言 sass scss(变量$var, css嵌套规则,@import规则,@extend,@mixin)

    什么是sass Sass 是对 CSS 的扩展,让 CSS 语言更强大.优雅. 它允许你使用变量.嵌套规则. mixins.导入等众多功能, 并且完全兼容 CSS 语法. Sass 有助于保持大型样式 ...

  5. html css hover也会冒泡

    <HEAD> <style type="text/css"> div:hover { color:blue !important; } </style ...

  6. How to learn PDE (怎么学偏微分方程)

    To learn PDE, you need some knowledge of physics (to build up the intuition), solid training of anal ...

  7. 劫持 Opengl32.dll 实现游戏MOD

    前提是你的游戏是用的Opengl,如果是DX的,自行谷歌方法,应该差不多,参考GTA5 最近玩了款<天命奇御>的国产网游,自己手动写了个MOD,本来是直接修改Chap-Assembly.d ...

  8. DIV浮动层被OCX控件遮蔽解决方案

    在开发中需要在网页中嵌入OCX控件,但是控件嵌入后,总是会出现在网页最顶层,页面中的浮动DIV总是不能正常显示,会被遮蔽掉,那么这里就需要特殊处理一下: OBJECT会遮蔽掉页面内容,但是IFRAME ...

  9. MacOS下使用远程桌面VNC

    1 分为一个server 和 viewer,server端就是可以加入组然后允许远程连接,viewer就是远程连接端 2 server下载地址 https://www.realvnc.com/en/c ...

  10. JAVA进阶6

    间歇性混吃等死,持续性踌躇满志系列-------------第6天 1.数组 package cn.intcast.day06.demo01; /* 直接打印数组名称,得到的是数组对应的内存地址的哈希 ...