• Spring配置切面的几种方式


    1、实现MethodBeforeAdvice等接口

    pom.xml添加spring核心依赖:

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>

    在Spring中,org.springframework.aop包下有四个接口,分别是MethodBeforeAdvice(前置通知)、AfterReturningAdvice(后置通知)、MethodInterceptor(环绕通知)、ThrowsAdvice(异常通知),其中,前三个接口都有对应的实现方法,分别实现后就可以在对应的通知方法中添加功能,但是ThrowsAdvice异常通知没有实现方法,所以需要自定义一个方法,不过对方法名有规定,必须写成afterThrowing,代码如下:

    定义一个切面类UserServiceAdvice:

    public class UserServiceAspect implements MethodBeforeAdvice, AfterReturningAdvice,
            MethodInterceptor, ThrowsAdvice {
    
        /**
         * 后置通知
         * @param o
         * @param method
         * @param objects
         * @param o1
         * @throws Throwable
         */
        @Override
        public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
            System.out.println("后置通知");
        }
    
        /**
         * 前置通知
         * @param method
         * @param objects
         * @param o
         * @throws Throwable
         */
        @Override
        public void before(Method method, Object[] objects, Object o) throws Throwable {
            System.out.println("前置通知。。。");
        }
    
        @Override
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            System.out.println("环绕通知前。。。");
            Object returnVal = methodInvocation.proceed();
            System.out.println("环绕通知后。。。");
            return returnVal;
        }
    
        /**
         * 异常通知,参照MethodBeforeAdvice,
         * 该方法的方法名必须叫做afterThrowing,
         * method,args,target这三个参数可以省略,要么全部声明
         * Exception必须保留
         * @param e
         */
        public void afterThrowing(Exception e){
            System.out.println("产生了异常:"+e.getMessage());
        }
    }

    在resources目录下创建一个Spring配置文件applicationContext.xml:

    在这个配置文件中主要是做对bean的配置和对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">
    
        <!-- 目标对象 -->
        <bean id="userService" class="edu.nf.ch12.service.impl.UserServiceImpl" />
        <!-- 切面 -->
        <bean id="userServiceAspect" class="edu.nf.ch12.service.aspect.UserServiceAspect" />
        <!-- aop配置, -->
        <aop:config proxy-target-class="false">
            <!-- 配置切入点,使用aspectJ的切入点表达式,
             表达式语法:
             1、execution(访问修饰符 方法返回值 包名.类名.方法名(参数类型))
                execution是切入到方法级别的
             2、within(访问修饰符 方法返回值 包名.类名)
                within是切入到类级别的
             说明:访问修饰符可以省略,
             方法返回值、包名、类名、方法名、可以使用*号进行统配,
             方法参数可以指定参数的类型,也可以使用".."来标识任意类型和个数的参数
             例如:execution(* edu.nf.ch12.service.impl.*.*(..))
             表示edu.nf.ch12.service.impl包下的所有类,以及任意返回值类和任意参数类型和个数的方法都会匹配-->
            <aop:pointcut id="myPointcut" expression="execution(* edu.nf.ch12.service.impl.UserServiceImpl.say(..))"/>
            <!-- 配置通知器(Advisor),其实就是切面
             advice-ref引用上面定义的切面的id
             pointcut-ref引用上面定义的切入点的id-->
            <aop:advisor advice-ref="userServiceAspect" pointcut-ref="myPointcut"/>
            <!-- 当有多个切面,但是又不想共用一个切入点表达式的时候,那么使用pointcut属性来重新制定切入点表达式 -->
            <aop:advisor advice-ref="demoAspect" pointcut="execution(* edu.nf.ch12.service.impl.UserServiceImpl.run())"/>
        </aop:config>
    </beans>

    2、使用AspectJ配置,不实现任何接口

    (1)使用配置文件配置切面

    当使用AspectJ配置时,不需要实现任何接口,因为对这些通知的方法都是在配置文件中配置和绑定的。

    创建一个切面类:

    public class UserServiceAspect {
    
        /**
         * 前置通知
         * @param jp 连接点,通过这个连接点可以获取目标方法
         */
        public void before(JoinPoint jp){
            System.out.println("前置通知,目标方法参数:" + jp.getArgs()[0]);
        }
    
        /**
         * 环绕通知
         * @param pjp 连接点,可以获取目标方法参数以及方法信息以及调用目标方法等等
         */
        public Object around(ProceedingJoinPoint pjp) throws Throwable{
            System.out.println("环绕通知前。。。");
            //获取目标方法的的Method对象
            MethodSignature ms = (MethodSignature)pjp.getSignature();
            Method method = ms.getMethod();
            System.out.println("当前调用的目标方法:" + method.getName());
            //调用目标方法
            Object returnVal = pjp.proceed();
            System.out.println("环绕通知后。。。");
            return returnVal;
        }
    
        /**
         * 后置通知
         * @param returnVal 目标方法的返回值
         */
        public void afterReturning(String returnVal){
            System.out.println("后置通知,返回参数:" + returnVal);
        }
    
        /**
         * 异常通知
         * @param e 目标方法产生的异常对象
         */
        public void afterThrowing(Throwable e){
            System.out.println("异常通知,异常信息:" + e.getMessage());
        }
    
        /**
         * 最终通知
         */
        public void after(){
            System.out.println("最终通知");
        }
    }

    在resources目录中创建一个Spring配置文件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">
    
        <bean id="userService" class="edu.nf.ch13.service.impl.UserServiceImpl"/>
        <!-- 定义切面 -->
        <bean id="userServiceAspect" class="edu.nf.ch13.service.aspect.UserServiceAspect"/>
    
        <!-- 配置AOP,基于AspectJ -->
        <aop:config>
            <aop:pointcut id="myPointcut" expression="execution(* edu.nf.ch13.service.impl.UserServiceImpl.*(..))"/>
            <!-- 装配切面,ref引用上面配置的切面的id -->
            <aop:aspect ref="userServiceAspect">
                <!-- 装配通知,method对应通知的方法名,pointcut-ref引用上面定义的切入点的id
                 如果不同的通知想使用不同的切入点,那么使用pointcut属性进行自定义 -->
                <!-- 前置通知 -->
                <aop:before method="before" pointcut-ref="myPointcut"/>
                <!-- 环绕通知 -->
                <aop:around method="around" pointcut-ref="myPointcut"/>
                <!-- 后置通知,returning属性指定后置通知方法的参数名(参数名称要一致) -->
                <aop:after-returning method="afterReturning" pointcut-ref="myPointcut" returning="returnVal"/>
                <!-- 异常通知,throwing属性指定异常通知方法的参数名(名称要一致) -->
                <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" throwing="e"/>
                <!-- 最终通知 -->
                <aop:after method="after" pointcut-ref="myPointcut"/>
            </aop:aspect>
        </aop:config>
    </beans>

    (2)使用注解和配置类配置切面

    在上面的applicationContext.xml配置文件中,对基于AspectJ的aop配置完全可以使用注解来配置,

    在切面类中:

    /**
     * AspectJ提供了所有通知注解,这些注解都有一个value属性,
     * 属性指定的是@Pointcut注解所标注的方法名,即pointcut(),
     * 如:@Around("pointcut()")
     * 如果不同通知想使用不同的切入点那么可以直接在value属性中自定义
     * 如:@Before("execution(* edu.nf.ch14.service.impl.UserServiceImpl.say())")
     */
    @Component
    /**
     * @Aspect注解标识当前类为一个切面类
     */
    @Aspect
    public class UserServiceAspect extends AbstractAsPect {
    
        /**
         * 声明一个切入点,@Pointcut声明在一个方法上,在这里将这个方法放在了AbstractAspect这个类中
         */
    //    @Pointcut("execution(* edu.nf.ch15.service.impl.UserServiceImpl.*(..))")
    //    public void pointcut(){
    //
    //    }
    
        /**
         * 前置通知
         * @param jp 连接点,通过这个连接点可以获取目标方法
         * pointcut()指定的是切入点注解所标注的方法名
         * @Before注解的value属性指定的是切入点注解所标注的方法名,
         * 结果不同通知想使用不同的切入点
         */
        @Before("execution(* edu.nf.ch15.service.impl.UserServiceImpl.say())")
        public void before(JoinPoint jp){
            System.out.println("前置通知,目标方法参数:" + jp.getArgs()[0]);
        }
    
        /**
         * 环绕通知
         * @param pjp 连接点,可以获取目标方法参数以及方法信息以及调用目标方法等等
         */
        @Around("pointcut()")
        public Object around(ProceedingJoinPoint pjp) throws Throwable{
            System.out.println("环绕通知前。。。");
            //获取目标方法的的Method对象
            MethodSignature ms = (MethodSignature)pjp.getSignature();
            Method method = ms.getMethod();
            System.out.println("当前调用的目标方法:" + method.getName());
            //调用目标方法
            Object returnVal = pjp.proceed();
            System.out.println("环绕通知后。。。");
            return returnVal;
        }
    
        /**
         * 后置通知
         * @param returnVal 目标方法的返回值
         */
        @AfterReturning(value = "pointcut()", returning = "returnVal")
        public void afterReturning(String returnVal){
            System.out.println("后置通知,返回参数:" + returnVal);
        }
    
        /**
         * 异常通知
         * @param e 目标方法产生的异常对象
         */
        @AfterThrowing(value = "pointcut()", throwing = "e")
        public void afterThrowing(Throwable e){
            System.out.println("异常通知,异常信息:" + e.getMessage());
        }
    
        /**
         * 最终通知
         */
        @After("pointcut()")
        public void after(){
            System.out.println("最终通知");
        }
    }

    创建一个配置类,可以做到0配置,

    SpringConfig:

    @Configuration
    @ComponentScan("edu.nf.ch15")
    /**
     * 启用AspectJ注解处理器,等同于xml中的<aop:aspectj-autoproxy/>
     */
    @EnableAspectJAutoProxy
    public class SpringConfig {
    }

     

     

     

  • 相关阅读:
    Python3中的新特性(3)——代码迁移与2to3
    Python3中的新特性(1)——新的语言特性
    Python3中的新特性(2)——常见陷阱
    输入一行字符,统计其中有多少个单词,单词之间用空格分隔开
    scanf(),gets(),gechar()函数小结
    CI控制器调用内部方法并载入相应模板的做法
    script脚本中写不写$(document).ready(function() {});的区别
    CentOS系统时间与现在时间相差8小时解决方法
    Linux下MySQL慢查询分析mysqlsla安装使用
    导入 Mysql 示例数据库 employees
  • 原文地址:https://www.cnblogs.com/zhangcaihua/p/12930900.html
Copyright © 2020-2023  润新知