欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring:基于xml和注解的aop

程序员文章站 2024-03-24 12:55:10
...

1、导入坐标

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

<!--用于解析切入点表达式的jar包-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.7</version>
</dependency>

2、建立通知类

将方法(主要是业务逻辑层的方法)中的共性代码抽取出来放到通知类中统一管理。

3、配置通知

配置文件中添加aop的约束。先配置ioc(spring的其它功能都需要基于ioc),再配置aop。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--先配置service的ioc-->
    <bean id="accountService" class="cao.zhanpeng.service.impl.AccountServiceImpl"/>

    <!--配置通知类的ioc-->
    <bean id="log" class="cao.zhanpeng.utils.Logger"/>

    <!--开始配置aop-->
    <aop:config>
        <!--配置切面,id表示该切面唯一标识符,ref用于指定通知类bean的id-->
        <aop:aspect id="logShow" ref="log">
            <!--配置通知类型,aop:before表示前置通知
            method指定通知类中哪个方法是前置通知(哪个是通知?)
            pointcut指定切入点表达式,表示对业务层的哪些方法进行通知(对谁通知?)
            -->
            <aop:before method="printLog" pointcut="execution(public void cao.zhanpeng.service.impl.AccountServiceImpl.saveMoney())"/>
        </aop:aspect>
    </aop:config>
</beans>

可以将切入点表达式独立出来

<!--将切入点表示式独立出来
如果放在切面内,只能当前切面引用
如果放在切面外,可以多个切面共用
-->
<aop:pointcut id="pt1" expression="execution(* cao.zhanpeng.service.impl.*.*(..))"/>
<!--再引用-->
<aop:before method="printLog" pointcut-ref="pt1"/>

切入点表达式

  • 关键字:execution(表达式)
  • 表达式:访问修饰符 返回值 通知目标类的全类名.方法名(参数列表)
  • 访问修饰符可以省略
  • 通常会将范围锁定到业务层的实现类包下
<!--星号表示任意通配符,双点..可以表示任意数量的通配符-->
* com.zanpng.service.impl.*.*(..)

 全通配写法如下(了解)

* *..*.*(..)

通知类型

aop:before,前置通知
aop:after-returning,后置通知
aop:after-throwing,异常通知,和后置通知互斥
aop:after,最终通知
aop:around,环绕通知

注解实现aop

1、配置环境

需要在applicationContext.xml文件导入context约束,配置ioc注解扫描,并直接使用以下标签开启aop注解。

<aop:aspectj-autoproxy/>

2、使用注解

在通知类上除了写上ioc注解,还要加上@Aspect注解,表示当前类是一个通知类。还要在对应的方法上使用如**解

@Before注解,前置通知
@AfterRunning注解,后置通知
@AfterThrowing注解,异常通知
@After注解,最终通知
@Around注解,环绕通知

定义一个空语句体的方法,使用@Pointcut注解传递切入点表达式,并且在其他注解中传递该方法,注意括号别忘了。

@Pointcut("execution(* cao.zhanpeng.service.impl.*.*(..))")
private void pt1(){}

@Before("pt1()")
public void beforePrintLog(){……}

在使用注解实现aop时,spring会出现一些执行顺序上的问题。所以如果要用注解,还是使用环绕通知来手动指定较好。环绕通知需要自己实现动态代理的代码,根据位置手动指定某个通知为何种类型。

  • spring框架提供了一个接口ProceedingJoinPoint,该接口可以作为通知类中环绕通知方法的参数,执行时spring会自动帮我们创建实现类对象,比如叫pjp。
  • pjp.getArgs()可以获取方法执行所需的参数。
  • ProceedingJoinPoint接口中有一个方法proceed(),此方法可以明确调用切入点方法(对应反射中的invoke方法),传递获取的参数即可。
@Around("pt1()")
public Object aroundPrintLog(ProceedingJoinPoint pjp){
    Object rtValue = null;
    try{
        Object[] args = pjp.getArgs();
        ……前置通知代码块……
        rtValue = pjp.proceed(args)
        ……后置通知代码块……
    }catch{
        ……异常通知代码块……
    }finally{
        ……最终通知代码块……
    }
}

有了环绕通知,就不能让其他的通知起作用了,否则会产生冲突。

相关标签: FRAME