天津网站开发培训学校,国家企业信用信息公示系统官网山东,重庆网上核名,温州建网站业务人员一、什么是代理模式 代理模式属于结构型设计模式。为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下#xff0c;一个对象不适合或者不能直接引用另一个对象#xff0c;而代理对象可以在客户端和目标对象之间起到中介的作用。
二、分类 代理模式分为三类#…一、什么是代理模式 代理模式属于结构型设计模式。为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下一个对象不适合或者不能直接引用另一个对象而代理对象可以在客户端和目标对象之间起到中介的作用。
二、分类 代理模式分为三类 静态代理动态代理CGLIB代理 三、特点 优点
代理模式可以隐藏真是对象的实现细节使客户端无需知晓真实对象的工作方式和结构。 通过代理类来间接访问真实类可以在不修改真实类的情况下对其进行扩展、优化或添加安全措施。 代理模式实现起来简单易于扩展和维护符合面向对象设计原则中的开闭原则。 缺点
代理模式可能会引入额外的复杂性和间接性增加程序设计和维护的难度。 对象代理可能会降低系统性能特别是在处理大数据量或频繁调用的情况下因为代理需要额外的计算和网络通信开销。 四、应用场景 4.1 生活场景 Window是的快捷键。 支票、银行卡。 律师。 4.2 Java场景 AOP通过定义切面、切入点和通知等Spring AOP在运行时生成代理对象将切面逻辑织入到目标对象的方法调用中。代理对象在方法调用前后执行附加操作如日志记录、性能监控等。 动态代理JDK动态代理、CGLIB代理当Bean类实现了接口时Spring使用JDK动态代理来为Bean生成代理对象当Bean类没有实现接口时Spring使用CGLIB代理来生成代理对象。 五、代码实现 5.0 代码结构 下面就以房东和租客为例分别介绍一下静态代理、jdk动态代理和cglib代理。
5.1 静态代理 静态代理是一种在代码编写期进行代理类和被代理类的关联的代理方式。
具体实现是创建一个代理类通常需要实现与被代理类相同的接口或继承被代理类。 房东接口类Landlord1Service
注意静态代理实现它的真实对象只能有一个多个的话代理对象不能确定哪个对象需要被代理会导致报错JDK动态代理没这个问题
/*** 房东* */
public interface Landlord1Service {/*** 出租* param money 金额* return*/void rent(Integer money);
}
租客TenantImpl/*** 租客* author Created by njy on 2023/5/30*/
Component
public class TenantImpl implements Landlord1Service {Overridepublic void rent(Integer money) {System.out.println(租下money元一个月的房子);}
}静态代理ProxyImpl
/*** 中介* */
Component
public class ProxyImpl implements Landlord1Service {/*** 房东有很多套房子不想亲自出马了于是找来了中介*/Autowiredprivate Landlord1Service target;/*** 优点就是在不改变原来的实现类的情况下对方法实现了增强* 缺点是如果原来的接口新增了方法那么这里也要对应实现新的方法* param money 金额* return*/Overridepublic void rent(Integer money) {System.out.println([静态代理]交中介费);target.rent(money);System.out.println([静态代理]中介负责维修管理);}
}测试 SpringBootTest
public class TestProxy {Autowiredprivate TenantImpl tenant;Autowiredprivate ProxyImpl proxy;//1.静态代理Testvoid TestStatic(){tenant.rent(1000);System.out.println();proxy.rent(2000);}
}
适用场景 对象必须实现一个或多个接口 代理类的代理方法不需要额外的逻辑 5.2 JDK动态代理 JDK动态代理是一种比较常见的代理方式它是在程序运行时动态生成代理类也就是说我们在编写代码时并不知道具体代理的是什么类而是在程序运行时动态生成。
房东接口类Landlord2Service
public interface Landlord2Service {/*** 出租* param money* return*/void rent(Integer money);
}租客1Teant1Impl
Component
public class Teant1Impl implements Landlord2Service{Overridepublic void rent(Integer money) {System.out.println(tenant1租下money元一个月的房子);}
}租客2Teant2Impl Component
public class Tenant2Impl implements Landlord2Service {Overridepublic void rent(Integer money) {System.out.println(tenant2租下money元一个月的房子);}
}JDK动态代理JDKProxy
/*** JDK动态代理就是把代理抽象了一下* */
public class JDKProxy {private Object target;public JDKProxy(Object target){this.targettarget;}/*** 给目标对象生成代理对象* return 代理生成的对象*/public Object getProxyInstance(){return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),//这里是要实现jdk代理InvocationHandler的接口lambda表达式(proxy,method,args)-{//执行对象方法System.out.println([JDK动态代理]交中介费);method.invoke(target,args);System.out.println([JDK动态代理]中介负责维修管理);return null;});}
}Test SpringBootTest
public class TestProxy {Autowiredprivate Teant1Impl teant1;Autowiredprivate Tenant2Impl tenant2;//2.JDK动态代理Testvoid TestJDK(){Landlord2Service proxyInstance1 (Landlord2Service) new JDKProxy(teant1).getProxyInstance();proxyInstance1.rent(2500);System.out.println();Landlord2Service proxyInstance2 (Landlord2Service) new JDKProxy(tenant2).getProxyInstance();proxyInstance2.rent(2500);}
}适用场景 对象必须实现一个或多个接口 代理类的代理方法不需要额外的逻辑 5.3 Cglib代理 CGLIB代理是在运行时动态生成代理类的方式它使用的库是cglib和JDK代理相比它不是动态的生成一个实现了接口的代理类而是直接在内存中构建一个被代理类的子类并重写父类的方法来进行代理。 房东类Landlord3Service
Component
public class Landlord3Service {/*** 出租房屋* param money* return*/public void rent(Integer money){System.out.println(租下money元一个月的房子);}
}Cglib代理类CglibProxy
/*** JDKProxycglib子类代理工厂* 1.代理的类不能为final* 2.目标对象的方法如果为final/static那么就不会被拦截也不会执行目标对象的业务方法* */
public class CglibProxy implements MethodInterceptor {/*** 目标对象*/private final Object target;public CglibProxy(Object target){this.targettarget;}public Object getProxyInstance(){//1.工具类Enhancer ennew Enhancer();//2.设置父类en.setSuperclass(target.getClass());//3.设置回调函数en.setCallback(this);//4.创建子类代理对象return en.create();}Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println([Cglib代理]交中介费);method.invoke(target,objects);System.out.println([Cglib代理]中介负责维修管理);return null;}
}测试 SpringBootTest
RequiredArgsConstructor
public class TestProxy {Autowiredprivate Landlord3Service landlord3Service;//3.Cglib代理Testvoid TestCglib(){Landlord3Service proxyInstance (Landlord3Service) new CglibProxy(landlord3Service).getProxyInstance();proxyInstance.rent(3000);}
}适用场景 被代理的类没有实现接口或者无法实现接口 代理类的代理方法需要进行额外的逻辑如事务处理等。 六、总结 对于没有实现接口的类只能使用CGLIB代理 对于实现了接口的类可以使用JDK代理或者CGLIB代理如果要求比较高的话建议使用JDK代理。 对于单个代理类的情况并且被代理类实现了接口可以使用静态代理。 对于多个被代理类的情况建议使用JDK代理或CGLIB代理。