好记忆不如烂笔头,能记下点东西,就记下点,有时间拿出来看看,也会发觉不一样的感受.
说说 spring aop 的那些事。
Spring AOP 的前世今生
-
起源与发展 :AOP(Aspect-Oriented Programming,面向切面编程)作为一种编程思想,旨在解决传统面向对象编程中存在的代码重复、关注点分散等问题。Spring AOP 是 Spring 框架对 AOP 思想的实现,它借鉴了 AOP Alliance 的相关规范,并不断发展和完善。
-
与 AspectJ 的关系 :早期 Spring AOP 和 AspectJ 是相互竞争的 AOP 框架,但后来 Spring 决定整合 AspectJ,从 Spring 2.0 开始对 AspectJ 提供支持,并在后续版本中不断加深融合。不过,Spring AOP 和 AspectJ 在实现原理和使用场景上有所不同,Spring AOP 主要基于动态代理实现运行时增强,而 AspectJ 是基于字节码操作的编译时增强。
Spring AOP 的核心设计思想
-
代码复用 :将通用的功能(如日志记录、事务管理等)抽取出来,形成可复用的切面模块,避免在多个业务模块中重复编写相同的代码,提高代码的可维护性和可扩展性。
-
关注点分离 :将业务逻辑和通用功能分离,让开发者能够更专注于业务逻辑的实现,而通用功能则由切面来处理,从而使代码更加清晰、简洁,降低模块间的耦合度。
-
动态织入 :在运行时通过动态代理技术将切面逻辑织入到目标对象的方法中,无需修改目标对象的源代码,实现了对目标对象的无侵入式增强,增强了系统的灵活性和可扩展性。
-
基于接口与注解的编程模式 :提供了丰富的注解(如 @Aspect、@Before、@After、@Around 等),方便开发者快速定义切面和切点,降低了 AOP 编程的门槛,同时也支持基于接口的编程模式,与 Spring 容器紧密结合,方便对切面进行管理。
-
与 Spring 容器的集成 :依赖于 Spring 的 IOC 容器,能够方便地获取和管理切面 Bean,同时也能够利用 Spring 容器的其他功能(如依赖注入等)来增强切面的灵活性和可配置性。
Spring AOP 的核心实现源码
-
AOP 代理的创建 :Spring AOP 通过 AopProxyFactory 来创建 AOP 代理对象,它会根据目标对象是否实现了接口以及相关配置来决定使用 JDK 动态代理还是 CGLIB 代理。其核心实现代码如下:扫码添加如下号码,了解更多信息。
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
-
方法拦截器链的执行 :在 Spring AOP 中,方法拦截器链的执行是通过 ReflectiveMethodInvocation 类来实现的,其核心代码如下:
public class ReflectiveMethodInvocation extends AbstractMethodInvocation {
// 方法拦截器链
private final List<Object> interceptorsAndDynamicMethodMatchers;
private final Class<?> targetClass;
private final Object[] arguments;
private final Method method;
private final Object target;
// 其他代码...
public Object proceed() throws Throwable {
Object returnType = null;
for (int i = 0; i < interceptorsAndDynamicMethodMatchers.size() - 1; i++) {
Object interceptorOrInterceptionAdvice = interceptorsAndDynamicMethodMatchers.get(i);
if (interceptorOrInterceptionAdvice instanceof MethodInterceptor) {
returnType = ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
if (returnType != null) {
return returnType;
}
}
}
return invokeJoinpoint();
}
private Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(target, method, arguments);
}
}
-
环绕通知的实现 :环绕通知是 Spring AOP 中一种强大的通知类型,它允许在目标方法执行前后都执行自定义逻辑,并且可以控制目标方法是否执行以及返回值等。环绕通知的核心实现代码如下:
public class AroundAdviceInterceptor implements MethodInterceptor {
private final MethodInterceptor interceptor;
public AroundAdviceInterceptor(MethodInterceptor interceptor) {
this.interceptor = interceptor;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
return this.interceptor.invoke(invocation);
}
}
Spring AOP 的使用场景
-
日志记录 :在方法执行前后记录日志信息,方便对系统的运行情况进行监控和分析。
-
权限验证 :在业务方法执行前进行权限验证,确保只有具有相应权限的用户才能访问特定的方法或功能。
-
性能监控 :通过环绕通知测量方法的执行时间,对系统的性能进行监控和优化。
-
事务管理 :对数据访问层的方法进行事务管理,确保数据的一致性和完整性。
-
缓存管理 :在方法执行前检查缓存中是否存在结果,如果存在则直接返回缓存结果,否则执行方法并将结果存入缓存。
-
异常处理 :在方法执行出现异常时进行统一的异常处理,如记录异常信息、发送警报邮件等。
Spring AOP 的替代方案
-
AspectJ :AspectJ 是一个功能强大的 AOP 框架,它基于字节码操作实现编译时增强,能够对类的字段、构造方法等进行增强,且性能较好。Spring AOP 已经集成了 AspectJ,但在使用时需要注意二者的区别和适用场景。
-
字节码增强工具 :如 ASM、Javassist 等,它们可以直接操作字节码来实现对类的增强,具有较高的灵活性和性能,但使用相对复杂,需要对字节码有一定的了解。
-
其他 AOP 框架 :如 Guice AOP 等,它们也提供了类似的功能,可根据具体需求选择合适的框架。