结构型设计模式之代理模式

网友投稿 593 2022-10-19

结构型设计模式之代理模式

结构型设计模式之代理模式

@TOC

代理模式

代理模式(Proxy Pattern)属于结构型模式。 它是指为其他对象提供一种代理以控制对这个对象的访问。 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 在代理模式中,创建具有现有对象的对象,以便向外界提供功能接口。 想在访问一个类时做一些控制的时候就可以是用代理模式。

分类

代理模式属于结构型模式,分为静态代理和动态代理。

1.静态代理:静态定义代理类

静态代理需要自己生成代理类

2.动态代理:动态生成代理类

动态代理不用亲自去实现,通常使用现成的API即可。目前普遍使用的是JDK自带的代理与CGLIB提供的类库。

主要角色

代理模式一般包含三种角色:

1.抽象主题角色(Subject)

2.真实主题角色(RealSubject)

该类也被称为被代理类,该类定义了代理所表示的真实对象,是负责执行系统真正的罗辑业务对象

3.代理主题角色(Proxy)

代理主题也被称为代理类,其内部特有RealSubject的引用,因此具备完全的对RealSubject的代理权。 客户端调用代理对象的方法,同时也调用被代理对象的方法,但是会在代理对象前后增加一些处理代码。可以理解为代码增强,实际上就是在原代码罗辑前后增加一些代码逻辑,而使调用者无感知。

作用

1.保护目标对象,将代理对象与真实被调用目标对象分离 2.增强目标对象 3.降低系统耦合性,提升扩展性

静态代理与动态代理的区别

1.静态代理只能通过手动完成代理操作,如果被代理类增加了新的方法,代理类需要同步增加,违背开闭原则。 2.动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原测。 3.若动态代理要对目标类的增强逻辑进行扩展,结合策略模式,只需要新增策略类便可完成,无须修改代理类的代码。

静态代理的基本使用

静态代理需要自己生成代理类 创建抽象主题 public interface ISubject { /** * 买票 */ void buyTickets(); } 创建真实主题 public class RealSubject implements ISubject { public void buyTickets() { System.out.println("进行买票操作"); } } 创建代理主题 public class Proxy implements ISubject { private ISubject subject; public Proxy(ISubject subject) { this.subject = subject; } public void buyTickets() { before(); subject.buyTickets(); after(); } public void before() { System.out.println("买票前的操作"); } public void after() { System.out.println("买票后的操作"); } } 客户端调用 public static void main(String[] args) { Proxy proxy = new Proxy(new RealSubject()); proxy.buyTickets(); }

买票前的操作 进行买票操作 买票后的操作

JDK动态代理的基本使用

创建抽象主题

public interface IUser { /** * 购物 */ void shopping(); }

创建真实主题

public class User implements IUser{ @Override public void shopping() { System.out.println("user shopping...."); } }

创建代理主题

public class JDKProxy implements InvocationHandler { private Object tarjet; public JDKProxy(Object tarjet) { this.tarjet = tarjet; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理user,执行shopping()开始..."); Object oj = method.invoke(tarjet, args); System.out.println("代理user,执行shopping()结束..."); return oj; } }

客户端调用

public static void main(String[] args) { User user = new User(); JDKProxy jdkProxy = new JDKProxy(user); IUser proxyInstance = (IUser) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), jdkProxy); proxyInstance.shopping(); }

代理user,执行shopping()开始... user shopping.... 代理user,执行shopping()结束...

小优化

在调用时候,传入了一推参数,可进一步优化

public class JDKProxy implements InvocationHandler { private Object tarjet; public Object JDKProxy(Object target){ this.tarjet = target; Class clazz = target.getClass(); return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理user,执行shopping()开始..."); Object oj = method.invoke(tarjet, args); System.out.println("代理user,执行shopping()结束..."); return oj; } }

public static void main(String[] args) { JDKProxy jdkProxy = new JDKProxy(); IUser user= (IUser)jdkProxy.JDKProxy(new User()); user.shopping(); }

CGLIB动态代理的基本使用

CGLIB动态代理也不需要生成代理类,实现MethodInterceptor 就可以了。

注意:CGLib不能代理final的方法

创建抽象主题

注意:CGLb代理的目标对象不需要实现任何接口,就可以通过动态继承目标对象实现动态代理。所以此处可以不用创建接口。直接使用真实主题。

public interface IUser { public void shopping(); }

创建真实主题

public class User implements IUser{ @Override public void shopping() { System.out.println("user shopping...."); } }

直接使用真实主题。

public class User { public void shopping() { System.out.println("user shopping...."); } }

创建代理主题

public class CglibProxy implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("代理user,执行shopping()开始..."); Object invokeSuper = methodProxy.invokeSuper(o, objects); System.out.println("代理user,执行shopping()结束..."); return invokeSuper; } }

客户端调用

public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(User.class); enhancer.setCallback(cglibProxy); IUser iUser = (IUser) enhancer.create(); iUser.shopping(); }

小优化

在客户端调用时,稍显复杂,可进一步优化

public class CglibProxy implements MethodInterceptor { public Object getInstance(Class clazz) throws Exception{ //相当于Proxy,代理工具类 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("代理user,执行shopping()开始..."); Object invokeSuper = methodProxy.invokeSuper(o, objects); System.out.println("代理user,执行shopping()结束..."); return invokeSuper; } }

public static void main(String[] args) throws Exception { IUser user = (IUser) new CglibProxy().getInstance(User.class); user.shopping(); }

CGLIB与JDK动态代理区别

1.执行条件

JDK动态代理实现了被代理对象的接口。CGLb代理的目标对象不需要实现任何接口,它是通过动态继承目标对象实现动态代理。

2.实现机制

JDK动态代理调用代理方法是由Java内部的反射机制来实现的,需要读取接口信息。CGLib动态代理是通过FastClass机制来实现的,需要覆盖父类方法。

3.性能

首先都在运行期生成字节码。 JDK动态代理的代理逻辑简单,直接写Class字节码,使用反射机制在生成类的过程中比较高效。 CGLib代理实现更复杂,使用ASM框架写Class字节码,但是asm在生成类之后的相关执行过程中比较高效。但是可以通过将asm生成的类进行缓存,解决asm生成类过程低效问题。 一句话:CGLib生成代理类比JDK动态代理效率低,但是执行效率比JDK动态代理高。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Workerman- 高性能 PHP socket 框架
下一篇:LBase-Android- 开发基础框架
相关文章

 发表评论

暂时没有评论,来抢沙发吧~