代理模式
来源:互联网 发布:pspice仿真软件下载 编辑:程序博客网 时间:2024/06/07 13:06
代理模式
代理模式:为其他对象提供一种代理以控制对这个对象的访问。
代理模式结构图如下:
代理模式结构图代码解析:
//代理类和真实类的公共接口(接口或抽象类)public abstract class Subject{ public abstract void request();}
//真实类,RealSubject类,定义 Proxy类所代表的真实实体public class RealSubject extends Subject{ @Override public void reqeust(){ print("真实的请求...."); }}
//代理类,Proxy类,用来保存一个引用使得代理可以访问实体,并提供一个与Subject接口相同的接口,这样代理类就可以替代实体。public class Proxy extends Subject{ RealSubject realSubject; //Spring的DI在这里挺好用 //调用Proxy的request方法就等于调用真实类的reqeust方法 @Override public void reqeust(){ if(realSubject == null){ realSubject = new RealSubject(); } realSubject.Reqeust(); }}
//客户端代码public class Main{ public static void main(String[] args){ //创建代理类 Proxy proxy = new Proxy(); proxy.reqeust(); //内部实质调用了真实类的request()方法 }}
代理模式的应用:
①远程代理:也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。
②. 虚拟代理:是根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的对象。这样可以达到性能的优化,比如在打开一个很大的HTML网页,里面有很多文字和图片,但还是可以很快的打开它,此时会先看到文字,而图片是一张一张下载后才能看到。那些没有打开的图片框,就是通过虚拟代理替代了真实的图片,此时代理存储了真实图片的路径和尺寸。
③. 安全代理:用来控制对真实对象访问时的权限。一般用于对象应该有不同访问权限的时候。
④. 智能代理:指当调用真实对象时,代理处理另外一些事。
上述代理模式是最简单的一种代理,即静态代理。静态代理的优点是:可以在不修改原类的情况下,对原来的类进行扩展。但它的缺点也很明显:因为代理类要和目标对象类实现相同的接口,因此会有很多代理类,并且如果接口中增加方法,代理类和目标对象类都要进行维护。
解决静态代理缺点的方式就是使用动态代理。
动态代理的优点有哪些?
①. 代理类不用实现和目标类一样的接口。
②. 代理对象的产生是利用JDK的API,动态的在内存中构建代理对象<需要我们指定创建代理对象/目标对象实现的接口的类型>。
③. 动态代理,也称jdk代理,接口代理。
JDK中生成代理对象的API:
代理类所在的包:java.lang.reflect.Proxy
JDK实现代理需要使用一个方法:newProxyInstance方法,该方法有三个参数。方法的完整写法时:static Object newProxyInstance(ClassLoader loader,Class
/** * Created by 杨Sir on 2017/11/14. * 动态代理的接口 */public interface IGiveGift { //送花的方法 void GiveFlowers();}
/** * Created by 杨Sir on 2017/11/14. */public class Girl { private String name; public Girl() { } public String getName() { return name; } public void setName(String name) { this.name = name; }}
/** * Created by 杨Sir on 2017/11/14. * 目标类 */public class Pursuit implements IGiveGift { Girl girl; public Pursuit(Girl girl) { this.girl = girl; } @Override public void GiveFlowers() { System.out.println(girl.getName()+ ": 送你鲜花。"); }}
/** * Created by 杨Sir on 2017/11/14. * 动态代理类,创建代理对象, * 不要实现接口,但要指定和目标对象一样的接口类型 */public class DynamicPorxy { //维护一个目标对象 private Object target; public DynamicPorxy(Object target) { this.target = target; } //给目标对象生成代理对象 public Object getProxyInstance(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("去买鲜花"); //执行目标对象的方法 Object returnValue = method.invoke(target,args); System.out.println("送花完成"); return returnValue; } }); }}
public class Main { public static void main(String[] args) { //创建一个Girl对象 Girl girl = new Girl(); girl.setName("校花"); //目标对象 Pursuit pursuit = new Pursuit(girl); //根据目标对象生成代理对象,这个代理对象在不改动目标类的情况下扩展了目标类的功能。 IGiveGift giveGift = (IGiveGift) new DynamicPorxy(pursuit).getProxyInstance(); //调用代理对象的方法 giveGift.GiveFlowers(); }}
需要注意的是,使用动态代理时,代理类虽然不需要实现接口,但是目标对象类一定要实现接口,否则不能用动态代理。
上面的两种代理方式都需要目标类实现一个接口,当如果目标类没有实现接口的话,那怎么创建目标对象的代理对象呢?答案是使用 Cglib 代理。
前面说的静态代理和动态代理都需要目标对象实现一个接口,当如果目标类没有实现任何接口的话,那怎么创建目标对象的代理对象呢?答案是使用 Cglib代理。
Cglib代理,也叫做子类代理,它通过在内存中构建一个子类对象从而实现对目标对象的扩展。
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就需要使用Cglib代理实现。
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP,进而为他们提供方法的interception(拦截)。
Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
Cglib代理的实现方法:
引入Cglib的jar包, 幸运的是Spring的core包已经引入了CGLIB的jar包,所以使用Spring的项目不用再次引入cglib的jar。
引入jar后,即可在内存中构建代理目标类的子类。
代理的类不能加 final。
目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象之外的业务方法。
在Spring的面向切面编程(aop)中,如果加入容器的目标对象实现了接口,用动态代理,否则用 CGLIB代理。
举个简单例子看一下:
/** * Created by 杨Sir on 2017/11/15. * 目标类 */public class Pursuit { public void GiveFlowers() { System.out.println("我是目标类。"); }}
/** * Created by 杨Sir on 2017/11/15. * CGLIB代理 创建目标对象的代理对象 */public class CglibProxy implements MethodInterceptor { //维护目标对象 private Object target; public CglibProxy(Object target) { this.target = target; } //为目标对象创建代理对象 public Object getProxyInstance(){ //工具类 Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(target.getClass()); //设置回调函数 enhancer.setCallback(this); //创建代理对象(目标类的子类) return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("购买鲜花..."); //执行目标对象的方法 Object returnVal = method.invoke(target,objects); //传入目标对象和方法的参数 System.out.println("送花完成...很开心"); return returnVal; }}
/** * Created by 杨Sir on 2017/11/15. * 测试 */public class Main { public static void main(String[] args) { //创建目标对象 Pursuit pursuit = new Pursuit(); //代理对象 Pursuit proxy = (Pursuit) new CglibProxy(pursuit).getProxyInstance(); //执行代理对象方法,送花 proxy.GiveFlowers(); }}
- 代理模式--动态代理
- 代理模式-静态代理
- 代理模式-静态代理
- 代理模式 & 动态代理
- 代理模式--静态代理
- 代理模式--动态代理
- 代理模式(动态代理)
- 代理模式-动态代理
- 代理模式-动态代理
- 代理模式动态代理
- 代理模式-静态代理
- 代理模式-动态代理
- 代理模式 -动态代理
- 代理模式---动态代理
- 代理模式-动态代理
- 代理模式--静态代理
- 代理模式!
- 代理模式
- PAT 乙级 1001 害死人不偿命的(3n+1)猜想 (15)
- **方程组求解的切比雪夫半迭代加速方法**
- 文章标题
- JavaScript数组去重
- C函数指针基础
- 代理模式
- 构建Maven多模块项目+SSM框架整合(一)
- redis知识盘点【零】_redis常用命令
- Material Design控件之TextInputLayout
- 菲戈挑战足球守门员机器人原理
- 封闭还是开放?创新才是关键
- scrapy里面的response参数了解
- Java反射的使用
- 独轮车