• Spring AOP源码分析(一)使用示例


    摘要: 本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。

    我们知道,使用面向对象编程(OOP)有一些弊端,当需要为多个不具有继承关系的对象引人同一个公共行为时,例如日志、安全检测等,我们只有在每个对象里引用公共行为,这样程序中就产生了大量的重复代码,程序就不便于维护了,所以就有了一个对面向对象编程的补充,即面向方面编程(AOP),AOP所关注的方向是横向的,不同于OOP的纵向。

    Spring中提供了AOP的实现,但是在低版本Spring中定义一个切面是比较麻烦的,需要实现特定的接口,并进行一些较为复杂的配置。低版本Spring AOP的配置是被批评最多的地方。Spring听取了这方面的批评声音,并下决心彻底改变这一现状。在Spring2.0中,SpringAOP已经焕然一新,你可以使用@AspectJ注解非常容易地定义一个切面,不需要实现任何的接口。

    Spring 2.0采用@AspectJ注解对POJO进行标注,从而定义一个包含切点信息和增强横切逻辑的切面。Spring 2.0可以将这个切面织人到匹配的目标Bean中。@AspectJ注解使用AspectJ切点表达式语法进行切点定义,可以通过切点函数、运算符、通配符等高级功能进行切点定义,拥有强大的连接点描述能力。我们先来直观地浏览一下Spring中的AOP实现。

    接下来一起看看@AspectJ注解是如何使用的。

    目录

    一、创建用于拦截的bean

    二、创建Advisor

    三、创建配置文件

    四、测试

    在开始前,先配置Aspect。

    <!-- aspectjweaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>${aspectj.version}</version>
    </dependency>

    一、创建用于拦截的bean

    在实际工作中,此bean可能是满足业务需要的核心逻辑,例如test方法中可能会封装着某个核心业务,但是,如果我们想在test前后加人口志来跟踪调试,如果直接修改源码并不符合面向对象的设计方法,而且随意改动原有代码也会造成一定的风险,还好接下来的Spring帮我们做到了这一点。

    public class Audience {
    
        private String name = "audience";
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void watch() {
            System.out.println("Watch movie");
        }
    }

    二、创建Advisor

    Spring中摒弃了最原始的繁杂配置方式而采用@AspectJ注解对POJO进行标注,使AOP 的的工作大大简化,例如,在AspectJAudience类中,我们要做的就是在所有类的watch方法执行前在控制台中打印silenceCellPhone和takeSeat,而在所有类的watch方法执行后打印applause,同时又使用环绕的方式在所有类的watch方法执行前后再次分别打印Silencing cell phone和CLAP CLAP CLAP。

    @Aspect
    public class AspectJAudience {
        /**
         * 定义一个公共的切点
         */
        @Pointcut("execution(* *.watch(..))")
        public void watch() {
    
        }
    
        /**
         * 目标方法执行之前调用
         */
        @Before("watch()")
        public void silenceCellPhone() {
            System.out.println("Silencing cell phone");
        }
    
        /**
         * 目标方法执行之前调用
         */
        @Before("watch()")
        public void takeSeat() {
            System.out.println("Taking seat");
        }
    
        /**
         * 目标方法执行完后调用
         */
        @AfterReturning("watch()")
        public void applause() {
            System.out.println("CLAP CLAP CLAP");
        }
    
        /**
         * 目标方法发生异常时调用
         */
        @AfterThrowing("watch()")
        public void demandRefund() {
            System.out.println("Demanding a refund");
        }
    
        /**
         * 环绕通知
         * @param p 通过它调用目标方法
         */
        @Around("watch()")
        public Object aroundWatch(ProceedingJoinPoint p) {
            Object o = null;
            try {
                System.out.println("Silencing cell phone");
                o = p.proceed();
                System.out.println("CLAP CLAP CLAP!!!");
            } catch (Throwable e) {
                System.out.println("Demanding a refund");
            }
            return o;
        }
    }

    三、创建配置文件

    XML是Spring的基础。尽管Spring—再简化配置,并且大有使用注解取代XML配置之势,但是无论如何,至少现在XML还是Spring的基础。要在Spring中开启AOP功能,还需要在配罝文件中作如下声明:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                                http://www.springframework.org/schema/beans/spring-beans.xsd
                                http://www.springframework.org/schema/aop
                                http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <aop:aspectj-autoproxy/>
    
        <bean id="audience" class="org.cellphone.uc.aop.Audience"/>
        <bean id="aspectJAudience" class="org.cellphone.uc.aop.AspectJAudience"/>
    </beans>

    四、测试

    经过以上步骤后,便可以验证Spring的AOP为我们提供的神奇效果了。

    public class AspectJMain {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("spring/aop-test.xml");
            Audience audience = (Audience) context.getBean("audience");
            audience.watch();
        }
    }

    不出意外,我们会看到控制台中打印了如下代码:

    Silencing cell phone
    Silencing cell phone
    Taking seat
    Watch movie
    CLAP CLAP CLAP!!!
    CLAP CLAP CLAP

    Spring实现了对所有类的watch方法进行增强,使辅助功能可以独立于核心业务之外,方便 与程序的扩展和解耦。

    那么,Spring究竞是如何实现AOP的呢?首先我们知道,Spring是否支持注解的AOP是由一个配置文件控制的,也就是<aop:aspectj-autoproxy/>,当在配置文件中声明了这句配置的时候,Spring就会支持注解的AOP,那么我们的分析就从这句注解开始。

  • 相关阅读:
    【openCV学习笔记】【2】读取并播放一段视频
    Net WebApi中使用Swagger
    .pfx格式和.Cer格式的区别
    数字证书原理
    ASP.NET发送电子邮件
    WindowsAzure上把WebApp和WebService同时部署在一个WebRole中
    JS原型与原型链终极详解
    三、ASP.NET MVC Controller 控制器(二:IController控制器的创建过程)
    二、ASP.NET MVC Controller 控制器(一:深入解析控制器运行原理)
    一、ASP.NET Routing路由(深入解析路由系统架构原理)
  • 原文地址:https://www.cnblogs.com/warehouse/p/9425372.html
Copyright © 2020-2023  润新知