AOP 组件
Aspact
- AspectJ:横切关注点的单元模块,类似于Java class 。它有独特的编译器 Compiler,重新编译字节码
- CGLib : 在运行的时候生成字节码,不会重新编译。也就是说是动态加载的
- Spring AOP :多个类之间的关注模块,组织的形式,里边包含横切的一些类或者方法。
Join point (横切点)
- AspectJ:一个方法 或者一个异常的处理,具体的某个执行的点
- Spring AOP :Aspact 属于一种组织模式(如类), 做为模块来组织 join point (具体的某个执行的点),然后 pointcut 来进行筛选,接下来由 advice 进行具体的动作。
Pointcut
- AspectJ :匹配 join point 筛选方式
- Spring AOP :Join point 的限制条件,判断哪个连接点可以接拦截器
Advice 通知/动作
- AspectJ : 一段代码,一个程序。在目标代码执行前后的一个动作
- Spring AOP : around (拦截、主动),before and after(被动),采用拦截器方式,可以有一串的拦截器在Join point上
Introduction 介绍
- AspectJ : 运行时或编译时动态的继承某个接口或者某个类
- Sping AOP : 辅助的类,在某个特点的类上面
AOP 的设计模式
- 代理模式:静态代理、静态代理
- 判断模式:类、方法、注解、参数、异常
- 拦截模式:前置、后置、返回、异常
Java静态代理
// 公共类和方法
public interface EchoService {
String echo (String message);
}
public class DefaultEchoServiceImpl implements EchoService{
@Override
public String echo(String message) {
return "echo " + message;
}
}
- 常用 oop 继承和组合相结合
public class ProxyEchoService implements EchoService{
private final EchoService echoService;
public ProxyEchoService(EchoService echoService) {
this.echoService = echoService;
}
@Override
public String echo(String message) {
long startTime = System.currentTimeMillis();
String result = echoService.echo(message);
long costTime = System.currentTimeMillis() - startTime;
System.out.println("echo 方法的执行时间:" + costTime + " ms");
return result;
}
}
/**
* 静态代理:
* 组合和继承的模式相结合
*/
public class StaticProxyDemo {
public static void main(String[] args) {
EchoService echoService = new ProxyEchoService(new DefaultEchoServiceImpl());
String echo = echoService.echo("Hello,word!");
System.out.println("echo result : " + echo);
}
}
Java动态代理
- JDK 动态代理
package com.example.demo.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK 动态代理
*/
public class JdkDynamicProxyDemo {
public static void main(String[] args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Object proxyInstance = Proxy.newProxyInstance(classLoader, new Class[]{EchoService.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (EchoService.class.isAssignableFrom(method.getDeclaringClass())) {
EchoService echoService = new ProxyEchoService(new DefaultEchoServiceImpl());
return echoService.echo((String) args[0]);
}
return null;
}
});
EchoService echoService = (EchoService) proxyInstance;
echoService.echo("hello,word!");
}
}
- 字节码提升,如 CGLIB
Java AOP 判断模式
判断来源
- 类型
- 方法
- 注解
- 参数
- 异常
package com.example.demo.aop;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
/**
* AOP 目标过滤示例
*
* 通过Java反射 API 判断
*/
public class TargetFileDemo {
public static void main(String[] args) throws ClassNotFoundException {
String targetClassName = "com.example.demo.aop.EchoService";
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?> targetClass = classLoader.loadClass(targetClassName);
//方法定义 - 采用Spring 的 util 获取方法
Method echo = ReflectionUtils.findMethod(targetClass, "echo", String.class);
System.out.println(echo);
//查找方法 throws 类型为 NullPointerException
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
System.out.println("仅抛出 NullPointerException 方法:" + method);
}
}, new ReflectionUtils.MethodFilter() {
@Override
public boolean matches(Method method) {
Class<?>[] parameterTypes = method.getParameterTypes();
Class<?>[] exceptionTypes = method.getExceptionTypes();
return exceptionTypes.length == 1
&& NullPointerException.class == exceptionTypes[0]
&& parameterTypes.length == 1
&& String.class == parameterTypes[0];
}
});
}
}
Java AOP 拦截模式
拦截类型
- 前置拦截
- 后置拦截
- 异常拦截
- 环绕拦截
Spring AOP 功能概述
核心特性
- 纯Java实现,无编译时特殊处理、不修改和控制ClasssLoader
- 仅支持方法级别的 Join Points
- 非完整AOP实现框架
- Spring IOC 容器整合
- AspectJ 注解驱动整合(非竞争关系)
Spring AOP 编程模型
注解驱动
- 实现 Enable 模块驱动,@EnableAspectJAutoProxy
- 注解
- 激活 AspectJ 自动代理 @EnableAspectJAutoProxy
- Aspect:@Aspect
- Pointcut : @Pointcut
- Advice:@Before、@AfterReturning、@AfterThrowing、@After、@Around
- Introduction:@DeclareParents
Spring AOP 设计目标
- 整体目标:不是要完整的实现AOP的框架,而是整合AspectJ.
自动动态代理
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;