Spring中的AOP

Aspect-Oriented Programming (AOP) Object-Oriented Programming (OOP)

关键概念:

  • 切面(aspect)

AOP作为Spring的一个关键部分,但是IOC容器并没有依赖AOP。

Spring 2.0 引入AOP。

AOP实现的几种思路:

  1. 编译期间
    • 可利用Java编译器暴露的API对class进行扩展
      • 如:lombok ; AspectJ
  2. 类加载期间
    • 代码织入
    • 如:Spring LoadTimeWeaver ; AspectJ
  3. 运行期间
    • 字节码增强
    • 如: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动态代理对象
  • Weaving
    • 织入
      • 完成切面通知的这个过程
      • 通常可以发生在:
        • 编译期
        • 加载期
        • 运行时

Spring框架的一个重要的原则就是:非侵入性。 避免业务/域模型直接与框架类/接口耦合。

需要

  • aspectjweaver.jar
    • 1.6.8 +
  • @EnableAspectJAutoProxy
  • @Aspect
  • @Pointcut

pointcut expressions:

  • execution
  • within
  • this
  • target
  • args
  • @target
  • @args
  • @within
  • @annotation

注意

  • 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
  • <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

    -javaagent:xxx.jar 会在main方法之前预先执行premain方法 Agent 类必须打成jar包,然后里面的 META-INF/MAINIFEST.MF 必须包含 Premain-Class这个属性 public static void premain(String args, Instrumentation inst)

代码织入

  • @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
    • 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
  • 使用被代理对象
    • 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
  • PooledDataBuffer
    • 基于引用计数
      • retain()
      • release()
  • decoders 和 transports
  • DataBufferUtils
    • compose

Codecs

  • org.springframework.core.codec
  • Encoder
  • Decoder
  • WebFlux也是基于此
    • WebFluxConfigurationSupport
      • configureHttpMessageCodecs

猜你喜欢

转载自my.oschina.net/roccn/blog/1822330