Spring AOP入门

作者: Real_man | 来源:发表于2018-06-24 20:48 被阅读69次

    Spring的核心有两部分,IOC和AOP,那么AOP的重要性可想而知,今天一块来了解下Spring AOP相关的内容。

    AOP概念

    AOP(Aspect-Oriented Programming)是面向切面编程的简称,定义如下:

    计算机科学中,AOP是一种编程范式,通过分离横切关注点点来增加模块性。它可以在已有的代码上增加额外的行为,却不需要修改已有的代码,而是通过指定代码的切点来实现。
    In computing, aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. It does so by adding additional behavior to existing code (an advice) without modifying the code itself, instead separately specifying which code is modified via a "pointcut" specification

    个人对这个概念的理解,如果仅仅使用OOP编程,虽然对象与对象有相互交错的地方,但大部分时候我们要遵循“单一职责”原则,即每个类只做一件事,做好自己的事情,这样很多类都是只做自己的事,类之间不相互知悉,但实际上它们之间有一些共同的事情要做。比如日志,事务,认证操作。

    虽然通过OOP的设计模式也可以实现复用效果,但AOP更加直观容易操作,OOP本身还是在代码中比AOP耦合的更多,AOP基本不需要侵入修改原本的代码。

    如图:


    image.png

    AOP 术语

    image.png
    • JoinPoint(连接点,加入点),如类的初始化前,类的初始化后,类的某个方法调用前,类的某个方法调用后,方法抛出异常后等位置。 Spring仅支持方法的JoinPoint
    • PointCut(切点),每个程序都有多个JoinPoint, 其中我们感兴趣的那个JoinPoint,要下手操作的那个点叫做Pointcut。
    • Advice(增强),我们找到感兴趣的点(PointCut)之后做什么呢,不管做什么,都是比之前做的事情多了那么一点点,所以可以理解为增强。
    • Target 目标对象,要下手的目标类
    • Weaving (织入),将Advice添加到Target的具体JoinPoint的过程。

    AOP案例

    先看一个案例,然后根据案例来进行思考。
    需要对Spring的Ioc及Bean的概念有些了解。

    1. 新建一个Maven项目,依赖如下
     <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>4.3.14.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>4.3.14.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.11</version>
            </dependency>
            <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.2</version>
            </dependency>
        </dependencies>
    
    1. 新建测试类HelloWorld,
    public class HelloWorld {
        public void sayHello(){
            System.out.println("hello");
        }
    }
    
    
    1. 新建在切点上的操作,上面提到了AOP是对某些通用的东西做一些操作,操作被称为Advice
    /**
    * 记录方法的执行时间
    */
    public class TimeLoggingAop implements MethodBeforeAdvice,AfterReturningAdvice {
        private long startTime = 0;
    
        @Override
        public void before(Method method, Object[] objects, Object o) throws Throwable {
            startTime = System.nanoTime();
    
        }
    
        @Override
        public void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable {
            long spentTime = System.nanoTime() - startTime;
            String clazzName = target.getClass().getCanonicalName();
            String methodName = method.getName();
            System.out.println("执行" + clazzName + "#" + methodName + "消耗" + new BigDecimal(spentTime).divide(new BigDecimal(1000000)) + "毫秒");
        }
    }
    
    1. resouce目录下新建Spring配置文件
    <?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/tool http://www.springframework.org/schema/tool/spring-tool.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <bean id="helloworld" class="com.qiandao.mall.controller.HelloWorld" />
        <bean id="timeLog" class="com.qiandao.mall.controller.TimeLoggingAop" />
        <aop:config>
            <aop:pointcut id="hello" expression="execution(public * * (..))"></aop:pointcut>
            <aop:advisor
                    id="timelogAdvisor"
                    advice-ref="timeLog"
                    pointcut-ref="hello"
            />
        </aop:config>
    </beans>
    
    1. 创建App类
    public class App {
        public static void main(String[] args) {
            // 加载Spring配置文件
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("app.xml");
            HelloWorld helloWorld = applicationContext.getBean(HelloWorld.class);
            helloWorld.sayHello();
    
        }
    }
    
    
    1. 运行结果
    hello
    执行com.qiandao.mall.controller.HelloWorld#sayHello消耗33.337513毫秒
    

    案例分析

    我们的HelloWorld类功能只是打印Hello,最后在打印Hello之后,又打印了这个方法的执行时间。

    其中:

    • HelloWorld为目标对象
    • TimeLogAOP实现了BeforeAdvice,AfterReturningAdvice 是 Advice
    • Pointcut为HelloWorld的方法执行前与方法返回值后,两个切点
    • 织入过程为Spring内部实现

    最后

    本次我们解释了AOP的概念和AOP相关的术语,并通过一个案例来说明具体术语的含义,希望能帮到大家。

    相关文章

      网友评论

        本文标题:Spring AOP入门

        本文链接:https://www.haomeiwen.com/subject/xomsyftx.html