面向切面的Spring

Posted hoo334

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向切面的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 Performance performance(){
return new ConcertPerformance();
}


@Bean
public Audience audience(){
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类中。

 

技术图片
切面运行结果

这里详细写一下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 编译器,我没换也能运行,不知道为啥。。

以上是关于面向切面的Spring的主要内容,如果未能解决你的问题,请参考以下文章

面向切面的Spring

面向切面的Spring

面向切面的spring

Spring系列Spring中AOP面向切面的编程(动态代理)

面向切面的Spring

面向切面的Spring