Spring基于注解的AOP配置

Joinpoint(连接点):

所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。指的是所有可以被增强的方法。

Pointcut(切入点):

所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。指的是已经决定即将要增强的方法。比如我决定要对saveAccount方法进行增强了,那么该方法就是切入点。

Advice(通知/增强):

所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。增强的代码所在的方法。如果我们要用Logger类中的pringtLog方法对saveAccount()进行增强,那么printLog方法就是通知或者说是增强。

Introduction(引介):-了解

引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field。通知是方法层面的,而引介是针对类层面的,可以动态的添加一个类的属性或者方法。

Target(目标对象):

代理的目标对象。将要对哪个对象进行增强。

Weaving(织入):

是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。将通知应用到切入点的过程。

Proxy(代理):

一个类被AOP织入增强后,就产生一个结果代理类。根据被代理对象的情况的不同,可能会生成一个基于接口的代理对象,也可能会生成一个基于子类的代理对象。

Aspect(切面):

是切入点和通知(引介)的结合。多个通知和多个切入的组合。

使用xml配置AOP:

<bean id="logger" class="com.demon.utils.Logger"/>
<aop:config>
    <aop:aspect id="logAdvice" ref="logger">
        <!-- 配置前置通知
             method:配置通知方法(即具体进行增强的方法)
             pointcut:配置AspectJ表达式,即将通知增强到哪个方法
             execution:使用AspectJ的切入点表达式
                     execution(修饰符 返回值类型 包名.类名.方法名(参数列表))
        -->
        <aop:before method="beforePrintLog" pointcut="execution(public void com.demon.service.impl.AccountServiceImpl.saveAccount())"/>
        <aop:after-returning method="afterReturningPrintLog" pointcut="execution(public void com.demon.service.impl.AccountServiceImpl.updateAccount(int))"
        <aop:after-throwing method="afterThrowingPrintLog" pointcut="execution(public void com.demon.service.impl.AccountServiceImpl.updateAccount(int)))"/
        <aop:after method="afterPrintLog" pointcut="execution(public int com.demon.service.impl.AccountServiceImpl.deleteAccount())"/>
    </aop:aspect>
</aop:config>

AspectJ切入点表达式说明

配置切入点表达式:aspectj表达式
    1、修饰符可以省略:表示对所有方法进行增强
        execution(void cn.itcast.service.impl.AccountServiceImpl.saveAccount())
    2、返回值类型可以使用*代替:表示任意返回值类型
        execution( * cn.itcast.service.impl.AccountServiceImpl.saveAccount())
    3、包名可以使用*代替:表示任意名称的包名
        execution( * *.*.*.*.AccountServiceImpl.saveAccount())
    4、如果有多个包名,可以使用*..代替:表示任意多个包名
        execution( * *..AccountServiceImpl.saveAccount())
    5、类名可以使用*代替:表示任意名称的类
        execution( * *..*.saveAccount())
    6、方法名称可以使用*代替:表示任意名称的方法
        execution( * *..*.*())
    7、参数可以使用*代替:表示任意类型的参数,但至少有一个参数
        execution( * *..*.*(*))
    8、参数使用..代替:表示任意多个,任意类型的参数
        execution( * *..*.*(..))
    
    最终推荐的表达式的写法:
        execution(* com.demon.service.impl.*.*(..))

使用注解配置AOP:

第一步:创建配置类

@Configuration
@ComponentScan(value = {"com.demon"})
@EnableAspectJAutoProxy
public class SpringConfiguration {

}

第二步:注解装配service实现类

@Service("accountService")
public class AccountServiceImpl implements IAccountService {

    @Override
    public void saveAccount() {
        System.out.println("保存账户");
    }

    @Override
    public void updateAccount(int i) {
        System.out.println("更新账户");
    }

    @Override
    public int deleteAccount() {
        System.out.println("删除账户");
        return 0;
    }
}

第三步:在通知类上使用@Aspect注解声明为切面

@Component
@Aspect//表示当前类是一个切面类(也可以称之为通知类)
public class Logger {}

第四步:使用注解配置通知类型

配置前置通知、后置通知、异常通知、最终通知

@Component
@Aspect
public class Logger {

    /**
     * 指定切入点表达式
     */
    @Pointcut("execution(* com.demon.service.impl.*.*(..))")
    public void pt1() {
    }

    /**
     * 前置通知
     * value:用于指定切入点表达式,还可以指定切入点表达式的引用。
     */
    @Before("pt1()")
    public void beforePrintLog(){
        System.out.println("前置通知执行了");
    }

    /**
     * 后置通知
     * value:用于指定切入点表达式,还可以指定切入点表达式的引用
     */
    @AfterReturning("pt1()")
    public void afterReturningPrintLog(){
        System.out.println("后置通知执行了");
    }

    /**
     * 异常通知
     * value:用于指定切入点表达式,还可以指定切入点表达式的引用
     */
    @AfterThrowing("pt1()")
    public void afterThrowingPrintLog(){
        System.out.println("异常通知执行了");
    }

    /**
     * 最终通知
     * value:用于指定切入点表达式,还可以指定切入点表达式的引用
     */
    @After("pt1()")
    public void afterPrintLog(){
        System.out.println("最终通知执行了");
    }
}

配置环绕通知

/**
 * 指定切入点表达式
 */
@Pointcut("execution(* com.demon.service.impl.*.*(..))")
public void pt1() {
}

/**
 * 环绕通知
 * value:用于指定切入点表达式,还可以指定切入点表达式的引用。
 * spring框架为我们提供了一个接口,该接口可以作为环绕通知的方法参数来使用
 * ProceedingJoinPoint。当环绕通知执行时,spring框架会为我们注入该接口的实现类。
 * 它有一个方法proceed(),就相当于invoke,明确的业务层方法调用
 * spring的环绕通知:
 *   它是spring为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
 */
@Around("pt1()")
public Object around(ProceedingJoinPoint pjp) {
    Object proceed = null;
    try {
        beforePrintLog();
        proceed = pjp.proceed();
        afterReturningPrintLog();
    } catch (Throwable throwable) {
        throwable.printStackTrace();
        afterThrowingPrintLog();
    } finally {
        afterPrintLog();
    }
    return proceed;
}

第五步:编写测试类

public class IAccountServiceTest {

    private IAccountService accountService;

    @Before
    public void setUp() throws Exception {
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        accountService = (IAccountService) ac.getBean("accountService");
    }

    @Test
    public void saveAccount() {
        accountService.saveAccount();
    }

    @Test
    public void updateAccount() {
        accountService.updateAccount(1);
    }

    @Test
    public void deleteAccount() {
        accountService.deleteAccount();
    }
}

配置注解AOP的步骤
    1、开启注解AOP
    2、在切面类上使用@Aspect,声明这是一个切面类
    3、在切面类中使用各类通知

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringAOP(面向切面编程)是通过注解配置的。AOP是一种用于将横切关注点(如日志记录、事务管理等)与主业务逻辑分离的技术。使用注解配置AOP可以更简洁、灵活地定义切面和通知。 要配置AOP,我们需要使用到Spring的几个注解。首先是使用@Aspect注解定义一个切面,该注解告诉Spring这是一个切面类。然后,我们可以在切面类内部定义多个通知方法,通知方法使用@Before、@After、@Around等注解来指定它们在目标方法之前、之后或者环绕目标方法执行。 在通知方法内部,我们可以通过使用@Pointcut注解来定义切点表达式,切点表达式用于指定哪些方法需要被拦截,以何种方式进行拦截。通过@Pointcut定义的切点可以被多个通知方法共享。 除了切面和通知,我们还可以使用其他注解来指定通知的类型。例如,使用@Before注解表示在目标方法执行之前执行通知方法,使用@After注解表示在目标方法执行之后执行通知方法,使用@Around注解表示在目标方法执行之前和之后都执行通知方法。 配置AOP时,我们还需要使用@Bean注解来将切面类注册为Spring的一个bean。这样,Spring容器才能够自动识别它并将其应用于适当的目标方法。 总结一下,通过使用注解配置AOP,我们可以更方便地定义切面和通知,并将它们应用于目标方法。SpringAOP注解提供了灵活的方式来实现横切关注点的分离,使得代码更具可读性和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值