zoukankan      html  css  js  c++  java
  • Spring中的Aop(三)通过spring的XML配置来实现AOP

    一、使用Aop来改造我们的代码

    在前两篇文章中,我们讲述了代理的概念,以及如何使用代理来改造我们的事务代码;将事务抽出来,放到代理类中,业务代码保持纯净来实现我们的事务控制;
    这一章我们来实践如果使用spring中aop来改造我们的代码;

    二、Aop的常用术语

    JoinPoint(连接点):被拦截到的点,在Spring中这些点都是方法;
    PointCut(切入点):是指对哪些JoinPoint进行拦截的定义
    Advice(通知/增强):拦截到JoinPoint之后,要做的事情就是通知;
    通知的类型有前置通知、后置通知、异常通知、最终通知和环绕通知;
    Target(目标对象):代理的目标对象;
    Weaving(织入):把增强应用到目标对象来创建新的代理对象的过程;
    Proxy(代理):一个类被Aop织入增强后,就产生一个增强的代理类;
    Aspect(切面):是切入点和通知的结合。

    三、代码演示

    为了更好的理解aop,我们写一个简单的示例来学习;

    3.1 创建项目并引入maven包

    选择创建maven项目

    引入maven包,如下:

        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.6.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.5</version>
            </dependency>
        </dependencies>
    

    3.2 编写目标对象

    创建一个模拟的service接口和实现:

    package org.study.service;
    public interface IAccountService {
        void getList();
        int getCount();
        void updateUserAccount(int id);
    }
    

    实现类如下:

    package org.study.service.impl;
    import org.study.service.IAccountService;
    public class AccountServiceImpl implements IAccountService {
        @Override
        public void getList() {
            System.out.println("getList 执行了...");
        }
    
        @Override
        public int getCount() {
            System.out.println("getCount 执行了...");
            return 0;
        }
        
        @Override
        public void updateUserAccount(int id) {
            System.out.println("updateUserAccount 执行了...");
        }
    }
    

    3.3 编写通知(advice)类

    我们的通知类是也是一个模拟类,用于增强方法,该类中我们写了五个方法,分别模拟前置通知、后置通知、异常通知、最终通知和环绕通知;
    代码如下:

    package org.study.util;
    import org.aspectj.lang.ProceedingJoinPoint;
    public class Logger {    
        public void beforePrintLog(){
            System.out.println("Logger.beforePrintLog...");
        }
    
        public void afterPrintLog(){
            System.out.println("Logger.afterPrintLog...");
        }
    
        public void throwingPrintLog(){
            System.out.println("Logger.throwingPrintLog...");
        }
    
        public void finallyPrintLog(){
            System.out.println("Logger.finallyPrintLog...");
        }
    
        /**
         * 环绕通知
         */
        public Object aroundPrintLog(ProceedingJoinPoint pjp) {
            try {
                Object returnVal;
                Object[] args = pjp.getArgs();
                System.out.println("Logger.前置...");
                returnVal = pjp.proceed(args);
                System.out.println("Logger.return...");
                return returnVal;
            } catch (Throwable throwable) {
                System.out.println("Logger.Exception...");
                throw new RuntimeException(throwable);
            } finally {
                System.out.println("Logger.finally...");
            }
        }
    }
    

    3.4 配置XML来实现方法增强

    接下来我们开始在xml文件中进行配置:
    配置的步骤如下:
    (1)配置目标对象
    (2)配置切面类
    (3)配置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
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!--配置目标对象-->
        <bean id="accountService" class="org.study.service.impl.AccountServiceImpl" >
        </bean>
        <!--配置切面类-->
        <bean id="logger" class="org.study.util.Logger">
        </bean>
        <aop:config>
            <!--定义切入点表达式-->
            <aop:pointcut expression=" execution(* org.study.service.*.*(..))" id="myPointCut"/>
            <aop:aspect id="aspect" ref="logger">
                <!--前置-->
                <aop:before method="beforePrintLog" pointcut-ref="myPointCut"/>
                <!--后置通知-->
                <aop:after-returning method="afterPrintLog" pointcut-ref="myPointCut"/>
                <!--异常通知-->
                <aop:after-throwing method="throwingPrintLog" pointcut-ref="myPointCut"/>
                <!--最终通知-->
                <aop:after method="finallyPrintLog" pointcut-ref="myPointCut"/>
    <!--            <aop:around method="aroundPrintLog" pointcut-ref="myPointCut"/>-->
            </aop:aspect>
        </aop:config>
    </beans>
    

    编写测试方法:

    package org.study;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.study.service.IAccountService;
    
    public class AccountServiceTest {
        public static void main(String[] args) {
            ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
            IAccountService accountService=context.getBean("accountService", IAccountService.class);
            int count= accountService.getCount();
        }
    }
    

    查看运行结果:

    3.5 环绕通知的配置

    通过上面的代码,我们可以发现,我们在配置xml文件时,注释掉了环绕通知,这一步我们把环绕通知的注释打开,运行一下测试类

    我们发现,环绕通知的结果和配置四种不同的通知结果一致。

    四、总结

    1、我们通过spring框架的aop很方便快捷地帮我们实现了代码的增强;
    2、通过aop我们可以把很多重复代码提取到公共类中,比如记录日志、事务控制等,这样业务代码会更清爽,便于阅读。

  • 相关阅读:
    React 组件生命周期
    React Ant Design Mobile 中 ListView 简单使用,搞懂每一行代码
    .net网站自动化部署-致两年前的遗留的问题
    【479】cross-entropy与softmax的求导
    【478】Victor Zhou深度学习链接
    网站高并发大流量访问的处理及解决方案
    年轻人的第一个 Docker 应用,大大提高生产力!
    Spring Boot 静态资源处理,妙!
    Spring 配置最好不要配置 xsd 版本号!
    自己动手实现一个简单的 IOC,牛皮!!
  • 原文地址:https://www.cnblogs.com/zqllove/p/13085973.html
Copyright © 2011-2022 走看看