动态代理

一、静态代理

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

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

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. Day039--HTML

    HTML小马哥博客 HTML CSS + DIV实现整体布局 1. HTML 超文本标记语言 对换行不敏感 空白折叠现象 标签要严格密封 新建HTML文件,输入 html:5,按tab键后,自动生成的 ...

  2. bootstrap学习: 折叠插件和面板

    bootstrap提供了面板排版工具和折叠插件,能够用来实现新闻列表.留言板.博客分块等: 1.折叠插件: <a data-toggle="collapse" data-ta ...

  3. strace -> System call tracer

    我只想告诉你一件事: strace 可以让你知道程序调用了哪些syscall.

  4. Nginx虚拟主机 子文件单独配置

    上一篇所有的server 全都配置在nginx.conf配置文件里,其实每个server 都可以单独做一个子文件 删除nginx.conf配置文件中的server及其余内容,加上如下图 创建保存每个虚 ...

  5. 关于JS中的常用表单验证+正则表达式

    一.非空验证 trim:去空格(去掉前后的空格),任何字符串都可以用这个方法.写法为:if(v.trim().length==0),表示如果去掉空格后的字符串的长度为0. <body> & ...

  6. 51nod 1215 数组的宽度

    若一个数在一段区间内作为最大值存在,那么答案应该加上这个数 若一个数在一段区间内作为最小值存在,那么答案应该减去这个数 所以我们利用单调栈,高效求出a[i]在哪个区间内作为最大/最小值存在,从而确定, ...

  7. codeblocks添加编译选项

    -std=c++0x

  8. Codeforces 544E K Balanced Teams (DP)

    题目: You are a coach at your local university. There are nn students under your supervision, the prog ...

  9. 【python】md5加密方法相关使用

    md5方法在hashlib库中,使用前需要先导入.它的主要方法为update,copy,以及转换为二进制,十六进制. 用法说明: Help on HASH object: class HASH(bui ...

  10. 【原创】大叔经验分享(18)hive2.0以后通过beeline执行sql没有进度信息

    一 问题 在hive1.2中使用hive或者beeline执行sql都有进度信息,但是升级到hive2.0以后,只有hive执行sql还有进度信息,beeline执行sql完全silence,在等待结 ...