Java笔记(二十一) 动态代理
动态代理
一、静态代理
代理的背后一般至少有一个实际对象,代理的外部功能和实际对象一般是一样的,
用户与代理打交道,不直接接触实际对象。代理存在的价值:
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笔记(二十一) 动态代理的更多相关文章
- Java笔记(二十一)……String与StringBuffer
String类 String类是一个特殊的类,叫做只读类,一旦创建了对象,便不可被改变,同样"abc"既为一个常量,也为一个对象,也是不可以改变的 String s1 = &quo ...
- Java核心技术点之动态代理
本篇博文会从代理的概念出发,介绍Java中动态代理技术的使用,并进一步探索它的实现原理.由于个人水平有限,叙述中难免出现不清晰或是不准确的地方,希望大家可以指正,谢谢大家:) 一.概述 1. 什么是代 ...
- Java Proxy和CGLIB动态代理原理
动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询.测试框架的后端mock.RPC,Java注解对象获取等.静态代理的代理关系在编译时就确定了,而动态代理的代理关 ...
- java反射机制与动态代理
在学习HadoopRPC时.用到了函数调用.函数调用都是採用的java的反射机制和动态代理来实现的,所以如今回想下java的反射和动态代理的相关知识. 一.反射 JAVA反射机制定义: JAVA反射机 ...
- Spring学习笔记之aop动态代理(3)
Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点: 1.在该系统中有多少的dao就的写多少的proxy,麻烦 2.如果目标接口有方法的改动,则proxy也需要改动. Person ...
- python3.4学习笔记(二十一) python实现指定字符串补全空格、前面填充0的方法
python3.4学习笔记(二十一) python实现指定字符串补全空格.前面填充0的方法 Python zfill()方法返回指定长度的字符串,原字符串右对齐,前面填充0.zfill()方法语法:s ...
- Java反射机制以及动态代理
Java反射机制以及动态代理 Java反射机制 含义与功能 Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类 ...
- java 代理模式二:动态代理
java动态代理: java动态代理类位于java.lang.reflect包下,一般主要涉及两个类: 1.Interface InvocationHandler 该接口中仅定义了一个方法:Objec ...
- Java 代理模式 (二) 动态代理
代理模式 代理(Proxy)是一种设计模式, 提供了对目标对象另外的访问方式:即通过代理访问目标对象. 这样好处: 可以在目标对象实现的基础上,增强额外的功能操作.(扩展目标对象的功能). 代理模式的 ...
- Java中的JDK动态代理
所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...
随机推荐
- Day039--HTML
HTML小马哥博客 HTML CSS + DIV实现整体布局 1. HTML 超文本标记语言 对换行不敏感 空白折叠现象 标签要严格密封 新建HTML文件,输入 html:5,按tab键后,自动生成的 ...
- bootstrap学习: 折叠插件和面板
bootstrap提供了面板排版工具和折叠插件,能够用来实现新闻列表.留言板.博客分块等: 1.折叠插件: <a data-toggle="collapse" data-ta ...
- strace -> System call tracer
我只想告诉你一件事: strace 可以让你知道程序调用了哪些syscall.
- Nginx虚拟主机 子文件单独配置
上一篇所有的server 全都配置在nginx.conf配置文件里,其实每个server 都可以单独做一个子文件 删除nginx.conf配置文件中的server及其余内容,加上如下图 创建保存每个虚 ...
- 关于JS中的常用表单验证+正则表达式
一.非空验证 trim:去空格(去掉前后的空格),任何字符串都可以用这个方法.写法为:if(v.trim().length==0),表示如果去掉空格后的字符串的长度为0. <body> & ...
- 51nod 1215 数组的宽度
若一个数在一段区间内作为最大值存在,那么答案应该加上这个数 若一个数在一段区间内作为最小值存在,那么答案应该减去这个数 所以我们利用单调栈,高效求出a[i]在哪个区间内作为最大/最小值存在,从而确定, ...
- codeblocks添加编译选项
-std=c++0x
- Codeforces 544E K Balanced Teams (DP)
题目: You are a coach at your local university. There are nn students under your supervision, the prog ...
- 【python】md5加密方法相关使用
md5方法在hashlib库中,使用前需要先导入.它的主要方法为update,copy,以及转换为二进制,十六进制. 用法说明: Help on HASH object: class HASH(bui ...
- 【原创】大叔经验分享(18)hive2.0以后通过beeline执行sql没有进度信息
一 问题 在hive1.2中使用hive或者beeline执行sql都有进度信息,但是升级到hive2.0以后,只有hive执行sql还有进度信息,beeline执行sql完全silence,在等待结 ...