zoukankan      html  css  js  c++  java
  • 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 {
    }

     

     

     

  • 相关阅读:
    eclipse中文乱码问题解决方案
    修改Tomcat的JDK目录
    Tomcat 5.5 修改服务器的侦听端口
    HTML DOM教程 27HTML DOM Button 对象
    HTML DOM教程 24HTML DOM Frameset 对象
    Navicat for MySQL v8.0.27 的注册码
    HTML DOM教程 25HTML DOM IFrame 对象
    Tomcat 5.5 的下载和安装
    android manifest相关属性
    ubuntu10.04 下 eclipse 小结
  • 原文地址:https://www.cnblogs.com/zhangcaihua/p/12930900.html
Copyright © 2011-2022 走看看