zoukankan      html  css  js  c++  java
  • Spring AOP之xml 配置实现

    首先这个配置模式估计现在已经不用了,因为我在我们公司的项目里面并没有看到这么配置AOP相关的东西。不过,这个就和学习spring的控制反转(IOC)和依赖注入(DI)一样,刚刚开始的时候,都是从简单的xml配置学起、然后再进一步简化:最开始也是在xml文件里面配置很多的bean,每个model都得配置一个bean标签,直到后来的只要一句话
    <context:component-scan base-package="com.lxk.hello" />;
    就可以搞定spring的依赖注入,也就是使用注解相关的配置了。
    这个AOP配置也是这么个道理。所以先从这个麻烦但是基础的配置模式看起。好理解这个AOP。

    对很多相同的操作提取到切面上去操作。这个只是把切面内部的方法写好,下面的配置文件说明这个切面切哪里也就是切入点在哪,怎么切,是前置,环绕,后置,还是异常等等。

    package com.lxk.spring.aop;
     
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
     
    import java.util.ArrayList;
    import java.util.List;
     
    /**
     * 切面(spring aop 就不需要拦截器啦)
     * (模拟hibernate里面保存数据要打开事物,然后各种增删改之后,再提交事物。)
     */
    public class Transaction {
     
        public void beginTransaction() {//前置通知
            //打开事物
            System.out.println("begin Transaction");
        }
     
        /**
         * @param joinPoint 通过joinPoint可以得到目标类和目标方法的一些信息
         * @param val       目标方法的返回值
         *                  和<aop:after-returning returning="val"/>中returning的值保质一致
         */
        public void commit(JoinPoint joinPoint, Object val) {//后置通知
            String methodName = joinPoint.getSignature().getName();
            System.out.println(methodName);
            System.out.println(joinPoint.getTarget().getClass().getName());
            //提交事物
            System.out.println("commit");
            List<Person> personList = (ArrayList<Person>) val;
            for (Person person : personList) {
                System.out.println(person.getPname());
            }
        }
     
        public void finalMethod() {
            System.out.println("最终通知");
        }
     
        public void aroundMethod(ProceedingJoinPoint joinPoint) {//环绕通知
            try {
                System.out.println("around method");
                joinPoint.proceed();//调用目标类的目标方法
            } catch (Throwable e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
     
        /**
         * 异常通知
         */
        public void throwingMethod(Throwable except) {
            System.out.println(except.getMessage());
        }
    }

    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-2.5.xsd
               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
        <!-- 
            1、目标类
            2、切面
            3、进行aop的配置
            (目标接口没有:因为引入到容器是为了实例化对象,接口是不能实现对象的。)
            (也没有拦截器的引入,有的只是aop的配置,如上的3、)
         -->
        <!-- 目标类 -->
        <bean id="personDao" class="com.lxk.spring.aop.PersonDaoImpl"/>
        <!-- 切面的声明 -->
        <bean id="transaction" class="com.lxk.spring.aop.Transaction"/>
        <!-- aop配置 -->
        <aop:config>
            <!--
                配置aop的切入点
                  id 是切入点的标识
                  expression 为切入点的表达式
                     execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
                        throws-pattern?)
                     modifiers-pattern  修饰符  可选  public private protected
                     ret-type-pattern  返回类型  必选  *  代表任意类型
                     declaring-type-pattern  方法的声明类型
                     name-patterm  方法名称类型
                         set*  以set开头的所有的方法名称
                         update*  以update开头的所有的方法名称
                     param-pattern  参数匹配
                         (..)  任意多个参数,每个参数任意多个类型
                         (*,String) 两个参数  第一个是任意类型,第二个是String
                         (String,*,Integer) 三个参数,第一个是String类型,第二个是任意类型,第三个是Integer类型
                        throws-pattern  异常的匹配模式
                 例子:
                   execution(* cn.itcast.spring.aop.xml.AService.*(..));
                      cn.itcast.spring.aop.xml.AService下的所有的方法
                   execution(public * cn.itcast.oa..*.*(..))
                       返回值为任意类型,修饰符为public,在cn.itcast.oa包及子包下的所有的类的所有的方法
                   exectuion(* cn.itcast.oa..*.update*(*,String))
                       返回值是任意类型,在cn.itcast.oa包及子包下所有的以update开头的参数为两个,第一个为任意类型
                       第二个为String类型的所有类的所有的方法
             -->
            <aop:pointcut expression="execution(* com.lxk.spring.aop.PersonDaoImpl.*(..))" id="perform"/>
            <!-- 配置切面(切面里面配置通知)—— ref 指向声明切面的类 -->
            <aop:aspect ref="transaction">
                <!-- 前置通知pointcut-ref 引用一个切入点 -->
                <aop:before method="beginTransaction" pointcut-ref="perform"/>
     
                <!--
                    后置通知
                       *  returning 目标方法的返回值
                       *  如果目标方法中有可能存在异常,异常确实发生了,这个时候,后置通知将不再执行
                 -->
     
                <!--<aop:after-returning method="commit" pointcut-ref="perform" returning="val"/>-->
     
                <!--
                    最终通知
                       *   不能得到目标方法的返回值
                       *   无论目标方法是否有异常,最终通知都将执行
                       *   资源的关闭、连接的释放写在最终通知里
                 -->
                <!--<aop:after pointcut-ref="perform" method="finalMethod"/>-->
     
                <!--
                        环绕通知
                           *  ProceedingJoinPoint的proceed方法就是目标对象的目标方法
                           *  环绕通知可以控制目标对象目标方法执行
                 -->
                <!--
                <aop:around method="aroundMethod" pointcut-ref="perform"/>
                 -->
                <!--
                        异常通知
                          在异常通知中获取目标方法抛出的异常
                 -->
                <!--<aop:after-throwing method="throwingMethod" pointcut-ref="perform" throwing="except"/>-->
            </aop:aspect>
        </aop:config>
    </beans>

    pointcut-ref设置切入点,也就是被选中的bean里面的方法执行的时候,就可以执行对应的切面的方法啦。

    也就是说,什么样的地方,会执行切面内部的代码操作。这里设置的是这个impl类里面的所有方法被调用的时候,就会执行切面的方法。

    下面有before after around 等等几种类型的切面方法,后面的method 指出这个前置通知还是后置通知,还是什么通知执行的方法的名称。对应于切面类里面的方法。这个是必须存在的,不然关联不到,那就不行啦。

    实际开发用的不是这么个配置姿势,实际开发配置页和spring注解实现一样,也就一两行的配置。

    Spring AOP 中的 execution切入点指示符。执行表达式格式和实际代码对照,以及参数的理解。

    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)

     

    ?,问号表示可选项。可填可不填。declaring-type是方法全名,只到类,不含方法名,具体就是类路径。看上面的图的对应关系可知。

  • 相关阅读:
    String和stringbuffer
    项目中Orcale存储过程优化记录
    大数据项目中的Oracle查询优化
    洛谷P3402 可持久化并查集
    Gym
    CodeForces
    Gym
    Gym
    UVA
    Kattis
  • 原文地址:https://www.cnblogs.com/zhaoyibing/p/9516343.html
Copyright © 2011-2022 走看看