Spring框架 AOP(动手模拟Spring的AOP)(二)

本文介绍了面向切面编程(AOP)的概念及其在Spring框架中的应用。通过实例演示了如何使用动态代理来实现在方法调用前后增加日志记录等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单来说,spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。

1、AOP简述

面向对象强调“一切皆对象”,是对真实世界的模拟。然而面向对象也并不是完美无缺,它更注重于对象层次结构方面的东西,对于如何更好的管理对象行为内部结构,还存在些许不足。那么如何使这个问题得到更完美的解决呢?答案就是AOP。

说到AOP,我们就不得不提一下软件的纵向和横向问题,从纵向结构来看我们软件系统的各个模块,它主要负责处理我们的核心业务,(例如:商品订购、购物车查看);而从横向结构来看,我们几乎每个系统有包含公共的模块(例如:权限、日志模块等),这些公共模块分布在我们各个核心业务之中(例如订购和查看商品明细的过程都需要检查用户权限、记录系统日志等)
这样一来不仅在开发过程中要处处关注公共模块的处理而且开发后维护起来也是十分麻烦。而有了AOP之后将应用程序中的商业逻辑同对其提供支持的通用服务进行分离,使得开发人员可以更多的关注核心业务开发。

这里写图片描述

2、利用动态代理实现AOP

下面我们就以一个简单的例子来看一下AOP吧!
比如说,我们现在要开发的一个应用里面有很多的业务方法,但是,我们现在要对这个方法的执行做全面监控,或部分监控.也许我们就会在要一些方法执行前进行日志记录,我们写个例子看看我们最简单的解决方案
我们先写一个接口UserManager.java代码如下:

publicinterface UserManager {  
publicvoid add(String userId, String userName);  
}  

add方法里面只是将简单的字符串作为参数,而不是实体,勿怪,讲解的重点不是这里,我们去写个类实现UserManager接口

publicclass UserManagerImp implements UserManager {  

@Override  
publicvoid add(String userId, String userName) {  
System.out.println("成功执行:UserManagerImpl.add()userId-->>" + userId);  
}  
}  

现在我们要为这个业务方法加上日志记录的业务,我们在不改变原代码的情况下,我们会去怎么做呢?也许,你会去写一个类去实现UserManager接口,并依赖UserManagerImp这个类.代码如下:

public class UserManagerProxyimplements UserManager{    
 private UserManager userManager;    

 public UserManagerProxy(UserManager userManager){    
this.userManager= userManager;    
  }    
publicvoid addUser(String userId, String userName) {    
System.out.println("start-->>addUser()userId-->>" + userId);    
try{    
userManager.add(userId,userName);    

System.out.println("success-->>addUser()");    
}catch(Exceptione) {    
e.printStackTrace();    
System.out.println("error-->>addUser()");    
thrownew RuntimeException();    
}            
}    
}  

从上面的代码我们可以看出,UserManager 对象是被UserManagerProxy这个所谓的代理所创建的.这样,如果我们以后要把日志记录的功能去掉.那我们只要把得到userManager对象的的具体实现改为UserManager的就可以。上面的代码 就是对AOP的最简单的实现,但是我们接下来想,如果我们要在很多业务逻辑之前加日志的话,那么,我们是不是要去写很多个UserManagerProxy这样的类呢.其实也是一种很麻烦的事.在jdk1.3以后.jdk跟我们提供了一个API java.lang.reflect.InvocationHandler的类. 这个类可以让我们在JVM调用某个类的方法时动态的为些方法做些什么事.让我们把以上的代码改一下来看看效果.
我们一样的去写一个代理类.只不过.让这个类去实现java.lang.reflect.InvocationHandler接口,代码如下:

packagecom.java.drp.pattern;  

importjava.lang.reflect.InvocationHandler;  
importjava.lang.reflect.Method;  
importjava.lang.reflect.Proxy;  

publicclass LogHandler implements InvocationHandler {  
/** 
 * 要处理的对象(也就是我们要在方法前后加上业务逻辑的对象) 
 */  
privateObject targetObject;  

/** 
 * 动态生成方法被处理过后的对象 (写法固定) 
 * @param targetObject 
 * @return 
 */  
publicObject newProxyInstance(Object targetObject){  
this.targetObject= targetObject;  
returnProxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(), this);  
}  

/** 
 *要处理的对象中的每个方法会被此方法送去JVM调用,也就是说,要处理的对象的方法只能通过此方法调用 
 * 此方法是动态的,不是手动调用的 
 */  
@Override  
publicObject invoke(Object proxy, Method method, Object[] args)  
throwsThrowable {  
System.out.println("将要执行的方法:"+ method.getName());  

System.out.print("将要执行的方法中的参数:");  
for(int i = 0; i < args.length; i++) {  
System.out.print(args[i]+ " ");  
}  
System.out.println();  

Objectresult = null;  
try{  
//执行原来的方法之前记录日志   
 System.out.println(method.getName()+ "Method Start!");  
//JVM通过这条语句执行原来的方法(反射机制)   
result= method.invoke(targetObject, args);  

//执行原来的方法之后记录日志   
 System.out.println(method.getName()+ "Method End!");  
}catch (Exception e) {  
e.printStackTrace();  
throwe;  
}  
//返回方法返回值给调用者   
returnresult;  
}  

}  

该段代码的执行流程
这里写图片描述
运行结果:
将要执行的方法:add
将要执行的方法中的参数:001tch
addMethod Start!
添加用户成功
addMethod End!

从上面的例子我们看出,你的任何对象的方法执行之前要加上记录日志的操作都是可以的.LogHandler自动去代理执行被代理对象UserManagerImp中的每一个方法,通过java.lang.reflect.InvocationHandler接口就把我们的代理对象和被代理对象解藕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值