• 04-Spring中的AOP编程之基于xml开发


    AOP编程

    ​ AOP为Aspect Oriented Programming的缩写,意为:面向切面编程。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    ​ 学习AOP之后,可以在不修改源码的情况下,进行源码的增强业务,进行权限的校验,日志记录,性能监控,事务控制等。

    Spring底层的AOP原理

    • 动态代理(静态代理)

      • JDK动态代理: 面向接口的,只能对实现了接口的类产生代理
      • Cglib动态代理(类似于JavaSsit第三方代理技术):对没有实现接口的类产生代理对象(生成子类对象)
    • 类实现了接口,Spring就用JDK动态代理,没有实现接口的,用Cglib动态代理,Spring底层可以自动切换

    Spring的AOP开发入门(1)(基于XML开发)

    1. 引入基本开发包和AOP开发相关的包

    第一个aop联盟

    第二个aspectj的依赖

    第三个AOP核心包

    第四个Spring与aspects整合的包

    2. 引入xml配置约束文件

    写切面的约束:aspect.xml

    <?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"> 
        <!--切面编程配置-->
        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="p1" expression="execution(* com.yd.service.impl.UserServiceImpl.add(..))"/>
            <!--配置切面类-->
            <aop:aspect ref="myAspect">
                <aop:before method="log" pointcut-ref="p1"></aop:before>
            </aop:aspect>
        </aop:config>
    </beans>
    

    写spring扫描类文件,管理相关类的对象:spring.xml

    <?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
    
        <context:component-scan base-package="com.yd.service"></context:component-scan>
        <context:component-scan base-package="com.yd.aspect"></context:component-scan>
    
    </beans>
    

    3. 编写原本的代码(切入点)

    UserService:

    public interface UserService {
        //添加用户方法
        public void add();
    }
    

    接口的实现类UserServiceImpl:

    • 使用@Service将该类交由spring容器管理
    @Service
    public class UserServiceImpl implements UserService {
    
        @Override
        public void add(){
            System.out.println("添加用户信息...");
        }
    }
    

    4. 编写增强类(通知)

    • 使用@Component将该类交由spring容器管理
    @Component
    public class MyAspect {
        public void log(){
            System.out.println("添加日志");
        }
    }
    

    5. 运行测试代码

    public class Demo {
    
        @Test
        public void run(){
            //引入配置文件
            ApplicationContext ac = new ClassPathXmlApplicationContext( "spring.xml","aspect.xml");
            //从spring容器中获取对象
            UserService userService = (UserService)ac.getBean("userServiceImpl");
            //执行对象方法
            userService.add();
        }
    
    }
    

    运行结果:

    Spring的AOP开发入门(2)(基于XML开发)

    UserService:

    public interface UserService {
        public void add();
        public void delete();
        public String deleteReturn();
        public void deleteAround();
        public void update(String uname,int pwd);
        public String updateReturn(String uname,int pwd);
        public void selectException();
        public void selectFin();
    }
    

    实现类UserServiceImpl:

    @Service
    public class UserServiceImpl implements UserService {
    
        @Override
        public void add(){
            System.out.println("添加用户信息...");
        }
    
        @Override
        public void delete() {
            System.out.println("删除用户信息...");
        }
        @Override
        public String deleteReturn() {
            System.out.println("删除用户,有返回值...");
            return "123";
        }
        @Override
        public void deleteAround(){
            System.out.println("删除信息deleteAround...");
        }
    
        @Override
        public void update(String uname,int pwd) {
            System.out.println("uname:"+uname+" pwd:"+pwd);
        }
    
        @Override
        public String updateReturn(String uname,int pwd) {
            System.out.println("uname:"+uname+" pwd:"+pwd);
            return uname;
        }
    
        @Override
        public void selectException() {
            System.out.println("select异常。。。");
            System.out.println(1/0);
            System.out.println("select2。。。");
        }
    
        @Override
        public void selectFin() {
            System.out.println("select无异常。。。");
    
        }
    
    }
    

    增强类MyAspect:

    @Component
    public class MyAspect {
    
        public void check(){
            System.out.println("----之前校验身份");
        }
    
        public void back(){
            System.out.println("----之后增强");
        }
    
        /**
         * 接收原方法返回值的后置增强方法
         * @param obj 切入点的返回值
         */
        public void backReturn(Object obj){
            System.out.println("后置接收切入点返回值:"+obj);
        }
    
        /**
         * 环绕增强
         * @param point 连接点
         * @throws Throwable
         */
        public void around(ProceedingJoinPoint point) throws Throwable {
            System.out.println("----之前增强");
            //执行切入点的方法
            point.proceed();
            System.out.println("----之后增强");
        }
    
        /**
         * 环绕增强,接收切入点的传入的参数
         * @param point
         * @throws Throwable
         */
        public void aroundParam(ProceedingJoinPoint point)throws Throwable{
            System.out.println("---之前增强");
            //获取切入点的参数
            Object[] args = point.getArgs();
            point.proceed();
            System.out.println("---之后增强 切入点参数1:"+args[0]+" 参数2:"+args[1]);
        }
        /**
         * 环绕增强,接收切入点的传入的参数,切接收返回
         * @param point
         * @throws Throwable
         */
        public void aroundReturn(ProceedingJoinPoint point)throws Throwable{
            System.out.println("---之前增强");
            //获取切入点的参数
            Object[] args = point.getArgs();
            String str = (String)point.proceed();
            System.out.println("---之后增强 切入点参数1:"+args[0]+" 参数2:"+args[1]+" 返回值:"+str);
        }
    
        /**
         * 切入点有异常
         * @param e 异常
         */
        public void afterCatch(Exception e){
            System.out.println(e.getMessage());
            System.out.println("---捕获异常");
        }
    
        public void finallyDo(){
            System.out.println("finally,总会执行...");
        }
    }
    

    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">
        <!--切面编程配置-->
        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="p1" expression="execution(* com.yd.service.impl.UserServiceImpl.add(..))"/>
            <aop:pointcut id="p2" expression="execution(* com.yd.service.impl.UserServiceImpl.delete(..))"/>
            <aop:pointcut id="p3" expression="execution(* com.yd.service.impl.UserServiceImpl.deleteReturn(..))"/>
            <aop:pointcut id="p4" expression="execution(* com.yd.service.impl.UserServiceImpl.deleteAround(..))"/>
            <aop:pointcut id="p5" expression="execution(* com.yd.service.impl.UserServiceImpl.update(..))"/>
            <aop:pointcut id="p6" expression="execution(* com.yd.service.impl.UserServiceImpl.updateReturn(..))"/>
            <aop:pointcut id="p7" expression="execution(* com.yd.service.impl.UserServiceImpl.selectException(..))"/>
            <aop:pointcut id="p8" expression="execution(* com.yd.service.impl.UserServiceImpl.selectFin(..))"/>
    
    
    
            <!--配置切面类-->
            <aop:aspect ref="myAspect">
                <!-- 之前增强-->
                <aop:before method="check" pointcut-ref="p1"></aop:before>
                <!-- 之后增强-->
                <aop:after-returning method="back" pointcut-ref="p2"></aop:after-returning>
                <!-- 之后增强接收切入点返回值  obj:增强方法接收返回值的参数,必须与方法中参数名一致-->
                <aop:after-returning method="backReturn" pointcut-ref="p3" returning="obj"></aop:after-returning>
                <!-- 环绕增强-->
                <aop:around method="around" pointcut-ref="p4"></aop:around>
                <!-- 环绕增强,获取切入点传入的参数信息-->
                <aop:around method="aroundParam" pointcut-ref="p5"></aop:around>
                <!-- 环绕增强,获取切入点传入的参数信息,且有返回-->
                <aop:around method="aroundReturn" pointcut-ref="p6"></aop:around>
    
                <!-- 最终通知,有无异常都会执行,相当于finally-->
                <aop:after method="finallyDo" pointcut-ref="p7"></aop:after>
    
                <!-- 切入点有异常,后置增强捕获 throwing="e"异常参数,必须与方法中一致-->
                <aop:after-throwing method="afterCatch" pointcut-ref="p7" throwing="e"></aop:after-throwing>
    
                <aop:after method="finallyDo" pointcut-ref="p8"></aop:after>
            </aop:aspect>
        </aop:config>
    </beans>
    

    测试类:

    public class Demo {
    
        @Test
        public void run(){
            ApplicationContext ac = new ClassPathXmlApplicationContext( "spring.xml","aspect.xml");
            UserService userService = (UserService)ac.getBean("userServiceImpl");
            //userService.add();
            //userService.delete();
            //userService.deleteReturn();
            //userService.deleteAround();
            //userService.update("张三",1234);
            //userService.updateReturn("李四",121);
            //userService.selectException();
            userService.selectFin();
        }
    
    • 注意:最终通知after和后置异常通知after-throwing的顺序不同,打印结果顺序不同

    方式一:

    运行结果

    方式二:

    运行结果:

    切入点表达式语法

    基于execution的函数完成的

    语法

    • execution([访问修饰符] 方法返回值 包名.类名.方法名(参数))

    com.spring.service.UserServiceImpl.add(..) 一般情况最好将方法名写完整

    com.spring.service.UserServiceImpl.*(..) 开发中用的最多的是这种,对当前类下所有的方法做增强处理(场景:事务处理)

    com.spring.service.impl.save(..)

    com.spring.service.impl.*(..) 表示: com.spring.service.impl类下所有方法被增强

    * *.*service.impl.add(..)没有包可以用*代替

    * com.spring..(..)表示com.spring包下所有的类,所有方法都被增强

  • 相关阅读:
    python3+request接口自动化框架
    类型转换函数
    操作符重载(三)
    操作符重载(二)
    操作符重载(一)
    时间获取函数
    文件和目录
    Linux五种IO模型
    类中的函数重载
    系统调用IO和标准IO
  • 原文地址:https://www.cnblogs.com/soft-test/p/14905374.html
Copyright © 2020-2023  润新知