Aspect-Oriented Programming (AOP) Object-Oriented Programming (OOP)
关键概念:
- 切面(aspect)
AOP作为Spring的一个关键部分,但是IOC容器并没有依赖AOP。
Spring 2.0 引入AOP。
AOP实现的几种思路:
- 编译期间
- 可利用Java编译器暴露的API对class进行扩展
- 如:lombok ; AspectJ
- 可利用Java编译器暴露的API对class进行扩展
- 类加载期间
- 代码织入
- 如:Spring LoadTimeWeaver ; AspectJ
- 运行期间
- 字节码增强
- 如:CGLIB ;Java 动态代理
- JDK6:Instrumentation-API
AOP核心概念:
- Aspect
- 切面
- Join point
- 结合点
- Advice
- 通知方式
- around
- before
- after (finally)
- After throwing
- After returning
- 在Spring等框架中,通过对结合点使用拦截器链来实现通知模型
@Before
@AfterReturning
@AfterThrowing
@After
@Around
ProceedingJoinPoint
- 顺序
org.springframework.core.Ordered
- 通知方式
- Pointcut
- 切入点
- 通过结合点匹配到的某个具体需要切入的点(方法)
- 切入点
- Introduction
- 引入
- 需要在切入点引入额外的方法或者属性
- 引入
- Target object
- 目标对象
- 源对象
- 通常也是一个代理对象
- 源对象
- 目标对象
- AOP proxy
- 通过AOP处理过的代理对象
- 通常是一个CGLIB或者JDK动态代理对象
- 通过AOP处理过的代理对象
- Weaving
- 织入
- 完成切面通知的这个过程
- 通常可以发生在:
- 编译期
- 加载期
- 运行时
- 织入
Spring框架的一个重要的原则就是:非侵入性。 避免业务/域模型直接与框架类/接口耦合。
需要
- aspectjweaver.jar
- 1.6.8 +
- @EnableAspectJAutoProxy
- @Aspect
- @Pointcut
pointcut expressions:
注意
- With CGLIB, public and protected method calls on the proxy will be intercepted, and even package-visible methods if necessary.
- For JDK proxies, only public interface method calls on the proxy can be intercepted
- calls within the target object are by definition not intercepted
如果需要内部调用;构造器拦截,需要使用AspectJ weaving织入的方式来进行AOP
-
bean(idOrNameOfBean)
- 只在Spring AOP中起作用
-
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
SPRING aop核心机制:代理
org.springframework.aop.framework.ProxyFactory
AopContext.currentProxy()
java-base
org.springframework.aop.aspectj.annotation.AspectJProxyFactory
Load-time weaving
-
(LTW)
-
完整文档 LTW section of the AspectJ Development Environment Guide
-
-javaagent:path/to/aspectjweaver.jar
-
-javaagent:path/to/org.springframework.instrument-{version}.jar
-
@EnableLoadTimeWeaving
- 自动配置几个Bean:
LoadTimeWeaver
DefaultContextLoadTimeWeaver
- 会根据环境来加载不同的
LoadTimeWeaver
WebLogicLoadTimeWeaver
GlassFishLoadTimeWeaver
TomcatLoadTimeWeaver
JBossLoadTimeWeaver
WebSphereLoadTimeWeaver
InstrumentationLoadTimeWeaver
ReflectiveLoadTimeWeaver
- 会根据环境来加载不同的
- 也可以手动指定
LoadTimeWeavingConfigurer
getLoadTimeWeaver()
AspectJWeavingEnabler
aspectjWeaving
属性ENABLED
:启用加载时代码织入DISABLED
:关闭……AUTODETECT
:自动判断- 检查是否存在
META-INF/aop.xml
- 检查是否存在
- 自动配置几个Bean:
-
<context:load-time-weaver/>
-
META-INF/aop.xml
-
spring-instrument.jar
org.springframework.instrument.classloading
LoadTimeWeaver
- 负责添加:
java.lang.instrument.ClassFileTransformers
- 实际是由:
org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter
- 实际是由:
- 负责添加:
-
环境
- Tomcat6,7默认的classloader不支持class转换(transformation)
- Spring为tomcat提供了一个增强版的加载器
TomcatInstrumentableClassLoader
org.springframework.instrument.tomcat.jar
- Spring为tomcat提供了一个增强版的加载器
-javaagent:xxx.jar 会在main方法之前预先执行premain方法 Agent 类必须打成jar包,然后里面的 META-INF/MAINIFEST.MF 必须包含 Premain-Class这个属性 public static void premain(String args, Instrumentation inst)
- Tomcat6,7默认的classloader不支持class转换(transformation)
代码织入
@Configurable
- 标记注解
- 标记某个类是符合spring驱动配置的
<context:spring-configured/>
@EnableSpringConfigured
org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect
-
- within the same classloader hierarchy*
@Transactional
-
- This is primarily intended for users who want to use the Spring Framework’s transaction support outside of the Spring container.*
public
-
Spring AOP API
- 组件:
org.springframework.aop.Pointcut
- If possible, try to make pointcuts static, allowing the AOP framework to cache the results of pointcut evaluation when an AOP proxy is created.
org.springframework.aop.aspectj.AspectJExpressionPointcut
org.springframework.aop.support.JdkRegexpMethodPointcut
org.springframework.aop.support.ControlFlowPointcut
- Advice
- 生命周期
- 针对每一个class
- 针对每一个实例
- 主要看增强代码是否依赖实例中的数据状态
- 类型:
- around
Interceptor
- before
BeforeAdvice
- 不可以改变返回值
- 可通过异常中断拦截器链
- Throws
ThrowsAdvice
- 可以覆盖原本的异常
- 如果是检查型异常,要注意是否与代理方法的签名一致
- after returning
AfterReturningAdvice
- 如果抛出异常则会替代被代理方法的返回值
- Introduction
IntroductionAdvisor
org.springframework.aop.support.DelegatingIntroductionInterceptor
- around
- 生命周期
- Advisor
org.springframework.aop.support.DefaultPointcutAdvisor
- ProxyFactoryBean
org.springframework.aop.framework.ProxyFactoryBean
org.springframework.aop.framework.ProxyConfig
- JDK- and CGLIB-based proxies
- CGLIB proxying works by generating a subclass of the target class at runtime. Spring configures this generated subclass to delegate method calls to the original target: the subclass is used to implement the Decorator pattern, weaving in the advice.
- CGLIB 的问题
- 通常是以子类的方式扩展
final
方法无法覆盖- 需要引入依赖库
- spring 3.2+ 内部直接包括cglib
- 手工创建
ProxyFactory
- 获得AOP信息
org.springframework.aop.framework.Advised
- 自动代理
- 使用spring的bean post processor机制,为每一个Bean做更细致的代理
org.springframework.aop.framework.autoproxy
- 使用spring的bean post processor机制,为每一个Bean做更细致的代理
- 使用被代理对象
org.springframework.aop.TargetSource
- 热更新
org.springframework.aop.target.HotSwappableTargetSource
- threadsafe
- 池化
org.springframework.aop.target.AbstractPoolingTargetSource
org.springframework.aop.target.PoolingConfig
org.springframework.aop.target.CommonsPool2TargetSource
- Commons Pool 2.2
org.springframework.aop.target.PrototypeTargetSource
- 每一次方法调用,都创建一个被代理对象
org.springframework.aop.target.ThreadLocalTargetSource
- 可以让被代理对象与线程绑定
空
org.springframework.lang
@NonNull
@Nullable
@NonNullApi
@NonNullFields
- Reactor和Spring Data中的null-safe API也是基于这个特性的
Data Buffer
- Spring对于Netty中的
ByteBuf
的抽象,可以直接用于非Netty的项目中。 DataBufferFactory
- 在Netty工程中,可以直接使用
NettyDataBufferFactory
- 如:Reactor Netty
DefaultDataBufferFactory
- 如:Servlet 3.1+ servers
- 在Netty工程中,可以直接使用
PooledDataBuffer
- 基于引用计数
retain()
release()
- 基于引用计数
- decoders 和 transports
DataBufferUtils
compose
Codecs
org.springframework.core.codec
- Encoder
- Decoder
- WebFlux也是基于此
WebFluxConfigurationSupport
configureHttpMessageCodecs