使用动态代理解决方法调用前后添加日志信息
一般情况,在每个调用的方法中直接添加日志信息,存在如下问题:
1.代码混乱:越来越多的非业务需求加入(如日志和验证等)后,原有的业务方法急剧膨胀,每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点;
2.代码分散:以日志需求为例,只是为了满足这个单一的需求,就不得不在多个模块里多次重复相同的日志代码,如果日志需求发生变化,必须修改所有的模块。
针对以上问题,使用动态代理带解决。
代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理取代原始对象。任何原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
1.先定义一个接口
public interface Calc { int add(int i,int j); int sub(int i,int j); int multi(int i,int j); int div(int i,int j); }
2.定义一个接口的实现类,如
public class CalcImpl implements Calc{ public int add(int i, int j) { int result =i+j; return result; } public int sub(int i, int j) { int result =i-j; return result; } public int multi(int i, int j) { int result =i*j; return result; } public int div(int i, int j) { int result =i/j; return result; } }
3.定义代理类
public class CalcLoggingProxy { //要代理的对象 private Calc target; public CalcLoggingProxy(Calc target) { this.target=target; } public Calc getLoggingProxy(){ Calc proxy=null; //代理对象由哪一个类加载器加载 ClassLoader loader=target.getClass().getClassLoader(); //代理对象的类型,即其中有哪些方法 Class[] interfaces = new Class[]{Calc.class}; //当调用代理对象其中的方法试,就执行该方法 InvocationHandler h=new InvocationHandler() { /** * proxy:正在返回的代理对象,一般情况下很少使用 * method:正在调用的方法 * args:调用方法时,传入的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("the method "+method.getName() +" begin with"+ Arrays.asList(args)); //执行target的方法,即执行代理对象的方法 Object result=method.invoke(target, args); System.out.println("the method "+method.getName() +" end with "+result); return result; } }; proxy=(Calc) Proxy.newProxyInstance(loader, interfaces, h); return proxy; } }
4.写个main方法测试效果
public static void main(String[] args) { Calc target =new CalcImpl(); Calc proxy =new CalcLoggingProxy(target).getLoggingProxy(); int result=proxy.add(1, 2); System.out.println("--->"+result); }
结果如下:
the method add begin with[1, 2]
the method add end with 3
--->3
用动态代理可以解决问题,但是用过spring的同学,肯定非常清楚spring中的AOP能轻松的解决此问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现