Spring in Action学习笔记(2)

Spring基础

AOP 面向切面编程

通知、连接点、切点、切面

Spring提供 4 种类型的AOP支持:

  • 基于代理的经典SpringAOP:使用ProxyFactoryBean。
  • 纯POJO切面:使用XML配置;
  • @ASpectJ注解驱动的切面;
  • 注入式AspectJ切面。

前三种都属于SpringAOP,基于代理(JDK动态代理和Cglib)。第四种属于AspectJ。

通过切点来选择连接点

切点表达式:

execution(* a.b.c.method(...)) && bean('some')

execution(* soundSystem.CompactDisc.playTrack(int)) && args(trackNumber)

1. 使用注解创建切面

@Aspect 注解 表明类是一个切面

Spring使用了 AspectJ库的注解并且使用 AspectJ库对切点表达式进行解析和匹配(需要aspectjweaver.jar),但AOP运行时并不使用 AspectJ的编译器和织入,仍然是使用纯粹的SpringAOP实现。

  1. 切面的方法前使用注解:
    @Before("切点表达式") 通知方法会在目标方法调用之前执行;
    @After("切点表达式") 通知方法会在目标方法返回或抛出异常后调用;
    @AfterReturning("切点表达式") 通知方法会在目标方法返回后调用;
    @AfterThrowing("切点表达式") 通知方法会在目标方法抛出异常后调用;
    @Around("切点表达式") 通知方法会将目标方法封装起来。
  2. @Pointcut("切点表达式") 注解方法,定义一个切点

该切面类需要装配为Spring中的bean,并且需要在配置类前使用@EnableAspectJAutoProxy 注解启用自动代理。

环绕通知:

@Aspect
public class Audience{

    @Pointcut("execution(** concert.Performance.perform(..))")
    public void performance(){}

    @Around("performance()")
    public void watchPerformance(ProceedingJoinPoint jp){
        try{
            //Before前置通知
            jp.proceed();   //调用被通知的方法,可以不调用以阻塞,也可以多次调用
            //AfterReturning后置通知
        }catch(Throwable e){
            //AfterThrowing后置通知
        }
    }
}

通过注解引入新功能:

@Aspect
public class EncoreableIntroducer{  //定义切面
    @DeclareParents(valule = "concert.Performance+",    //哪种类型的bean要引入该接口
                    deafultImpl = DefaultEncoreable.class) //为引入接口提供实现的类
    public static Encoreable encoreable;    //要引入的接口
}

上述类需要被声明为一个bean

2. 在XML中声明切面

如果你需要声明切面,但是又不能为通知类切面类添加注解的时候(没有源码),那么就必须转向XML配置了

  • [ ] TODO

3. 注入AspectJ切面

首先配置AspectJ的环境:

  1. 在https://www.eclipse.org/aspectj/downloads.php#ides 下载aspectj-1.x.x.jar;
  2. 使用java -jar aspectj-1.1.0.jar进行安装;
  3. 将 ${aspect_path}/lib/aspectjrt.jar加入项目的依赖;
    在IDE中将编译器设置为Ajc,路径为${aspect_path}/bin/aspectjtools.jar;
文件 CriticAspect.aj:

package concert;

public aspect CriticAspect {    //定义切面,需在XML中配置为bean

    pointcut performance():execution(* concert.Performance.perform(..));    //定义切点

    after():performance(){  //定义通知
        System.out.println(criticismEngine.getCriticism());
    }

    private CriticismEngine criticismEngine;    //将被注入bean
    // 通过属性的setter()函数实现注入
    public void setCriticismEngine(CriticismEngine criticismEngine) {
        this.criticismEngine = criticismEngine;
    }
}
原文地址:https://www.cnblogs.com/caophoenix/p/11240507.html