Java 代理模式(二) Java中的动态代理
动态代理类
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
1.Interface InvocationHandler
该接口中仅定义了一个方法:
Object invoke(Object proxy, Method method, Object[] args)
在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组(无参时设置为null)。
这个抽象方法在代理类中动态实现。
2.Proxy
该类即为动态代理类,作用类似于上文例子中的ProxySubject,其中主要包含如下内容:
protected Proxy(InvocationHandler h): 构造函数,用于给内部的invocation handler赋值。
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) : loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) :返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类在Subject接口中声明过的方法)。
动态代理类说明
所谓Dynamic Proxy是这样一种class:
它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。
你当然可以把该class的实例当作这些interface中的任何一个来用。
当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你做实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
在使用动态代理类时,我们必须实现InvocationHandler接口。每一个动态代理类都会有一个与之关联的invocation handler。
真正的调用是在invocation handler的invoke()方法里完成的。
实例说明:
首先定义抽象角色和真实角色类:
public interface Subject
{
public void request();
}

public class RealSubject implements Subject
{
@Override
public void request()
{
System.out.println("From real subject!");
}
}

之后定义一个DynamicSubject类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; /**
* 该代理类的内部属性是Object类型,实际使用的时候通过该类的构造方法传递进来一个对象。
* 该类实现了invoke()方法,该方法中的method.invoke()其实就是调用被代理对象的将要执行的方法,
* 方法参数sub表示该方法从属于sub。
* 通过动态代理类,我们可以在执行真实对象的方法前后加入自己的一些额外方法
*
*/
public class DynamicSubject implements InvocationHandler
{ //对真实对象的引用
private Object sub; public DynamicSubject(Object obj)
{
this.sub = obj; } @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
System.out.println("Before calling: " + method); //通过反射来调用方法
method.invoke(sub, args); System.out.println("After calling: " + method);
return null;
} }

使用的时候:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; public class Client
{
public static void main(String[] args)
{
RealSubject realSubject = new RealSubject(); InvocationHandler handler = new DynamicSubject(realSubject); Class<?> classType = handler.getClass(); // 生成代理
// 动态生成一个类(实现了指定的接口),生成类的对象,转换成接口类型
Subject subject = (Subject) Proxy.newProxyInstance(classType
.getClassLoader(), realSubject.getClass().getInterfaces(),
handler); subject.request();
// 调用方法时,转移给handler接管,由其中的invoke()方法实际完成方法执行 System.out.println(subject.getClass());// 打印出:class $Proxy0
// $Proxy0是在运行期间动态生成的一个类 } }

通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。
动态代理
动态代理是指客户通过代理类来调用其他对象的方法。
动态代理使用场合:
调试。
远程方法调用(RMI)。
动态代理步骤
1.创建一个实现接口InvocationHandler的类,它必须实现invoke()方法。
2.创建被代理的类以及接口。
3.通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)创建一个代理。
4.通过代理调用方法。
动态代理实现例子2:
动态代理实现例子3:
这个例子中定义了一个接口:
public interface Foo
{
public void doAction();
}
这个接口有两个实现类:

public class FooImpl1 implements Foo
{
@Override
public void doAction()
{
System.out.println("From Implement 1 !");
}
} public class FooImpl2 implements Foo
{
@Override
public void doAction()
{
System.out.println("From Implement 2 !");
}
}

定义invocation handler,其中的set方法使得实际对象是可更换的:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class CommonInvocationHandler implements InvocationHandler
{
private Object target; public CommonInvocationHandler()
{ } public CommonInvocationHandler(Object obj)
{
this.target = obj;
} public void setTarget(Object target)
{
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
return method.invoke(target, args);
} }

使用:

import java.lang.reflect.Proxy; public class Demo
{
public static void main(String[] args)
{
CommonInvocationHandler handler = new CommonInvocationHandler(); Foo f = null; handler.setTarget(new FooImpl1()); f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class }, handler); f.doAction();
System.out.println("----------------------------");
handler.setTarget(new FooImpl2());
f.doAction(); } }

程序运行后输出:
From Implement 1 !
----------------------------
From Implement 2 !
Java 代理模式(二) Java中的动态代理的更多相关文章
- 模式的秘密-代理模式(2)-JDK动态代理
代理模式-动态代理 (1) (2) 代码实践动态代理: 第一步:被代理类的接口: package com.JdkProxy; public interface Moveable { void move ...
- 十分钟理解Java中的动态代理
十分钟理解 Java 中的动态代理 一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道 ...
- 深度剖析java中JDK动态代理机制
https://www.jb51.net/article/110342.htm 本篇文章主要介绍了深度剖析java中JDK动态代理机制 ,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定 ...
- Java 中的动态代理
一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,“委托者” ...
- java反射中的动态代理机制(有实例)
在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...
- java设计模式中的动态代理
Java的三种代理模式 1.代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩 ...
- Java中的动态代理(jdk和cglib)
JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类 ...
- 一文读懂Java中的动态代理
从代理模式说起 回顾前文: 设计模式系列之代理模式(Proxy Pattern) 要读懂动态代理,应从代理模式说起.而实现代理模式,常见有下面两种实现: (1) 代理类关联目标对象,实现目标对象实现的 ...
- 使用Java中的动态代理实现数据库连接池
2002 年 12 月 05 日 作者通过使用JAVA中的动态代理实现数据库连接池,使使用者可以以普通的jdbc连接的使用习惯来使用连接池. 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的 ...
- java中的动态代理
1.动态代理的定义:为其他对象提供一个代理以控制对这个对象的访问 2.通过api看下proxy生成代理类的2中写法: 创建某一接口 Foo 的代理: InvocationHandler handler ...
随机推荐
- JSP动作指令
JSP动作指令 动作指令与编译指令不间,编译指令是通知 Servlet 引擎的处理消息,而动作指令只是运行时的脚本动作.编译指令在将JSP 编译成 Servlet 时起作用:处理指令通常可替换成 Ja ...
- Redis队列——PHP操作简单示例
入队操作 <?php $redis = new Redis(); $redis->connect('127.0.0.1',6379); while(True){ try{ $value = ...
- 关于ROS证书导入的步骤
在群里的vibbow大神指点下,做了一个ROS证书导入的步骤 1.到阿里云申请的免费证书清单如下:(如果你准备的自签名证书,那么在客户端也需要安装证书才行,否则就要到网上去申请真实的,或者花钱买的证书 ...
- android.support.v7.internal.widget.ActionBarOverlayLayout Couldn't Be Initialized
问题症状: Android Studio 1.2 (Build 141.1890965) 新建工程,自动build完成后,Layout Editor无法预览Layout文件,报错内容: Renderi ...
- http和https(转)
一.HTTP协议 最近看了一些网络通信方面的书籍,研究了一下 HTTP 和 TCP/IP,有了一些新的收获和理解,在这里做个归纳和总结. (1)什么是HTTP协议 HTTP (HyperText Tr ...
- webdriver定位页面元素时使用set_page_load_time()和JavaScript停止页面加载
webdriver定位页面元素时使用set_page_load_time()和JavaScript停止页面加载 原文:https://my.oschina.net/u/2344787/blog/400 ...
- controller 允许跨域访问
1.在controller 上加上 @CrossOrigin(origins = {"http://localhost:7777", "http://someserver ...
- BTM事务配置
请参考原贴:http://thinkdifferent.iteye.com/blog/1450433 Tomcat6上配置BTM 博客分类: practice tomcatjava )去http:// ...
- Rhythmk 一步一步学 JAVA (21) JAVA 多线程
1.JAVA多线程简单示例 1.1 .Thread 集成接口 Runnable 1.2 .线程状态,可以通过 Thread.getState()获取线程状态: New (新创建) Runnable ...
- centos 使用windows7 存储
1. 在Windows7上创建一个带密码的用户,如disk 2. 创建一个文件夹,如 D:\centos-disk2 3. 选中此文件夹,点击上方的 共享 -> 特定用户, 添加disk用户, ...