基本概念
AOP,面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
主要意图
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
核心思想:不通过修改源代码方式添加新功能。
实际案例分享:
例如我们现在有一个用户登录的功能,现在需要增加一个新的功能,就是登录完成后增加登录信息的记录的功能,记录的信息包括登录名称、登录时间、登录的ip地址、登录的操作系统等内容。我们会有两种方式实现,一种是修改源代码,在登录功能代码中添加记录用户登录信息功能,另外一种方式是通过AOP的方式不改变源代码添加登录信息记录的功能。
AOP实现方式如下图:
AOP的底层实现原理
AOP底层使用动态代理实现:
动态代理实现有两种方式
1)被代理的对象有接口情况
使用JDK动态代理实现
场景:
2)被代理的对象没有接口的情况
使用CGLIB动态代理实现
场景:
AOP(JDK动态代理)实现原理
编写JDK动态代理代码:
1)创建接口UserDao和接口实现类UserDaoImpl
package org.learn.spring5.dao;
public interface UserDao {
int add();
int update(Integer id);
}
package org.learn.spring5.dao.impl;
import org.learn.spring5.dao.UserDao;
/**
* UserDao的实现类
*/
public class UserDaoImpl implements UserDao {
public int add() {
System.out.println("UserDaoImpl add ");
return 1;
}
public int update(Integer id) {
System.out.println("UserDaoImpl update");
return id;
}
}
2)创建MyInvocationHandler类实现InvocationHandler,该类用于实现代理类调用的方法增强的那部
分的处理。增强处理的内容是在invoke方法中,在代理类调用方法时,执行invoke方法。
package org.learn.spring5.dao.impl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//创建代理对象调用的程序代码
public class MyInvocationHandler implements InvocationHandler {
private Object object;
//有参构造传递
public MyInvocationHandler(Object object){
this.object = object;
}
//增强的逻辑
//第一个参数:类加载
//第二个参数:增强方法所在的类,这个类实现的接口,支持多个接口
//第三个参数:实现这个接口InvocationHandler,创建代理对象,写增强的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法之前处理");
//被增强的方法执行
Object invoke = method.invoke(object,args);
System.out.println("方法之后处理");
return invoke;
}
}
3)利用Proxy类生成代理对象的实例,调用相应的被代理类的方法。
import org.learn.spring5.dao.UserDao;
import org.learn.spring5.dao.impl.MyInvocationHandler;
import org.learn.spring5.dao.impl.UserDaoImpl;
import java.lang.reflect.Proxy;
class TestProxy {
public static void main(String[] args) {
//被增强的类,真实的角色
UserDaoImpl userDaoImpl = new UserDaoImpl();
Class[] interfaces = {UserDao.class}; //接口
//动态生成代理对象的实例并返回,传递谁就生产谁的代理对象
UserDao dao = (UserDao) Proxy.newProxyInstance(TestProxy.class.getClassLoader(), userDaoImpl.getClass().getInterfaces(), new MyInvocationHandler(userDaoImpl));
int res = dao.update(1);
System.out.println(res);
}
}
AOP操作术语
-
连接点
类里面哪些方法可以被增强,这些方法就被称为连接点。
-
切入点
实际被增强的方法,称之为切入点
-
通知(增强)
实际增强的内容被称为通知
通知有多种类型:
前置通知
后置通知
环绕通知
异常通知
最终通知
-
切面
通知应用到切入点的过程
-
切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构:
excution (<权限修饰符><返回类型><类全路径><方法名称>(<参数列表>))
(3)示例:对org.learn.spring5.UserDao类的add方法进行增强
excution(* org.learn.spring5.UserDao.add(..))
示例:对org.learn.spring5.UserDao类的所有方法进行增强
excution(* org.learn.spring5.UserDao.*(..))