JAVA代理模式
来源:互联网 发布:淘宝热卖怎么加入 编辑:程序博客网 时间:2024/06/05 15:31
java的代理模式是一种应用很广泛的设计模式,在一个实际的项目工程当中,模块之间相互调用调用的其实只是某个对象中的方法而已,我们并不需要关心这个方法是由哪个对象所拥有的,所以我们在使用方法的时候,我们没有必要去创建一个对象,这样的做法是很耗系统资源的,在某些情况下,客户端代码不想或者不能够直接调用或者不能调用被调用者,我们就可以创建一个代理对象,负责去调用我们想要使用的方法,这就是代理模式,代理的对象其实就是在调用者和被调用者之间起到中介作用而已。
按照代理的创建时期,代理类可以分为两种:
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
(1)静态代理
首先创建一个接口,接口提供了一个图书增加的方法
public interface IBook {
public void add();
}
接着是一个实现了该接口的类:
public class BookImpl implements IBook {
@Override
public void add() {
System.out.println("图书增加");
}
}
接着是一个代理类,这个代理类对上面这个实现类进行了增强:
public class BookProxy implements IBook{
//传入实现类,对原来的进行增强处理
private BookImpl bookimpl;
public BookProxy(BookImpl bookimpl){
this.bookimpl = bookimpl;
}
@Override
public void add() {
bookimpl.add();
}
}
接下来我们可以测试测试:
public class TestStaticProxy {
/**
* @param args
*/
public static void main(String[] args) {
BookImpl bookimpl = new BookImpl();
BookProxy proxy = new BookProxy(bookimpl);
proxy.add();
}
}
运行测试以后,我们发现通过代理类成功调用了目标方法。到这里,可能会有人提出疑问,代理模式在调用目标方法的时候,还是要创建BookImpl的对象实例传入,才可以创建一个代理对象,从而调用目标方法,我们的系统资源占用没有实质性的减少,反而把问题复杂化了?我们可以从另外的角度去思考问题:假如那个被调用的方法在一个需要占用大量系统资源的对象当中,直接创建那个对象会不会占用很多资源,减慢系统的速度呢?答案是肯定的。
观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。
再来看一下动态代理: 我在以上代码基础之上增加了下面一个重要的类:
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//InvocationHandler 是代理实例的调用处理程序 实现的接口
public class BookAutoProxy implements InvocationHandler{
private Object target; //传入要调用的目标对象
public Object bind(Object target) {
this.target = target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
//在代理实例上处理方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//执行方法
Object result = method.invoke(target, args);
return result;
}
}
动态代理的关键是实现InvocationHandler这个接口,查阅jdk文档我们可以知道:
nvocationHandler
是代理实例的调用处理程序 实现的接口。
每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke
方法
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
- 参数:
proxy
- 在其上调用方法的代理实例method
- 对应于在代理实例上调用的接口方法的Method
实例。Method
对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。args
- 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为null
。基本类型的参数被包装在适当基本包装器类(如java.lang.Integer
或java.lang.Boolean
)的实例中。- 返回:
- 从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。如果此方法返回的值为
null
并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出NullPointerException
。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,则代理实例上的方法调用将抛出ClassCastException
。 - 抛出:
Throwable
- 从代理实例上的方法调用抛出的异常。该异常的类型必须可以分配到在接口方法的throws
子句中声明的任一异常类型或未经检查的异常类型java.lang.RuntimeException
或java.lang.Error
。如果此方法抛出经过检查的异常,该异常不可分配到在接口方法的throws
子句中声明的任一异常类型,代理实例的方法调用将抛出包含此方法曾抛出的异常的
所以我们要提供绑定需要调用的目标对象的方法进行绑定: public Object bind(Object target) {
this.target = target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
接下来,是一个测试
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//InvocationHandler 是代理实例的调用处理程序 实现的接口
public class BookAutoProxy implements InvocationHandler{
private Object target; //传入要调用的目标对象
public Object bind(Object target) {
this.target = target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
//在代理实例上处理方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//执行方法
Object result = method.invoke(target, args);
return result;
}
}
- Java代理之代理模式
- java代理模式---静态代理
- java代理模式--动态代理
- 代理模式&java动态代理
- JAVA代理模式--静态代理
- JAVA代理模式--动态代理
- JAVA动态代理 代理模式
- Java代理模式-静态代理
- java代理模式-动态代理
- Java代理模式 静态代理 动态代理
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- Java代理模式和kotlin代理模式
- Java中的代理模式
- 算法导论 第11章 散列表
- jQuery 版本支持 IE
- 学习SVM
- Sizeof与Strlen的区别与联系(面试题)
- (群+波利亚定理)
- JAVA代理模式
- 黑马程序员——java主函数详细讲解
- Windows下手动完全卸载Oracle
- php语法基础之赋值符号
- ios CADisplayLink
- 【源码】Timer和TimerTask源码剖析
- varchar、char和Nvarchar\nchar区别
- [概念]__bridge、__bridge_transfer和__bridge_retained详解
- 九度oj-1068-球的半径和体积