一、概述
AOP:Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。
AOP是OOP(面向对象)的扩展和延申,解决OOP开发遇到的问题
二、OOP的问题
需求:现在项目中有A、B、C三个DAO,在保存数据之前要做权限的验证。
按照传统方式:1、在每个DAO中分别创建权限验证方法(check()),然后在保存方法(save())中调用权限验证方法(check())
2、创建一个DAO的父级DAO,并在父级DAO中创建权限验证方法,然后在保存方法(save())中调用权限验证方法(check())
这样就要变更save方法中的代码,并且要修改多个DAO,代码修改范围也是很大。
三、AOP(面向切面)思想
AOP采取横向抽取机制(代理机制),在不变更方法源代码基础上对方法进行增强。
四、Spring的AOP的底层实现原理
1、JDK动态代理:只能对实现接口的类产生代理
2、Cglib动态代理:没有实现接口的类产生代理对象,生成子类对象
Spring的AOP会自动切换动态代理
①、JDK动态代理
Ⅰ、定义接口
public interface UserDao { public void save(); public void find(); public void update(); public void delete(); }
Ⅱ、创建实现接口的类
public class UserDaoImpl implements UserDao { @Override public void save() { System.out.println("保存用户..."); } @Override public void find() { System.out.println("查询用户..."); } @Override public void update() { System.out.println("更新用户..."); } @Override public void delete() { System.out.println("删除用户..."); } }
Ⅲ、编写可以创建代理的类
public class JdkProxy implements InvocationHandler { //1、将要增强的对象传递到代理中 private UserDao userDao; /** * @param userDao */ public JdkProxy(UserDao userDao) { this.userDao = userDao; } //2、创建代理对象 public UserDao createProxy() { //newProxyInstance(类加载器, 类实现的接口, InvocationHandler) UserDao userDaoProxy=(UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);//this 因为 JdkProxy implements InvocationHandler return userDaoProxy; } //3、增强代理对象的方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //判断方法名是不是save if("save".equals(method.getName())) { System.out.println("权限校验......."); } return method.invoke(userDao, args); } }
Ⅳ、测试方法
@Test public void demo1() { UserDao userDao=new UserDaoImpl(); UserDao proxy=new JdkProxy(userDao).createProxy(); proxy.save(); proxy.find(); proxy.update(); proxy.delete(); }
②、Cglib动态代理
Ⅰ、引入jar
Ⅱ、创建类
public class CustomerDao { public void save() { System.out.println("保存用户..."); } public void find() { System.out.println("查询客户..."); } public void update() { System.out.println("修改客户..."); } public void delete() { System.out.println("删除客户..."); } }
Ⅲ、编写可以创建代理的类
public class CglibProxy implements MethodInterceptor{ // 1、获取要增强的对象 private CustomerDao customerDao; public CglibProxy(CustomerDao customerDao) { this.customerDao = customerDao; } // 2、创建对象代理 public CustomerDao createProxy() { // 2.1、创建cglib的核心类对象 Enhancer enhancer=new Enhancer(); // 2.2、设置父类的类型 enhancer.setSuperclass(customerDao.getClass()); // 2.3、设置回调(类似InvocationHandler对象) enhancer.setCallback(this);// this因为CglibProxy implements MethodInterceptor // 2.4、创建代理对象 CustomerDao proxy=(CustomerDao) enhancer.create(); return proxy; } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { if("save".equals(method.getName())) { System.out.println("权限检验......."); } return methodProxy.invokeSuper(proxy, args);//proxy:通过子类调用父类方法 } }
Ⅳ、测试方法
@Test public void demo2() { CustomerDao customerDao=new CustomerDao(); CustomerDao proxy=new CglibProxy(customerDao).createProxy(); proxy.save(); proxy.find(); proxy.update(); proxy.delete(); }
五、AOP的术语
Joinpoint:连接点,可以被拦截到的点
可以被增强的方法就可以称为是连接点
Pointcut:切入点,真正被拦截到的点
被增强的方法就称为切入点
Advice:通知、增强(方法层面的增强)
对方法进行增强的方法称为通知(如上例中对save方法增强的权限校验的方法称为通知)
Introduction:引介(类层面的增强)
Target:被增强的对象(如上例:CustomerDao 的实例)
Weaving:织入,将通知(Advice)应用到目标对象的过程
Proxy:代理对象
Aspect:切面,多个通知和多个切入点的组合