zoukankan      html  css  js  c++  java
  • spring-AOP(面向切面编程)-xml方式配置

    AOP是针对面向对象编程的一种补充,有时使用面向对象不能很好完成一些额外的功能业务时,可以采用AOP来进行补充。

    AOP术语:

    1. 切面(Aspect)

      切面是用于编写切面逻辑的一个类,这个类很类似于JDK动态代理中的回调处理器或者cglib中的方法拦截器,主要就是将需要增强目标对象的功能代码编写在这个类中,而这些功能增强的代码就是切面逻辑。

    2. 切入点(Pointcut)

      切入点类似一个切入的坐标,目的就是要找到目标对象的哪些方法。

      通常切入点都是以一种表达式的形式来描述

    3. 通知/增强(Advice)

      通知就是切面中具体的增强逻辑,总共分为五种:

      1)前置通知(在目标方法调用之前执行)

      2)后置通知(在目标方法正确返回之后执行)

      3)环绕通知(在目标方法调用前后执行)

      4)异常通知(当目标方法抛出异常时执行,并且不会执行后置通知)

      5)最终通知(不管目标方法有无异常都会执行)

    4. 连接点(Joinpoint)

      目标对象的方法就称之为连接点,一个切入点可以对应目标对象的的多个连接点。

    5. 代理(Proxy)

      在运行时动态创建的对象,称之为代理对象,负责调用目标对象的方法,并执行增强功能

    6. 目标(Target)

      被代理的对象就是目标对象

    7. 织入(Weaver)

      将切面中的通知应用到目标对象上并且产生代理的过程称之为织入。

      因此通常描述为“将通知织入到具体的目标”。


    项目结构:

    代码示例:

    applicationContext.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">
    
        <!-- 装备UserServiceImpl -->
        <bean id="userService" class="edu.nf.ch11.service.impl.UserServiceImpl"/>
    
        <!-- 装配自定义的切面-->
        <bean id="userServiceAspect" class="edu.nf.ch11.service.aspect.UserServiceAspect"/>
    
        <!-- 配置AOP, proxy-target-class用于设置是否强制使用cglib进行动态代理
             true表示强制使用,false则表示spring会根据目标对象有无实现接口来决定
             使用jdk动态代理还是cglib代理。默认值就是false-->
        <aop:config>
            <!-- 配置切入点,id属性给切入点定义一个唯一标识,expression用于编写切入点表达式-->
            <!-- execution表达式的使用:切入范围是在方法级别-->
            <!-- 表达式语法[访问修饰符] 返回值类型 [完整类名].方法名(参数)-->
            <!-- *号表示通配所有,方法的参数可以使用".."来代表任意个数和类型的参数-->
            <aop:pointcut id="myCut" expression="execution(* edu.nf.ch11.service.*.*(..))"/>
    
            <!-- within表达式的使用:切入范围是在类级别-->
            <!--<aop:pointcut id="myCut" expression="within(edu.nf.ch11.service.impl.*)"/>-->
    
            <!-- 引用上面装配的切面类的id -->
            <aop:aspect ref="userServiceAspect">
                <!-- 配置具体的通知方法,method指定通知的方法名
                pointcut-ref引用上面定的切入点的id,也可以通过pointcut来编写相应的切入点表达式 -->
                <!-- 前置通知 -->
                <aop:before method="before" pointcut-ref="myCut"/>
                <!-- 环绕通知-->
                <aop:around method="around" pointcut-ref="myCut"/>
                <!-- 后置通知,returning指定后置通知的参数名,用于获取目标方法的返回值-->
                <aop:after-returning method="afterReturn" pointcut-ref="myCut" returning="returnVal"/>
                <!-- 异常通知,如果要获取目标方法抛出的异常对象,需要指定throwing属性,value对应异常通知的参数名-->
                <aop:after-throwing method="throwAdvice" pointcut-ref="myCut" throwing="e"/>
                <!-- 最终通知-->
                <aop:after method="after" pointcut-ref="myCut"/>
            </aop:aspect>
    
        </aop:config>
    
    </beans>

    切面(增强)类:

    package edu.nf.ch11.service.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.reflect.MethodSignature;
    
    import javax.xml.crypto.dsig.SignatureMethod;
    
    /**
     * @author wangl
     * @date 2018/10/23
     * 编写一个UserService的切面
     * 在切面中编写的方法都称之为通知或者是增强
     * 在AOP当中,通知有五种类型
     * 1. 前置通知
     * 2. 后置通知
     * 3. 环绕通知
     * 4. 最终通知
     * 5. 异常通知
     * 在一个切面中,任何一种类型的通知都可以定义多个,当有多个通知存在的时候
     * 就会形成一个通知栈
     */
    public class UserServiceAspect {
    
        /**
         * 前置通知
         * 在执行目标方法之前执行,拦截目标方法的参数
         * 可以通过JoinPoint获得目标方法的参数信息
         */
        public void before(JoinPoint joinPoint){
            System.out.println("前置通知...");
            //通过连接点获得目标对象
            //joinPoint.getTarget();
            //获取目标方法的参数信息
            Object[] params = joinPoint.getArgs();
            for (Object param : params) {
                System.out.println(param);
            }
        }
    
        /**
         * 后置通知
         * 在目标方法执行完并且return之后执行
         */
        public void afterReturn(String returnVal){
            System.out.println("后置通知..."+returnVal);
        }
    
        /**
         * 环绕通知
         * @param pjp 连接点处理器,由它负责调用目标对象的具体方法
         *
         */
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("环绕通知前...");
            //调用目标对象的方法
            Object returnVal = pjp.proceed();
            //获取目标方法的参数
            System.out.println(pjp.getArgs()[0]);
            //通过MethodSignature获取连接点方法信息
            MethodSignature ms = (MethodSignature)pjp.getSignature();
            //获取正在调用的目标方法
            System.out.println(ms.getMethod().getName());
            //获取目标方法的返回类型
            System.out.println(ms.getReturnType());
            System.out.println("环绕通知后...");
            return returnVal;
        }
    
        /**
         * 异常通知
         * @param e 获取目标方法抛出的异常对象
         */
        public void throwAdvice(Throwable e){
            System.out.println("异常通知..."+e.getMessage());
        }
    
        /**
         * 最终通知
         */
        public void after(){
            System.out.println("最终通知...");
        }
    }

     UserService接口:

    package edu.nf.ch11.service;
    
    /**
     * @author wangl
     * @date 2018/10/23
     */
    public interface UserService {
    
        /**
         * 添加用户
         */
        void addUser();
    
        /**
         * 删除用户
         * @param uid
         */
        void deleteUser(String uid);
    
        /**
         * 查询用户
         * @param uid
         * @return
         */
        String getUserNameById(String uid);
    }

    UserServiceImpl实现类:

    package edu.nf.ch11.service.impl;
    
    import edu.nf.ch11.service.UserService;
    
    /**
     * @author wangl
     * @date 2018/10/23
     * 目标对象(被代理的对象)
     * Spring的AOP中需要代理的所有目标对象都应该归纳在ioc容器中管理
     */
    public class UserServiceImpl implements UserService {
    
        @Override
        public void addUser() {
            System.out.println("保存用户信息");
        }
    
        @Override
        public void deleteUser(String uid) {
            System.out.println("删除用户,ID:" + uid);
        }
    
        @Override
        public String getUserNameById(String uid) {
            System.out.println("根据ID查询用户名");
            //System.out.println(10/0);
            return "user1";
        }
    }

    程序测试类:

    package edu.nf.ch11.test;
    
    import edu.nf.ch11.service.UserService;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * @author wangl
     * @date 2018/10/23
     */
    public class UserServiceAspectTest {
    
        @Test
        public void testAddUser(){
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            //这里从容器中获取的对象是一个代理对象
            UserService service = context.getBean("userService", UserService.class);
            //service.addUser();
            //System.out.println("----------------------");
            //service.deleteUser("10001");
            //System.out.println("----------------------");
            service.getUserNameById("10001");
        }
    }

     运行结果

  • 相关阅读:
    PhpStorm 常用快捷键和配置+关闭快捷键ctrl+alt+方向键旋转屏幕+快速复制一行快捷键恢复
    WP七牛云插件详解
    注册表删除键值时拒绝访问
    删除注册表子项清除u盘使用痕迹
    一件代发发货人怎么写?淘宝代理发货流程
    联动设置
    使用vue实现行列转换的一种方法。
    从后端到前端之Vue(五)小试路由
    从后端到前端之Vue(四)小试牛刀——真实项目的应用(树、tab、数据列表和分页)
    从后端到前端之Vue(三)小结以及一颗真实的大树
  • 原文地址:https://www.cnblogs.com/hhmm99/p/9835791.html
Copyright © 2011-2022 走看看