面向切面的Spring

我们知道如何使用依赖注入(DI)管理和配置我们的应用对象,DI有助于应用对象之间的解耦,而AOP可以实现横切关注点与他们所影响的对象之间的解耦。切面能帮助我们模块化横切关注点,横切关注点可以被描述为影响应用多处的功能。

定义AOP术语,描述切面的术语有通知,切点和连接点。

通知定义了切面是什么以及切面何时开始使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题。它应该应用在某个方法被调用之前?之后?之前和之后都调用?还是只在方法抛出异常时调用?

Spring切面可以应用5种类型的通知:

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

后置通知:在目标方法完成之后调用通知功能;

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

异常通知:在目标方法抛出异常后调用的通知功能;

环绕通知:通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

我们的应用可能有数千计的时机应用通知。这些时机被称为连接点。连接点是在应用执行过程中能够插入切面的一个点,这个点可以是调用方法时,抛出异常时,甚至修改一个字段时,切面代码可以利用这些点插入到应用正常的流程之中,并添加新的行为。

如果说通知定义了切面的“什么”和“何时”的话,那么切点就定义了“何处”切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式来匹配通知所要织入的一个或多个连接点。

切面是通知和切点的结合。通知和切点共同定义了切面的全部内容--它是什么,在何时和何处完成其功能。

织入是把切面应用到目标对象并创建新的代理对象的过程。

我们先定义一个Performance接口

package concert;

public interface Performance {

public void perform();

}

再定义一个它的实现类

package concert;

public class ConcertPerformance implements Performance {

@Override

    public void perform() {

System.out.println("Performing...");

    }

}

重点是这里的Audience类

package concert;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.*;

@Aspect

public class Audience {

@Pointcut(value ="execution(* concert.Performance.perform(..))")

public void performance() {}

@Before("performance()")

public void silenceCellPhone() {

System.out.println("silencing cellPhone");

    }

@After("performance()")

public void afterPerformance() {

System.out.println("after performance");

    }

@AfterThrowing("performance()")

public void demanRefund() {

System.out.println("demanding a refund");

    }

// 环绕通知

    @Around("performance()")

public void watchPerformance(ProceedingJoinPoint joinPoint) {

try {

            System.out.println("around before performance...");

            joinPoint.proceed();

            System.out.println("around after performance...");

        }catch(Throwable t) {

t.printStackTrace();

        }

}

}

@Aspect声明这是一个Aspect注解驱动的切面。

@Poincut定义了一个切点,execution(* concert.Performance.perform(..))代表perform这个方法执行时将会声明为一个切点

“ * ” 代表任意返回值类型,“ .. ”代表任意参数类型。也可以写成 * *.perform(..)代表任意类的perform方法。

@Before,@After,@AfterThrowing,分别是前置,后置,异常通知。

@Around声明一个环绕通知

这还不够,我们需要一个配置类,来启用自动代理功能。

package concert;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration

@EnableAspectJAutoProxy

@ComponentScan(basePackages = {"concert"})

public class ConcertConfig {

@Bean

    public Performanceperformance(){

return new ConcertPerformance();

    }

@Bean

    public Audienceaudience(){

return new Audience();

    }

}

@EnableAspectJAutoProxy注解启动了自动代理功能,这里我们声明了两个Bean。

接下来测试一下,AOPTest类

package concert;

import concert.ConcertConfig;

import concert.Performance;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(classes= {ConcertConfig.class})

public class AOPTest {

@Autowired

    private Performance performance;

    @Test

    public void testAop() {

performance.perform();

    }

}

performance对象会自动注入到AOPTest类中。

 

面向切面的Spring
切面运行结果

这里详细写一下IDEA 配置AspectJ的步骤:

1、启用IDEA AspectJ plugin File---Settings--Plugins,搜索栏内搜索AspectJ,启用支持,注意这里只有Ultimate版才会有。

2、添加依赖

build.gradle添加

compile"org.springframework:spring-context:4.0.7.RELEASE"

compile"org.springframework:spring-test:4.0.7.RELEASE"

compile group:'org.aspectj',name:'aspectjtools',version:'1.8.9'

testCompile"org.springframework:spring-test:4.0.7.RELEASE"

implementation'junit:junit:4.12'

其他博客说要换Ajc Java 编译器,我没换也能运行,不知道为啥。。

上一篇:Performance Tuning MySQL


下一篇:CH2 程序性能