是什么?
面向切面编程,把那些与业务无关,却为业务模块所共同调用的逻辑封装成一个可重的模块,即切面
使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点
为什么使用?
一.开发的痛点
我们在初学习Java Web的时候,应该都经历了以下的阶段:
(1)一个主函数main中包含了所有的方法;
(2)面向对象,
(3)分层,每一层负责不同的功能
`
在面向对象的大环境下,我们可以很好地组织代码,通过继承、封装和多态的思想去设计一个个比较让人满意的类,但是我们慢慢的发现,我们的代码中逐渐多了很多重复性的代码,有人可能会想到,把这些重复性的代码抽取出来不就好了吗?是这样的,我们看一下这种思路的一个实例:
/**
* 根据id 查询用户
*/
try{
userService.selectUserById(0);
}catch(Exception e){
e.printStackTrace();
}
/**
* 添加用户信息
*/
try{
userService.addUser();
}catch(Exception e){
e.printStackTrace();
}
可以看到,上述代码功能上确实可以实现,但是我们的业务代码已经被这些非核心的代码所混淆,并且占据了大量的空间!显然这种显示的调用过程成为了我们开发过程中的一个痛点,如何将类似这种的非核心的代码剥离出去成为一个迫切需要解决的问题!
诸如此类,还有数据库事务的控制,数据库连接的创建和关闭等等,这些都充斥这大量重复性的模板代码!一个很现实的问题,假如有一天,业务需求不需要进行日志记录了,那岂不是我们需要把以前写的代码,全部删掉!想想都是一件很可怕的事情!所以为了降低代码的耦合性,以及提高代码的复用性,就有了下面的办法动态代理和aop.
二.JDK 动态代理的改进
动态代理代码:
public class MyInvocationHandler implements InvocationHandler {
private Object target;
/**
* 通过构造方法将要增强的类对象传入
*/
public MyInvocationHandler(Object target){
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
//记录日志
MyLog.doLog(target.getClass());
//业务处理
Object invoke=method.invoke(target,args);
//处理事务
MyTransaction.doTransaction(target.getClass());
return invoke;
}
}
业务逻辑代码:
public class UserDaoImpl implements UserDao{
public void addUser() {
//记录日志
// MyLog.doLog(this.getClass());
System.out.println("添加学生数据");
//提交事务
// MyTransaction.doTransaction(this.getClass());
}
}
测试方法:
/**
* 测试动态代理
*/
@Test
public void testProxy(){
//创建目标类对象
UserDaoImpl userDao=new UserDaoImpl();
//创建代理
UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), new MyInvocationHandler(userDao));
userDaoProxy.addUser();
}
三.Aop 的本质
上述过程中,我们看到在动态代理的invoke方法里边,我们相当于在原有方法的调用前后“植入”了我们的通用日志记录代码。
上述抽取公共代码其实就是AOP中横切的过程,在开发过程中,我们把这些向记录日志,事务处理公用的抽出来,然后织入到我们的业务逻辑代码中。总的来说,我们想解决我们开发中的痛点,然后就出现了一种技术,这种技术手段就是AOP。
AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
在编程过程中无需关心与业务逻辑关系不太大的部分,降低了代码的耦合性。