【Spring -- 12 Spring代理选择 】

 AOP实现

  1. 切点(Pointcut)

    • 切点的作用是定义在何处应用横切关注点
    • 通过切点表达式,我们可以精确地指定需要应用横切逻辑的方法、类或包等。
    • 常见的切点表达式有:方法签名匹配、注解匹配、控制流匹配、静态分析等。
  2. 通知(Advice)

    • 通知的作用是定义在连接点上执行的具体操作
    • 通知包括前置通知、后置通知、环绕通知等,用于在目标方法执行前、执行后或执行期间插入横切逻辑。
    • 通知的实现依赖于动态代理、字节码增强或编译时织入等底层技术。
  3. 切面(Aspect)

    • 切面的作用是将切点和通知组合在一起
    • 切面定义了在何处(切点)应用何种操作(通知)。
    • 切面的实现也依赖于动态代理、字节码增强或编译时织入等底层技术。
// 定义切面
@Aspect
public class LoggingAspect {

    // 使用 execution 表达式定义切点
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethodPointcut() {
    }

    // 前置通知
    @Before("serviceMethodPointcut()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Calling method: " + joinPoint.getSignature().getName());
    }

    // 后置通知
    @AfterReturning(pointcut = "serviceMethodPointcut()", returning = "result")
    public void logAfter(JoinPoint joinPoint, Object result) {
        System.out.println("Method returned: " + result);
    }

    // 环绕通知
    @Around("serviceMethodPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around: before method execution");
        Object result = joinPoint.proceed();
        System.out.println("Around: after method execution");
        return result;
    }
}

// 定义目标对象
@Service
public class MyService {
    public String getMessage() {
        return "Hello, Spring AOP!";
    }

    public int add(int a, int b) {
        return a + b;
    }
}

// 配置 AOP
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    @Bean
    public LoggingAspect loggingAspect() {
        return new LoggingAspect();
    }
}

// 使用目标对象
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        MyService service = context.getBean(MyService.class);

        System.out.println(service.getMessage());
        System.out.println(service.add(2, 3));

        context.close();
    }
}

底层的切点实现

在 Java 中,切点(Pointcut)是用于定义在何处应用横切关注点的表达式。底层的切点实现主要依赖于 Java 反射机制。通常有以下几种常见的切点实现方式:

  1. 方法签名匹配:使用正则表达式或通配符匹配方法签名。
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    
    @Aspect
    public class MethodSignatureMatchingAspect {
    
        @Pointcut("execution(* com.example.myapp.service..*(*)) && args(..)")
        public void allServiceMethods() {}
    
        @Before("allServiceMethods()")
        public void logMethodCall(JoinPoint joinPoint) {
            System.out.println("Calling method: " + joinPoint.getSignature());
        }
    }
  2. 注解匹配:扫描类或方法上的自定义注解。
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    
    @Aspect
    public class AnnotationMatchingAspect {
    
        @Pointcut("@annotation(com.example.myapp.annotations.LogMethodCall)")
        public void loggedMethods() {}
    
        @Before("loggedMethods()")
        public void logMethodCall(JoinPoint joinPoint) {
            System.out.println("Calling method: " + joinPoint.getSignature());
        }
    }
  3. 静态分析:通过静态字节码分析确定切点。
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    
    @Aspect
    public class StaticAnalysisMatchingAspect {
    
        @Pointcut("execution(public * com.example.myapp.service.*.*(int, String))")
        public void publicServiceMethodsWithIntAndStringArgs() {}
    
        @Before("publicServiceMethodsWithIntAndStringArgs()")
        public void logMethodCall(JoinPoint joinPoint) {
            System.out.println("Calling method: " + joinPoint.getSignature());
        }
    }

 

底层的通知实现

通知(Advice)是切面在特定连接点上的动作,主要包括前置通知、后置通知、环绕通知等。底层的通知实现通常依赖于以下技术:

  1. 动态代理(JDK 动态代理或 CGLIB 动态代理)
  2. 字节码增强(如 ASM、Javassist 等字节码操作库)
  3. 编译时织入(如 AspectJ 的编译期织入)

通知的实现通常需要在目标方法执行前后或周围进行介入,以实现特定的横切逻辑。

底层的切面实现

切面(Aspect)是通知和切点的结合。底层的切面实现主要包括以下几种方式:

  1. 基于代理的切面实现
    • 使用 JDK 动态代理或 CGLIB 动态代理创建代理对象
    • 在代理对象中织入通知逻辑
  2. 基于字节码增强的切面实现
    1. 使用字节码操作库(如 ASM、Javassist)直接修改目标类的字节码
    2. 在目标类的字节码中织入通知逻辑
  3. 基于编译时织入的切面实现
    • 使用 AspectJ 等 AOP 框架在编译期对目标类进行织入
    • 在编译期将通知逻辑织入到目标类中

Spring中ProxyFactory 用来创建代理

  • 如果指定了接口,且 proxyTargetClass = false,使用 JdkDynamicAopProxy

  • 如果没有指定接口,或者 proxyTargetClass = true,使用 ObjenesisCglibAopProxy

  • 例外:如果目标是接口类型或已经是 Jdk 代理,使用 JdkDynamicAopProxy

 

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值