• Spring的面向切面


    Spring的面向切面

      在应用开发中,有很多类似日志、安全和事务管理的功能。这些功能都有一个共同点,那就是很多个对象都需要这些功能。复用这些通用的功能的最简单的方法就是继承或者委托。但是当应用规模达到一定程度时,使用继承或委托将会使应用的结构非常复杂。

      面向切面便是解决上面问题的最佳办法。我们把这些通用的功能(横切关注点)放在专门的类中(这种类又叫切面),然后在程序运行后通过动态代理,将这些功能插入到需要这些功能的类中。在这种模式下,这些通用的功能都是通过切面统一管理,使得模块之间更加清晰。

    一、面向切面基础

    (一)AOP术语

      在学习Spring的面向切面时,首先需要学习SpringAOP术语。在切面中常用的术语有通知(advice)、切点(pointcut)和连接点(joinpoint)。

    1.通知(Advice

      当我们往那些需要插入通用功能的类中进行插入时,通知就是定义这个功能是什么以及在什么时候插入,是方法调用之前?之后?还是前后都要用?

        前置通知:在目标方法调用之前调用通知功能。

        后置通知:在目标方法调用之后调用通用功能,此时不关心方法的输出是什么。

        返回通知:在目标方法成功执行后调用通知。

        异常通知:在目标方法抛出异常后调用通知。

        环绕通知:在目标方法的前后执行自定义的行为。

    2.连接点(Join point

      连接点就是所有可以插入功能的点的集合,例如,调用方法时、抛出异常时、修改一个字段时。Spring只支持方法级别的连接点。

    3.切点(Pointcut

      我们知道,很多的连接点都可以进行插入功能,但是只有在需要这个功能地方进行插入才会有意义,而这些“需要”的地方,就是切点。

      上面说到通知定义了功能是什么以及在什么时候插入。那么切点就是定义在什么地方插入。

    4.切面(Aspect

      切面就是通知和切点的结合,他们一起定义了功能是什么以及什么时候、什么地方插入。

    5.引入(Introduction

      引入允许我们向现有的类添加新方法或属性(其实是通过动态代理,生成一个和原有类有一样方法的类,同时在这个类中添加新方法或属性。因为方法一样,我们完全可以把新生成的类看成是原来的类)。这样我们就可以在不修改类的情况下让他有新的行为和状态。

    6.织入(Weaving

      织入就是把切面应用到目标对象的过程,就是前面说的“插入”。

     

    (二)Spring中使用AOP的几种方式

    Spring提供四种AOP支持

    1. 基于代理的经典SpringAOP
    2. POJO切面(借助Springaop命名空间,pojo提供调用方法)
    3. @AcpectJ注解驱动的切面(可以不借助XML来实现AOP
    4. 注入式AspectJ切面

    二、创建切面

    (一)使用注解创建切面

      如果使用AspectJ的注解,需要aspectjrtaspectjweaver依赖。

      切面就是一个特殊的类,之所以特殊是因为要在类上添加@Aspect注解。并且这个切面也需要是一个bean

      下面我们根据一个实例来了解切面的创建,在这个实例中,我们要通过AOP的技术,使得所有的汽车在启动的前后都需要进行安全检查。

      首先需要一个接口来构建一个车的骨架。

       

      有公交车和货车都实现了这个接口。

       

      

      我们的目的是让所有实现Car接口的车在启动前后都能进行安全检查,例如启动前车门情况,跑完锁是否关了等,下面是AOP的实现。

       

      当我们把切面声明完以后,还需要启动AspectJ自动代理,否则就不会生效。

      在JavaConfig中,启动需要添加@EnableAspectJAutoProxy注解

       

      在XML中,需要Spring Aop空间的<aop:aspectj-autoproxy>元素

       下面是测试代码,测试使用了:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {Config.class})
    public class CarTest {
        @Autowired
        private Car bus;
        @Autowired
        private Car trucks;
        @Test
        public void go(){
            bus.run();
            bus.change(1);
            bus.change(2);
            System.out.println("--------");
            trucks.run();
        }
    
    }
    View Code

      我是使用maven创建的项目,下面是依赖:

    <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>4.3.12.RELEASE</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/junit/junit -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>4.3.10.RELEASE</version>
                <scope>test</scope>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.hamcrest/hamcrest-core -->
            <dependency>
                <groupId>org.hamcrest</groupId>
                <artifactId>hamcrest-core</artifactId>
                <version>1.3</version>
                <scope>test</scope>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>4.3.11.RELEASE</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>1.8.10</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.4</version>
            </dependency>
    View Code

    (一)处理通知中的参数

    当我们创建通知时,可能会需要切入点方法调用时的参数。例如,在计算汽车油量时,通知应该在汽车换挡时获取切换的档数,然后根据档数来计算油耗。

     

    在这个例子中,通过args(num)限定符实现了参数的传递。它说明change()方法的int参数会被传递到通知中去。参数的名称a需要与切点方法签名中的参数相匹配。

  • 相关阅读:
    C指针
    redis五种基本数据类型
    mongoDB MapReduce
    JSON传参
    mongodb查询实练
    逻辑数据结构和存储数据结构
    线性表的顺序存储和链式存储
    数据结构和算法关系
    UIActivityIndicatorView使用
    Swift中格式化日期
  • 原文地址:https://www.cnblogs.com/chenkeyu/p/7711600.html
Copyright © 2020-2023  润新知