AOP概述
AOP是软件开发思想的一个飞跃,AOP的引入将有效弥补OOP的不足,OOP和AOP分别从纵向和横向对软件进行抽象,有效地消除重复性的代码,使代码以更优雅的更有效的方式进行逻辑表达。
spring AOP 面向切面编程 Aspect Oriented Programming(适用于权限检查,日志记录,性能分析,事务管理,异常管理) 。
AOP有三种织入切面的方法:
- 其一是编译期织入,这要求使用特殊的Java编译器,AspectJ是其中的代表者;
- 其二是类装载期织入,而这要求使用特殊的类装载器,AspectJ和AspectWerkz是其中的代表者;
- 其三为动态代理织入,在运行期为目标类添加增强生成子类的方式,Spring AOP采用动态代理织入切面。
Spring AOP使用了两种代理机制,一种是基于JDK的动态代理,另一种是基于CGLib的动态代理,之所以需要两种代理机制,很大程度上是因为JDK本身只提供基于接口的代理,不支持类的代理。
基于JDK的代理和基于CGLib的代理是Spring AOP的核心实现技术,认识这两代理技术,有助于探究Spring AOP的实现机理。只要你愿意,你甚至可以抛开Spring,提供自己的AOP实现。
带有横切逻辑的实例
首先,我们来看一个无法通过OOP进行抽象的重复代码逻辑,它们就是AOP改造的主要对象。
下面,我们通过一个业务方法事务管理的实例了解横切逻辑。
业务方法事务管理,在每一个业务方法调用之前开始事务,业务方法结束后提交事务:
包含事务管理的横切代码:
UserDaoImpl.java
public class UserDaoImpl implements UserDao {
@Override
public User saveUser(User user) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();//开始事务
session.save(user);
session.getTransaction().commit();//提交事务
return user;
}
@Override
public void updateUser(User user) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();//开始事务
session.load(User.class, user.getUid());
user.setUname("等风的草");
user.setUsex("男");
session.getTransaction().commit();//提交事务
}
}
注释部分表示的代码就是具有横切特征的代码,需要进行事务管理的每个业务方法的前后都需要添加类似的事务管理语句。
通过下面代码测试这个拥有事务管理的业务方法:
@Test
public void nonProxyTest() {
UserDao userDao = new UserDaoImpl();
User user = new User();
user.setUname("1号等风的草");
user.setUsex("男");
userDao.saveUser(user);
}
在控制台可以看到一条insert插入语句:
如实例所示,要对业务类进行CRUD,就必须在每个业务类方法的前后两处添加上重复性的开启事务和提交事务的代码。这些非业务逻辑的事务管理破坏了作为业务类UserDaoImpl的纯粹性。
下面,分别用JDK动态代理和CGLib动态代理技术,将业务方法中开启和提交事务的这些横切代码从业务类中完成移除。
基于JDK的动态代理
JDK的动