贵州省建设厅网站查,辽宁建设工程信息网 招标文件,推荐一本学做网站的书,什么是电商怎么做电商目录
概述
一. 什么是代理模式
1. 举例说明
二. 代理模式作用
1. 保护代理
2. 增强功能
3. 代理交互
4. 远程代理#xff1a;
三. 代理模式3个角色
四. 静态代理
1. 代码示例#xff1a;
五. JDK动态代理
1. 代码示例#xff1a;
六. CGLIB 动态代理
1.代码示…目录
概述
一. 什么是代理模式
1. 举例说明
二. 代理模式作用
1. 保护代理
2. 增强功能
3. 代理交互
4. 远程代理
三. 代理模式3个角色
四. 静态代理
1. 代码示例
五. JDK动态代理
1. 代码示例
六. CGLIB 动态代理
1.代码示例 七. JDK动态代理和CGLIB动态代理区别
八. 两种在spring的使用 概述 代理模式Proxy Pattern是设计模式中的一种结构型模式其核心思想是通过创建一个代理对象来间接访问实际对象也称为主题对象从而在不改变实际对象的前提下为实际对象添加额外的功能或控制。 代理模式根据实现方式可分 接口实现某个类必须有实现的接口如果某个类没有实现接口那么这个类就不能通过 JDK 产生动态代理了 静态代理动态代理继承实现是 CGLIB 通过动态生成一个需要被代理类的子类即被代理类作为父类该子类重写被代理类的所有不是 final 修饰的方法使用 Java 反射技术创建代理类的实例CGLIB 是一个第三方库 一. 什么是代理模式 代理模式就是给一个对象提供一个代理并由代理对象控制对原对象的引用。它使得客户不能直接与真正的目标对象通信。代理对象是目标对象的代表其他需要与这个目标对象打交道的操作都是和这个代理对象在交涉。 代理对象可以在客户端和目标对象之间起到中介的作用这样起到了的作用和保护了目标对象的同时也在一定程度上面减少了系统的耦合度。
1. 举例说明 以卖房为例房东 A 要卖房客户 B 要买房 没有代理模式情况 房东 A 要卖房可能要贴小广告卖房带买家 B 来看房买家 B 非常满意交易达成出售成功 使用代理模式 房东 A 要卖房找到代理 C 由 C 去做卖房信息发布代理 C 带有购买意向的客户看房买家 B 很满意交易达成 在这个例子中房东只需找到代理即可其他发布房源信息和看房都由代理去做。 二. 代理模式作用
1. 保护代理 代理可以为实际对象提供一层保护确保对象不会被不信任的调用者直接访问。 2. 增强功能 在程序中需要给某个对象的功能进行功能增强的时候可以考虑找一个代理进行增强例如:Spring 框架中的 AOP 切面编程就是对代理模式的经典应用。 3. 代理交互 在程序中A对象无法和B对象直接交互时也可以使用代理模式来解决。 4. 远程代理 代理可以作为远程对象的本地代表隐藏对象位于不同地址空间的事实使得远程调用就像本地调用一样。 三. 代理模式3个角色
目标对象目标对象也就是被代理对象对应着被代理类代理对象代理对象对应着代理类公共接口目标对象和代理对象的公共接口目标对象和代理对象都需要实现这个接口。注意在JDK中是通过接口实现代理的但是在cglib中使用的是继承来实现动态代理的
UML图 四. 静态代理 静态代理实现相对来比较简单静态代理是代理模式中较简单的一种模式它在编译时就已经确定代理类和目标类的关系。
1. 代码示例
创建公共接口 package com.demo.proxy;/*** 文件名Subject* 创建者* 创建时间2024-09-05* 描述公共接口*/
public interface Subject {void info();
}创建目标类 package com.demo.proxy;/*** 文件名RealSubject* 创建者* 创建时间2024-09-05* 描述 目标类*/
public class RealSubject implements Subject{Overridepublic void info() {System.out.println(被代理对象方法执行。。。);}
}创建代理类 package com.demo.proxy;/*** 文件名ProxySubject* 创建者* 创建时间2024-09-05* 描述 代理类*/
public class ProxySubject implements Subject{private Subject subject;public ProxySubject(Subject subject) {this.subject subject;}Overridepublic void info() {perReqs();subject.info();postReqs();}private void perReqs(){System.out.println(记录请求日志);}private void postReqs(){System.out.println(记录响应日志);}}测试类 package com.demo.proxy;/*** 文件名Main* 创建者* 创建时间2024-09-05* 描述 测试类*/
public class Main {public static void main(String[] args) {//1.创建目标对象Subject subject new RealSubject();//2.创建代理对象(将目标对象传入代理对象构造中)Subject sub new ProxySubject(subject);sub.info();}
}测试结果
五. JDK动态代理 java.lang.reflect 包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。 代理类在程序运行时利用反射机制动态创建而成主要分为jdk动态代理和cglib动态代理。 JDK 动态代理类的字节码在程序运行时由 Java 反射机制动态生成无需手工编写它的源代码。 动态代理类不仅简化了编程工作而且提高了软件系统的可扩展性因为 Java 反射机制可以生成任意类型的动态代理类。 1. 代码示例
参数说明 Proxy类的静态方法 newProxyInstance() 参数: loader类加载器使用本类的类加载器即可或者 target 对象的类加载器也行。interfaces接口数组表示被代理类实现的接口因可能会实现多个接口所以这里是数组的形式。InvocationHandler核心在这里创建一个内部实现类实现InvocationHandler接口重写invoke方法 invoke 里的参数 proxy 是代理类的实例method是代理类的实例执行的方法args则是执行的方法里面的参数 我们可以在这里对执行核心业务逻辑前后增加代码。method.invoke(target, args)这里是用了反射的原理让target对象去执行method方法。 定义接口 package com.demo.proxy.dynamic;/*** 文件名UserService* 创建者* 创建时间2024-09-05* 描述业务服务接口*/
public interface IUserService {boolean login(String name,String pwd);void signOut(String name);
}定义接口实现类也就是业务实现类 package com.demo.proxy.dynamic;/*** 文件名UserService* 创建者* 创建时间2024-09-05* 描述业务实现类*/
public class UserService implements IUserService{/*** 登录* param name* param pwd* return*/Overridepublic boolean login(String name,String pwd) {System.out.println(name:登录成功);return true;}/*** 退出* param name*/Overridepublic void signOut(String name) {System.out.println(name : 退出成功);}
}定义代理类无需实现接口 package com.demo.proxy.dynamic;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 文件名DefineProxy* 创建者* 创建时间2024-09-05* 描述动态代理类*/
public class DefineProxy {private Object target;public DefineProxy(Object target){this.target target;}public Object createProxy(){return Proxy.newProxyInstance(DefineProxy.class.getClassLoader(), this.target.getClass().getInterfaces(), new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {perName(method.getName());Object invoke method.invoke(target, args);postName(method.getName());return invoke;}});}/*** 前置方法* param name*/private void perName(String name){System.out.println(name方法-前置执行);}/*** 后置方法* param name*/private void postName(String name){System.out.println(name方法-后置执行);}
}定义测试类 package com.demo.proxy.dynamic;/*** 文件名Main* 创建者* 创建时间2024-09-05* 描述测试类*/
public class Main {public static void main(String[] args) {//1.创建目标对象UserService userService new UserService();//2.创建代理对象DefineProxy defineProxy new DefineProxy(userService);//3.调用生成代理方法IUserService proxy (IUserService) defineProxy.createProxy();//4.代理执行方法boolean flg proxy.login(小明,12345);System.out.println(返回值flg);System.out.println();proxy.signOut(小明);}
}测试结果截图 修改动态代理类通过实现 InvocationHandler 接口来实现代理 package com.demo.proxy.dynamic;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** 文件名DefineProxyTwo* 创建者宁贝贝* 创建时间2024-09-05* 描述动态代理类通过实现接口*/
public class DefineProxyTwo implements InvocationHandler {private Object target;public DefineProxyTwo(Object target){this.target target;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {perName(method.getName());Object res method.invoke(target,args);postName(method.getName());return res;}/*** 前置方法* param name*/private void perName(String name){System.out.println(name方法-前置执行);}/*** 后置方法* param name*/private void postName(String name){System.out.println(name方法-后置执行);}
}修改测试类 package com.demo.proxy.dynamic;import java.lang.reflect.Proxy;/*** 文件名MainTwo* 创建者* 创建时间2024-09-05* 描述测试类*/
public class MainTwo {public static void main(String[] args) {//1.创建被代理对象UserService userService new UserService();//2.获取被代理对象的类加载器用作生成代理对象的必要参数ClassLoader classLoader userService.getClass().getClassLoader();//3.获取被代理对象的实现接口// 用作生成代理对象的必要参数// 方法映射就是基于这个参数实现的Class?[] interfaces userService.getClass().getInterfaces();//4.获取被代理对象的增强主题类用作生成代理对象的必要参数DefineProxyTwo defineProxyTwo new DefineProxyTwo(userService);//5.生成代理对象的核心代码IUserService proxyInstance (IUserService) Proxy.newProxyInstance(classLoader, interfaces, defineProxyTwo);// 使用代理对象执行方法proxyInstance.login(星星,765432);System.out.println();proxyInstance.signOut(星星);}
}六. CGLIB 动态代理 JDK 中提供的生成动态代理类的机制有个鲜明的特点是某个类必须有实现的接口如果某个类没有实现接口那么这个类就不能通过 JDK 产生动态代理了。 CGLIBCode Generation Library是一个强大的、高性能、高质量的Code生成类库它可以在运行期扩展Java类与实现Java接口。 CGLIB 通过动态生成一个需要被代理类的子类即被代理类作为父类该子类重写被代理类的所有不是 final 修饰的方法并在子类中采用方法拦截的技术拦截父类所有的方法调用进而织入横切逻辑。此外因为 CGLIB 采用整型变量建立了方法索引这比使用 JDK 动态代理更快使用 Java 反射技术创建代理类的实例。 CGLib 创建某个类 A 的动态代理类的模式是
查找 A 上的所有非 final 的 public 类型的方法定义将这些方法的定义转换成字节码将组成的字节码转换成相应的代理的 class 对象实现 MethodInterceptor 接口用来处理 对代理类上所有方法的请求这个接口和JDK动态代理InvocationHandler的功能和角色是一样的
1.代码示例
定义普通业务类 package com.demo.proxy.cglib;/*** 文件名UserService* 创建者* 创建时间2024-09-05* 描述一个普通的业务类*/
public class UserService{/*** 登录* param name* param pwd* return*/public boolean login(String name,String pwd) {System.out.println(name:登录成功);return true;}/*** 退出* param name*/public void signOut(String name) {System.out.println(name : 退出成功);}
}定义CGLIB动态代理类 package com.demo.proxy.cglib;import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** 文件名CGLibProxy* 创建者* 创建时间2024-09-05* 描述cglib动态代理类*/
public class CGLibProxy implements MethodInterceptor {private Object target;public CGLibProxy(Object target) {this.target target;}public Object createProxy(){//cglib中的增强器用来创建动态代理Enhancer enhancer new Enhancer();//设置要创建动态代理的类enhancer.setSuperclass(target.getClass());//设置回调这里相当于是对于代理类上所有方法的调用都会调用callback而callback则需要实现intercept()方法进行拦截。enhancer.setCallback(this);//创建代理类return enhancer.create();}Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println(cglib 代理开始...);Object object proxy.invokeSuper(obj,args);System.out.println(cglib 代理结束...);return object;}
}定义测试类 package com.demo.proxy.cglib;/*** 文件名Main* 创建者* 创建时间2024-09-05* 描述测试类*/
public class Main {public static void main(String[] args) {//1.创建被代理对象UserService userService new UserService();//2.创建CGLibProxy对象CGLibProxy cgLibProxy new CGLibProxy(userService);//3.调用createProxy创建代理对象UserService proxy (UserService)cgLibProxy.createProxy();//4.代理执行方法boolean res proxy.login(晓月,5676543);System.out.println(登录结果res);System.out.println(--------------------------------);proxy.signOut(晓月);System.out.println();//其实上面那几个步骤可以一行代码全搞定UserService us (UserService)new CGLibProxy(new UserService()).createProxy();boolean result us.login(小红,13123123);System.out.println(登录结果result);System.out.println(--------------------------------);us.signOut(小红);}
}测试结果 七. JDK动态代理和CGLIB动态代理区别
实现原理JDK动态代理是基于Java反射机制实现的它要求目标类必须实现一个或多个接口代理对象在运行时动态创建通过实现目标类接口的方式来代理目标类。 CGLIB代理则是基于ASM字节码框架实现的它可以代理没有实现接口的目标类。CGLIB在运行时通过动态生成目标类的子类来实现代理。性能表现JDK动态代理因为需要实现目标类接口所以它的性能相对较低但是它的应用场景更为广泛适用于大多数情况下的代理需求。 CGLIB代理则因为不需要实现目标类接口所以它的性能相对较高但是它不能代理final类和final方法以及一些无法生成子类的类。应用场景JDK动态代理适用于代理接口的场景例如Spring中的事务处理、日志记录等。 CGLIB代理适用于代理类的场景例如Spring中的AOP切面编程等。
八. 两种在spring的使用 如果被代理对象实现了需要被代理的接口则使用 JDK 的动态代理否则便使用 CGLIB 代理在spring中它会自动根据使用情况进行切换但是如果你缺少CGLIB依赖肯定是会报错。需要添加 cglib 依赖包。 dependencygroupIdcglib/groupIdartifactIdcglib/artifactIdversion3.3.0/version
/dependency