Spring系列之AOP分析(二)

简介:

终于要正式开始SpringAOP的分析工作了,在这之前先问个问题:关于AOP你认为最重要的是哪几个地方?我觉得有这样几个地方(理解的不对的地方欢迎指出):一个是AOP的配置(拦截规则的配置),一个是代理对象的创建,一个是统一的拦截调用过程。关于AOP的配置Spring是自己定义了一套规则同时集成了AspectJ的语法,抽象为了Pointcut类。代理对象的创建,SpringAOP定义了一个工厂类AopProxy,同时支持JDK动态代理和CGlib动态代理。统一的拦截调用过程则是使用了AOP联盟中定义的拦截过程:Advice----->Interceptor------->MethodInterceptor。但是SpringAOP在这个基础上做了一些扩展,形成了自己的一套体系。接下来先介绍一下长得很像三胞胎的三个类:
Advice:SpringAOP联盟中定义的类。是一个标识性的接口。通知类型的接口。同时也是Interceptor、MethodInterceptor的父类。通知类型都有去实现的一个接口。
Advisor:关联了Advice和Pointcut。在SpringAOP中是一个很关键的类。上起到了连接点的匹配下起到了通知类型的调用。统一了拦截的调用过程。
Advised:关联了Advisor和TargetSource的类。也是AOP中一个很关键的类。AOP进行方法拦截的时候,就是从它里面获取的拦截调用链。
一个大致的关系如下:
Advised_Advisor_Advice
下面我们先写一个使用SpringAOP的小例子,这里使用了AspectJ中的语法。小例子如下:
先定义一个切面类和一个前置通知:

@Aspect
public class AopAdviceConfig {

    @Before("execution(* com.zkn.spring.learn.aop.program.service..*.*(..))")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println(joinPoint.getThis());
        System.out.println("我是前置通知....");
    }
}
//定义一个接口
public interface AspectJService {

    /**
     * 测试前置通知
     */
    void beforeAdvice();

    /**
     * 测试后置通知
     */
    void afterAdvice();
}
//实现类
public class AspectJServiceImpl implements AspectJService {

    @Override
    public void beforeAdvice() {
        System.out.println("测试前置通知,我是第一个Service。。。。。。");
    }

    /**
     * 测试后置通知
     */
    @Override
    public void afterAdvice() {
        System.out.println("测试AspectJ后置通知。。。。");
    }
}

我们用编程的方式去进行一个AOP的拦截功能。

public class AspectJProxyFactoryLearn {

    public static void main(String[] args) {
        //手工创建一个实例
        AspectJService aspectJService = new AspectJServiceImpl();
        //使用AspectJ语法 自动创建代理对象
        AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(aspectJService);
        //添加切面和通知类
        aspectJProxyFactory.addAspect(AopAdviceConfig.class);
        //创建代理对象
        AspectJService proxyService = aspectJProxyFactory.getProxy();
        //进行方法调用
        proxyService.beforeAdvice();
    }
}

我们看一下输出结果:
AspectJProxyFactory
从上面的输出结果来看,我们的AOP拦截功能是生效了。但是对于这样的操作你可能会很奇怪,感觉SpringAOP还能这样玩?上面的AspectJProxyFactory这个类又是什么鬼?怎么只调用了一下addAspect方法,然后调用getProxy方法生成代理对象,这样就能进行AOP拦截了?我们在下面的文章中慢慢为你解谜。
在进行AspectJProxyFactory分析之前先来看一下AspectJProxyFactory的UML类图:
AspectJProxyFactory
AspectJProxyFactory的类图如上所示,我们可以看到它是Advised的一个子类。先把这个图印在脑子里。我们先来看第一段代码:

AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(aspectJService);
//对应的AspectJProxyFactory构造函数的内容
public AspectJProxyFactory(Object target) {
    Assert.notNull(target, "Target object must not be null");
    setInterfaces(ClassUtils.getAllInterfaces(target));
    setTarget(target);
}

当我们调用AspectJProxyFactory的有参构造函数时,它做了这几件事,检测目标对象不能为null,设置目标对象的所有的接口,设置目标对象。
获取类上的所有的接口是通过调用ClassUtils.getAllInterfaces来获取的。这个方法可以获取类上的所有接口,包括父类上的接口,但是它不能获取接口的接口。意思是如果:类A继承了类B,类B实现了接口C,接口C继承了接口D,如果传入的参数是类A,这里是可以获取到接口C,但是获取不到接口D的

    //AdvisedSupport中添加接口信息
    public void setInterfaces(Class<?>... interfaces) {
        Assert.notNull(interfaces, "Interfaces must not be null");
        //先清空原来的接口信息 是一个List
        this.interfaces.clear();
        for (Class<?> ifc : interfaces) {
            addInterface(ifc);
        }
    }
    //AdvisedSupport中的方法
    public void addInterface(Class<?> intf) {
        Assert.notNull(intf, "Interface must not be null");
        //如果不是接口 抛出异常
        if (!intf.isInterface()) {
            throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
        }
        if (!this.interfaces.contains(intf)) {
            this.interfaces.add(intf);
            adviceChanged();
        }
    }
    //ProxyCreatorSupport中的方法
    protected void adviceChanged() {
        super.adviceChanged();
        synchronized (this) {
            if (this.active) {
                //给Advised的监听器发送通知 通知Advised的变化 
                //在Spring中没有默认的实现
                for (AdvisedSupportListener listener : this.listeners) {
                    listener.adviceChanged(this);
                }
            }
        }
    }
    //AdvisedSupport中的方法
    protected void adviceChanged() {
        //清空缓存的方法信息 这里可以思考一下为什么当Interface变化的时候,会清空methodCache
        //Map<MethodCacheKey, List<Object>> methodCache
        //为什么这个类名是adviceChanged???
        this.methodCache.clear();
    }

设置目标对象

    public void setTarget(Object target) {
        //注意这里是将目标对象封装为了 SingletonTargetSource 是一个单例的
        //这里一定要记着 SingletonTargetSource中存放的是我们的目标对象 不是代理对象
        //这里调用的是AdvisedSupport中的方法 setTargetSource这个方法是Advised中定义的方法
        setTargetSource(new SingletonTargetSource(target));
    }
    // AdvisedSupport
    public void setTargetSource(TargetSource targetSource) {
        this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
    }

剩下的我们在下一章分析。

相关文章
|
2月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
407 0
|
1月前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
6月前
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
1060 13
|
3月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
3月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
5月前
|
负载均衡 Java API
基于 Spring Cloud 的微服务架构分析
Spring Cloud 是一个基于 Spring Boot 的微服务框架,提供全套分布式系统解决方案。它整合了 Netflix、Zookeeper 等成熟技术,通过简化配置和开发流程,支持服务发现(Eureka)、负载均衡(Ribbon)、断路器(Hystrix)、API网关(Zuul)、配置管理(Config)等功能。此外,Spring Cloud 还兼容 Nacos、Consul、Etcd 等注册中心,满足不同场景需求。其核心组件如 Feign 和 Stream,进一步增强了服务调用与消息处理能力,为开发者提供了一站式微服务开发工具包。
616 0
|
9月前
|
XML Java 测试技术
Spring AOP—通知类型 和 切入点表达式 万字详解(通俗易懂)
Spring 第五节 AOP——切入点表达式 万字详解!
644 25
|
7月前
|
SQL 前端开发 Java
深入分析 Spring Boot 项目开发中的常见问题与解决方案
本文深入分析了Spring Boot项目开发中的常见问题与解决方案,涵盖视图路径冲突(Circular View Path)、ECharts图表数据异常及SQL唯一约束冲突等典型场景。通过实际案例剖析问题成因,并提供具体解决方法,如优化视图解析器配置、改进数据查询逻辑以及合理使用外键约束。同时复习了Spring MVC视图解析原理与数据库完整性知识,强调细节处理和数据验证的重要性,为开发者提供实用参考。
332 0
|
8月前
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
1017 0