Spring的面向切面

Spring的面向切面

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

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

1、面向切面基础

(一)AOP术语maven

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

1.通知(Advice学习

  当咱们往那些须要插入通用功能的类中进行插入时,通知就是定义这个功能是什么以及在何时插入,是方法调用以前?以后?仍是先后都要用?测试

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

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

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

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

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

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切面

2、建立切面

(一)使用注解建立切面

  若是使用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须要与切点方法签名中的参数相匹配。

相关文章
相关标签/搜索