一、概述
动态代理实现程序功能的统一维护的一种技术。
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:切面,多个通知和多个切入点的组合