4.3使用注解创建切面
4.3.1定义切面
package aspect;
/**
* @version 版权 Copyright(c)2019
* @ClassName: 表演接口
* @Descripton:
* @author: Shing
* @date: 2020-06-09 18:35
*/
public interface Performance {
public void perform();
}
@Component
public class DramaPerformance implements Performance{
@Override
public void perform() {
System.out.println("戏剧在表演...");
// throw new RuntimeException("不好看...");
}
}
package aspect;
import org.aspectj.lang.annotation.*;
/**
* @version 版权 Copyright(c)2019
* @ClassName: 观众 切面类
* @Descripton:
* @author: Shing
* @date: 2020-06-09 18:42
*/
@Aspect
public class Audience {
/**
* 重复写aspect表达式,可以使用Pointcut注解
*/
@Pointcut("execution(* aspect.Performance.perform(..))")
public void performance(){}
// @Before("execution(* aspect.Performance.perform(..))")
@Before("performance()")
public void silenceCellPhones(){
System.out.println("手机静音");
}
// @Before("execution(* aspect.Performance.perform(..))")
@Before("performance()")
public void takeSeats(){
System.out.println("Taking Seats");
}
// @AfterReturning("execution(* aspect.Performance.perform(..))")
@AfterReturning("performance()")
public void applause(){
System.out.println("CLAP CLAP CLAP");
}
// @AfterThrowing("execution(* aspect.Performance.perform(..))")
@AfterThrowing("performance()")
public void demandRefund(){
System.out.println("垃圾 退票");
}
}
package aspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* @version 版权 Copyright(c)2019
* @ClassName: 切面配置到容器
* @Descripton: 如果仅仅只是配置了切面类@Aspect,但它并不会被视为切面,这些注解不会解析、创建将其转换为切面的代理
* 所以需要把声明切面类,并且启用自动代理功能。
* @author: Shing
* @date: 2020-06-09 19:21
*/
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AspectConfig {
@Bean
public Audience audience(){
return new Audience();
}
}
package aspect;打印结果:
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;
/**
* @version 版权 Copyright(c)2019
* @ClassName: 测试
* @Descripton:
* @author: Shing
* @date: 2020-06-09 19:13
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= AspectConfig.class)
public class AspectTest {
@Autowired
private Audience audience;
@Autowired
private Performance performance;
@Test
public void testAspect(){
performance.perform();
}
}

4.3.2创建环绕通知
环绕通知 相当于 编写前置通知与后置通知
上面也说了,当没有声明切面类的bean时候,是不会生效的。所以当有多个切面类服务于一个切点,只需声明被使用的就行。
package aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
* @version 版权 Copyright(c)2019
* @ClassName: 观众 切面类 环绕
* @Descripton:
* @author: Shing
* @date: 2020-06-09 18:42
*/
@Aspect
public class Audience_around {
/**
* 重复写aspect表达式,可以使用Pointcut注解
*/
@Pointcut("execution(* aspect.Performance.perform(..))")
public void performance(){}
@Around("performance()")
public void watchPerformance(ProceedingJoinPoint jp){
try {
System.out.println("手机静音");
System.out.println("Taking Seats");
jp.proceed();
System.out.println("CLAP CLAP CLAP");
}catch (Throwable e){
System.out.println("垃圾 退票");
}
}
}
4.3.3处理通知中的参数
/**
* @version 版权 Copyright(c)2019
* @ClassName: 使用切点表达式传参
* @Descripton:
* @author: Shing
* @date: 2020-06-11 07:02
*/
@Aspect
public class Audience_beforeparam {
@Pointcut("execution(* aspect.Performance.perform(String)) && args(pfName)")
public void performance(String pfName){};
@Before("performance(pfName)")
public void silenceCellPhones(String pfName){
System.out.println(pfName);
System.out.println("手机静音");
}
}
4.3.4通过注解引入新功能(方法)
Spring的自动代理机制将会获取到它的什么,当Spring发现一个bean使用了@Aspect注解时,Spring就会创建一个代理,然后将调用委托给被代理的bean或者被引入的实现。这取决于调用的方法属于被代理的bean还是属于被引入的接口。
/**
* @version 版权 Copyright(c)2019
* @ClassName: 表演太好了,观众想再看一次
* @Descripton:
* @author: Shing
* @date: 2020-06-11 13:10
*/
public interface Encoreable {
void performEncore();
}
/**
* @version 版权 Copyright(c)2019
* @ClassName:
* @Descripton:
* @author: Shing
* @date: 2020-06-11 13:13
*/
public class DefaultEncoreable implements Encoreable{
@Override
public void performEncore() {
System.out.println("太棒了,在来一次");
}
}
/**
* @version 版权 Copyright(c)2019
* @ClassName:
* @Descripton: 通过注解引入新功能(方法)
* @author: Shing
* @date: 2020-06-11 13:14
*/
@Aspect
public class EncoreableIntroducer {
/**
* value:指定了那种类型的bean要引入该接口,在这里的话,就是所有实现了Performace的类型。标记符+表示Perform所有之类,而不是本身。
* defaultImpl:指定了为引用功能提供实现的类。
* DeclareParents:注解所标示的静态属性指明了要引入的接口。
*/
@DeclareParents(value = "aspect.Performance+",defaultImpl = DefaultEncoreable.class)
public static Encoreable encoreable;
}
测试方法1:
@Autowired
private Performance performance;
@Test
public void testEncoreablePerform(){
performance.perform("莎士比亚-tempest");
Encoreable encoreable = (Encoreable)performance;
encoreable.performEncore();
}
测试方法2:
@Autowired
private Performance performance;
@Autowired
private Encoreable encoreable;
@Test
public void testEncoreablePerform(){
performance.perform("莎士比亚-tempest");
encoreable.performEncore();
}

浙公网安备 33010602011771号