一、什么是AOP ?
-
AOP是 Aspect Oriented Programming(面向切面编程) 的简称,和OOP(面向对象编程)一样是一种编程思想,是对OOP的一种补充。
-
AOP旨在将横切关注点(crosscutting concern)从业务主体逻辑中进行剥离,实现关注点分离,以提高程序的模块化程度(及业务模块只需关注业务逻辑,无需关注日志、安全、事务等通用逻辑)
二、AOP常见概念
-
切面(Aspect):具有一定横切逻辑的类,用于封装特定的横切关注点,例如:事务、日志、安全等。
-
切点(Pointcut):表示横切关注点的位置,通常定义在方法粒度上,可以通过表达式或注解等方式进行定义。
-
通知(Advice):定义了特定的横切逻辑,包括前置通知、后置通知、环绕通知、异常通知等。
-
织入(Weaving):将切面的逻辑应用到目标对象中,目标对象可以是一个类或者一个方法,实现了横切逻辑和业务逻辑的分离。
-
引入(Introduction):一种特殊的通知形式,用于向目标对象引入新的方法或属性。
-
连接点(Join Point):在应用程序执行过程中能够进行拦截的具体点,例如:方法调用、属性访问、异常处理等。
-
切面顺序(Aspect Ordering):当多个切面对一个连接点进行拦截时,决定拦截顺序的规则。
-
目标对象( Target ):指被切面织入的对象
三、Spring AOP的动态代理模式
-
JDK 动态代理
概念:JDK 动态代理是 Java 语言本身提供的一种动态代理实现方式,通过反射机制动态地创建一个代理类,在代理对象中调用目标对象的方法,实现对目标对象的增强。JDK 动态代理要求代理的目标对象必须实现一个接口,在创建代理对象时需要传入一个 InvocationHandler 对象,该对象实现了对目标对象方法的增强逻辑。在使用 JDK 动态代理时,Spring AOP 可以通过配置文件或注解等方式进行配置和使用。
-
定义“目标对象”实现的业务接口。
public interface UserService { void addUser(); } public class UserServiceImpl implements UserService { @Override public void addUser() { System.out.println("Add user..."); } }
-
通过定义一个 InvocationHandler 对象,包含目标对象和横切逻辑。
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 { System.out.println("Before method calling..."); Object result = method.invoke(target, args); System.out.println("After method calling..."); return result; } }
-
使用 Proxy 类的静态方法 newProxyInstance(ClassLoader, Class[], InvocationHandler) 动态创建一个代理对象,并指定代理对象和 InvocationHandler 对象。
public class ProxyDemo { public static void main(String[] args) { UserService userService = new UserServiceImpl(); InvocationHandler handler = new MyInvocationHandler(userService); UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), handler); proxy.addUser(); } }
-
代理对象调用方法时,会被转发到 InvocationHandler 对象处理,从而实现对目标对象的增强。
-
-
CGLIB 动态代理
概念:CGLIB 动态代理是一个基于字节码技术的动态代理实现方式,不需要目标对象实现接口,通过创建目标对象的子类来实现对目标对象的代理。CGLIB 动态代理使用 Enhancer 类生成目标对象的子类,并重写其中的方法,将增强逻辑插入到目标对象方法的前后,实现对目标对象的增强。CGLIB 动态代理通常被用于 AOP 框架中对没有接口的 Java 对象进行代理。在使用 CGLIB 动态代理时,Spring AOP 可以通过配置文件或注解等方式进行配置和使用。
-
在运行时,通过继承目标类生成一个代理类。
public class UserService { public void addUser() { System.out.println("Add user..."); } }
-
在代理类中重写目标类的非 final 方法,在方法中委托拦截器处理横切逻辑。
public class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("Before method calling..."); Object result = methodProxy.invokeSuper(o, args); System.out.println("After method calling..."); return result; } }
-
通过创建代理类的实例,对目标对象进行代理。
public class ProxyDemo { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserService.class); enhancer.setCallback(new MyMethodInterceptor()); UserService userService = (UserService) enhancer.create(); userService.addUser(); } }
-