5、动态代理
1、介绍
切面编程 AOP
业务对象的的每个方法都要进行性能统计,存在大量重复的代码
代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的
Proxy 方法: public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
动态代理的优点
- 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接口本身做代理
- 可以为被代理对象的所有方法做代理
- 可以在不改变方法源码的情况下,实现对方法功能的增强
- 不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率
关键步骤
- 必须有接口,实现类要实现接口(代理通常是基于接口实现的)
- 创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象
动态代理:目标对象 + 代理逻辑 = 代理对象
- JDK:代理对象和目标对象出于同一个接口之下
- CGLib:代理对象是目标对象的子对象
// 接口 public interface UserService { String login(String loginName, String password); void selectUsers(); boolean deleteUsers(); }
// 实现类 public class UserServiceImpl implements UserService { @Override public String login(String loginName, String password) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if ("admin".equals(loginName) && "123".equals(password)) return "success"; return "fail"; } @Override public void selectUsers() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("账号: admin, 密码: 123"); } @Override public boolean deleteUsers() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return false; } }
2、JDK 动态代理
JDK 动态代理,依赖接口
// 代理实现统计方法耗时 public class ProxyUtil { // 泛型方法: 为任何对象做代理 public static <T> T getProxy(T obj) { return (T) Proxy.newProxyInstance( obj.getClass().getClassLoader(), // 类加载器, 负责加载代理类到内存中使用 obj.getClass().getInterfaces(), // 获取代理类实现的全部接口 new InvocationHandler() { // 代理逻辑 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 参数一: 代理对象本身, 一般不管 // 参数二: 正在被代理的方法 // 参数三: 被代理方法传入的参数 long startTime = System.currentTimeMillis(); Object result = method.invoke(obj, args); // 业务代码 long endTime = System.currentTimeMillis(); System.out.println(method.getName() + " 耗时: " + (endTime - startTime) / 1000.0); return result; } }); } }
// 测试 public class Test { public static void main(String[] args) { UserService userService = ProxyUtil.getProxy(new UserServiceImpl()); System.out.println(userService.login("admin", "123")); userService.selectUsers(); userService.deleteUsers(); } } // login 耗时: 1.014 // success // 账号: admin, 密码: 123 // selectUsers 耗时: 1.013 // deleteUsers 耗时: 1.012
3、CGLib 动态代理
CGLib 动态代理,不依赖接口,但是不能对声明为 final 的类或者方法进行代理,因为 CGLib 原理是动态生成被代理类的子类
public class CGLibProxyUtil { public static <T> T getProxy(T obj) { // 1. 创建 Enhancer 对象, 类似 JDK 代理中的 Proxy 类 Enhancer enhancer = new Enhancer(); // 2. 设置父类的字节码对象 enhancer.setSuperclass(obj.getClass()); // 3. 设置回掉函数 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { /* o 代理对象 method 真实对象中的方法的 Method 实例 args 实际参数 methodProxy 代理对象中的方法的 method 实例 */ long startTime = System.currentTimeMillis(); Object result = method.invoke(obj, args); // 业务代码 long endTime = System.currentTimeMillis(); System.out.println(method.getName() + " 耗时: " + (endTime - startTime) / 1000.0); return result; } }); // 4. 创建代理对象(属于目标对象类的子类的对象) return (T) enhancer.create(); } }
4、更多
本文来自博客园,作者:lidongdongdong~,转载请注明原文链接:https://www.cnblogs.com/lidong422339/p/17473107.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步