spring 14 jdk 和 cglib 的统一

Spring 中对切点、通知、切面的抽象如下

  • 切点:接口 Pointcut,典型实现 AspectJExpressionPointcut
  • 通知:典型接口为 MethodInterceptor 代表环绕通知
  • 切面:Advisor,包含一个 Advice 通知,PointcutAdvisor 包含一个 Advice 通知和一个 Pointcut

«interface»

Advice

«interface»

MethodInterceptor

«interface»

Advisor

«interface»

PointcutAdvisor

«interface»

Pointcut

AspectJExpressionPointcut

代理相关类图

  • AopProxyFactory 根据 proxyTargetClass 等设置选择 AopProxy 实现
  • AopProxy 通过 getProxy 创建代理对象
  • 图中 Proxy 都实现了 Advised 接口,能够获得关联的切面集合与目标(其实是从 ProxyFactory 取得)
  • 调用代理方法时,会借助 ProxyFactory 将通知统一转为环绕通知:MethodInterceptor

使用

创建

创建

«interface»

Advised

ProxyFactory

proxyTargetClass : boolean

Target

Advisor

«interface»

AopProxyFactory

«interface»

AopProxy

+getProxy() : Object

基于CGLIB的Proxy

ObjenesisCglibAopProxy

advised : ProxyFactory

JdkDynamicAopProxy

advised : ProxyFactory

基于JDK的Proxy

底层切点、通知、切面

模拟

import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;

public class S14 {
    public static void main(String[] args) {
        testSpringProxy1();
    }

    private static void testSpringProxy1() {
        //定义切点 pointcut
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* cn.xyf.spring.s14.*.a(..))");
        //定义通知 advice
        MethodInterceptor advice = invocation -> {
            System.out.println("前置增强...");
            Object result = invocation.proceed();
            System.out.println("后置增强...");
            return result;
        };
        //定义切面 advisor
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
        //使用工厂创建代理
        //   * 如果指定了接口,且 proxyTargetClass = false,使用 JdkDynamicAopProxy
        //   * 如果没有指定接口,或者 proxyTargetClass = true,使用 ObjenesisCglibAopProxy
        //   * 例外:如果目标是接口类型或已经是 Jdk 代理,使用 JdkDynamicAopProxy

        S14Bean2 target = new S14Bean2();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setInterfaces(target.getClass().getInterfaces());
        proxyFactory.setProxyTargetClass(true);
        proxyFactory.setTarget(target);
        proxyFactory.addAdvisor(advisor);
        S14Bean1 proxy = (S14Bean1) proxyFactory.getProxy();
        System.out.println(proxy.getClass());
        proxy.a();
        proxy.b();
    }
}




 class  S14Bean2 implements S14Bean1{
    @Override
    public void a() {
        System.out.println("S14Bean2 a running...");
    }

    public void a(int i) {
        System.out.println("S14Bean2 a running" + i);
    }

    @Override
    public void b() {
        System.out.println("S14Bean2 b running...");
    }
}

interface S14Bean1 {
    void a();
    void b();
}
  1. 底层的切点实现
  2. 底层的通知实现
  3. 底层的切面实现
  4. ProxyFactory 用来创建代理
    • 如果指定了接口,且 proxyTargetClass = false,使用 JdkDynamicAopProxy
    • 如果没有指定接口,或者 proxyTargetClass = true,使用 ObjenesisCglibAopProxy
    • 例外:如果目标是接口类型或已经是 Jdk 代理,使用 JdkDynamicAopProxy

注意

  • 要区分本章节提到的 MethodInterceptor,它与之前 cglib 中用的的 MethodInterceptor 是不同的接口
posted @   xy7112  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示