spring学习笔记(7):AOP

一、Spring中的AOP的相关术语

1.JointPoint(连接点)和PointCut(切入点)

1.1 JointPoint(连接点)

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

1.2 PointCut(切入点)

所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。

1.3 二者区别

在这里插入图片描述

2.Advice(通知/增强):

所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
在这里插入图片描述

3.Introduction(引介)

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

4.Target(目标对象)

代理的目标对象。即是被代理对象
在这里插入图片描述

5.Weaving(织入)

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

  • 采用动态代理前的service无法实现事务的支持,加入动态代理,到返回代理对象的加入事务支持这个过程称为织入。

6.Proxy(代理)

  • 一个类被AOP织入增强后,就产生一个结果代理类。就是代理对象

7.Aspect(切面)

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

二、基于XML的AOP配置

1.pom.xml

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

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>

    </dependencies>

2.必要的代码

2.1业务层接口和实现类

public interface IAccountService {

    /**
     * 模拟保存账户
     */
    void saveAccount();

    /**
     * 模拟更新账户
     * @param i
     */
    void updateAccount(int i);

    /**
     * 删除账户
     * @return
     */
    int  deleteAccount();

}
public class AccountService implements IAccountService {


    public void saveAccount() {
        System.out.println("执行了保存");
    }


    public void updateAccount(int i) {
        System.out.println("执行了更新"+i);

    }

    public int deleteAccount() {
        System.out.println("执行了删除");
        return 0;
    }
}

2.2工具类:提供日志类

public class Logger {

    /**
     * 用于打印日志:计划让其在切入点方法执行之前执行(切入点方法就是业务层方法)
     */
    public  void printLog(){
        System.out.println("Logger类中的pringLog方法开始记录日志了.......");
    }

}

3.bean.xml

Spring的任何代码都依赖于IOC

    <!--先配置service层方法-->
    <bean id="accountService" class="com.xpt.service.impl.AccountServiceImpl"></bean>
   <bean id="logger" class="com.xpt.utils.Logger"></bean>

    <!--配置AOP-->
    <aop:config>
        <!--配置切面-->
        <aop:aspect id="logAdvice" ref="logger">
            <!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
            <aop:before method="printLog" pointcut="execution( public void com.xpt.service.impl.AccountServiceImpl.saveAccount())"></aop:before>
        </aop:aspect>

    </aop:config>

4.测试类

上面完成了AOP的最基本的配置,下面开始测试

    public static void main(String[] args) {
        //.1获取IOC容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.测试方法
        as.saveAccount();
        System.out.println("-----------");
        as.deleteAccount();
    }

4.1结果

在这里插入图片描述

5. 切入点表达式的写法

上面完成了一次简单的AOP的配置过程,下面详细的说明切入点表达式的写法

5.1各种写法

在这里插入图片描述

5.2开发中建议写法

在这里插入图片描述

6.通知类型

6.1增加日志类方法

public class Logger {


    /**
     * 前置通知
     */
    public  void beforePrintLog(){
        System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。");
    }

    /**
     * 后置通知
     */
    public  void afterReturningPrintLog(){
        System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。");
    }
    /**
     * 异常通知
     */
    public  void afterThrowingPrintLog(){
        System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。");
    }

    /**
     * 最终通知
     */
    public  void afterPrintLog(){
        System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");
    }
}

6.2增强配置信息

    <!--配置AOP-->
    <aop:config>
        <!--配置切面-->
        <aop:aspect id="logAdvice" ref="logger">
            <!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
            <!-- 配置前置通知:在切入点方法执行之前执行-->
            <aop:before method="beforePrintLog" pointcut="execution( * com.xpt.service.impl.*.*(..))"></aop:before>

            <!-- 配置后置通知:在切入点方法正常执行之后值。它和异常通知永远只能执行一个-->
            <aop:after-returning method="afterPrintLog" pointcut="execution( * com.xpt.service.impl.*.*(..))"></aop:after-returning>

            <!--&lt;!&ndash; 配置异常通知:在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个-->
            <aop:after-throwing method="afterThrowingPrintLog"  pointcut="execution( * com.xpt.service.impl.*.*(..))"></aop:after-throwing>

            <!--&lt;!&ndash; 配置最终通知:无论切入点方法是否正常执行它都会在其后面执行-->
           <aop:after method="afterPrintLog"  pointcut="execution( * com.xpt.service.impl.*.*(..))"></aop:after>

        </aop:aspect>

    </aop:config>

6.3测试效果

在这里插入图片描述

6.4 产生异常,查看效果

在这里插入图片描述- 注意点
在这里插入图片描述

7 通用化切入点表达式

  • 前面的切入点配置中有大量的重复配置
    在这里插入图片描述- 通用化切入点就是来解决这个问题的
    在这里插入图片描述
  • 效果
    在这里插入图片描述

8.环绕通知

8.1 日志类定义方法

在这里插入图片描述

8.2 bean.xml配置

 <aop:config>
        <aop:pointcut id="pt1" expression="execution( * com.xpt.service.impl.*.*(..))"></aop:pointcut>
        <!--配置切面-->
        <aop:aspect id="logAdvice" ref="logger">
            <aop:around method="aroundPrintLog" pointcut-ref="pt1"></aop:around>
        </aop:aspect>
    </aop:config>

8.3效果

在这里插入图片描述

8.4小结

  • Spring框架为我们提供了一个接口:ProceedingJoinPoint。该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。
  • 该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。

三、基于注解的AOP配置

1.bean.xml

在这里插入图片描述

2.注解部分

在这里插入图片描述

3.环绕通知的注解部分

在这里插入图片描述

四、基于xml配置的AOP实现银行转账案例中的事务控制

1.bean.xml中配置AOP

    <!--配置AOP Config-->
    <!--配置AOP config类-->
    <!--配置事务管理器-->
    <bean id="txManager" class="com.xpt.utils.TransactionManager">
        <!--注入connectionUtils-->
        <property name="connectionUtils" ref="connectionUtils"></property>

    </bean>
    <aop:config>
        <aop:pointcut id="pt1" expression="execution(* com.xpt.service.impl.*.*(..))"></aop:pointcut>

        <aop:aspect id="transaction" ref="txManager">

            <!--在执行数据库操作之前 应该开启事务-->
            <aop:before method="beginTransaction" pointcut-ref="pt1"></aop:before>

            <!--完成数据库操作后 应该提交事务-->
            <aop:after-returning method="commit" pointcut-ref="pt1"></aop:after-returning>
            <!--如果出现异常 应该进行回滚-->
            <aop:after-throwing method="rollback" pointcut-ref="pt1"></aop:after-throwing>

            <!--正常提交后 应该进行资源的释放-->
            <aop:after method="release" pointcut-ref="pt1"></aop:after>
        </aop:aspect>
    </aop:config>

2.事务控制类添加代码,方便观察

在这里插入图片描述

3.测试类修改

在这里插入图片描述

4.测试效果

在这里插入图片描述

5.小结

  • 基于AOP来进行事务控制,只需要在配置中进行相关配置和写好相关的事务控制代码
  • 不需要自己实现动态代理过程

6.环绕通知实现上述

    public Object aroundControl(ProceedingJoinPoint pjp){
        Object rtValue = null;
        try {
            //得到方法的执行参数
            Object[] args = pjp.getArgs();
            //开启业务层方法之前 开启事务
            beginTransaction();
            //调用业务层方法
            rtValue = pjp.proceed(args);
            //完成业务方法后 提交事务
            commit();
            return rtValue;
        } catch (Throwable throwable) {
            //出现异常 回滚事务
            rollback();
            throwable.printStackTrace();
            throw new RuntimeException(throwable);
        }finally {
            //释放资源
            release();
        }
    }

在这里插入图片描述

五、基于注解配置的AOP实现银行转账案例中的事务控制

1.bean.xml

在这里插入图片描述

2.业务层添加注解

在这里插入图片描述

3.持久层添加注解

在这里插入图片描述

4.事务管理层添加注解

注意只使用环绕通知
在这里插入图片描述

5.效果

  • 可以实现转账需求,并实现事务控制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值