zoukankan      html  css  js  c++  java
  • 【Spring四】AOP之XML配置

    AOP:Aspect Oriented  Programming 面向切面编程

    面向切面编程的核心是动态代理设计模式。请先參见动态代理设计模式笔记。

    以Hibernate保存一个对象到数据库为例,因为保存数据时须要开启事务,利用面向切面编程思想,将事务的处理分离出来。当作一个切面来处理。

    jdk的动态代理的缺点:
       1、在拦截器中,切入点的推断是很复杂的
       2、尽管实现了切面与目标类的松耦合,可是在拦截器中还得实现结合过程

    一.springAOP的原理
    目标类:在目标类的方法调用的前后,我们须要增加自己的逻辑。
    切面:包括了全部的封装了自己的逻辑方法的类
    切入点:目标类里的须要增加额外逻辑的方法。
    通知:切面里的自己的封装自己的逻辑的方法;
    比方Hibernate中,目标类是XDaoImpl,切入点是XDao.save(xx)方法,通知是开启事务,以及commit,切面就是封装了开启事务和commit的类;即在save方法运行前。须要開始事务,运行后,须要提交事务!

       1、当启动spring容器的时候,
             <bean id="classDao" class="cn.itheima03.spring.aop.xml.ClassesDaoImpl"></bean>
             <bean id="myTransaction" class="cn.itheima03.spring.aop.xml.MyTransaction"></bean>

           把这两个bean创建对象了
       2、解析<aop:config>便签
            (1)、解析切入点表达式<aop:pointcut>。切入点针对的是函数,从函数进行切入,把表达式解除出来以后和              spring中的bean进行匹配
            (2)、假设匹配成功。则为该bean创建代理对象,在创建代理对象的过程中,把目标方法和通知结合在一起了
                   假设匹配不成功。则直接报错
            (3)、当client调用context.getBean时,获取到的
                                              (1)、假设该对象有代理对象,则返回代理对象
                                              (2)、假设该对象没有代理对象。则返回对象本身
        3、<aop:aspect>切面标签:
              在切面中配置各种通知,这些通知就我们自己须要额外运行的逻辑。有的逻辑在切入点函数运行前运行,用<aop:before>配置。有的须要在切入点方法运行之后运行,使用<aop:after>配置。还有的是运行切入点函数出现异常后运行,等的。。
    说明:
       spring容器内部会自己主动推断:
                  假设目标类实现了接口。则採用jdkproxy
                  假设目标类没有实现接口,则採用cglibproxy

    二.关于通知(通知就是切面里的方法,又称Advive,是在方法运行前和后须要运行的自己的代码)
    前置通知:
       1、在目标方法之前运行
       2、不管目标方法遇到异常都运行
    后置通知:
       1、在目标方法之后运行
       2、假设目标方法遇到异常,则不运行
       3、能够获取连接点的一些信息
    终于通知:
       1、相当于finally
       2、不管目标方法是否遇到异常,都运行

    异常通知
       1、获取目标方法抛出的异常信息
       2、throwing參数的配置才干获取信息

    围绕通知
       相当于jdkproxy的invoke方法

    三.以下使用Spring的AOP来处理Hibernate保存对象。

    1.配置文件:applicationContext.xml
    <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的配置 -->
         <bean id="classDao" class="cn.itheima03.spring.aop.xml.ClassesDaoImpl" ></bean>
         <bean id="myTransaction" class="cn.itheima03.spring.aop.xml.MyTransaction" ></bean>

         <aop:config >
               <!-- 切入点表达式 expression切入点表达式 id 唯一标示 -->
               <aop:pointcut
                   expression="execution(* cn.itheima03.spring.aop.xml.ClassesDaoImpl.*(..))"
                   id= "perform" />

               <!-- ref 引向切面 切面里包括各种各样的通知,这些通知都是我们自己想要额外实现的东西,比方开启事务等。。-->

               <aop:aspect ref= "myTransaction">
                   <!-- 方法运行之前运行 -->
                   <aop:before method= "beginTransaction" pointcut-ref="perform" />

                   <!-- 后置通知 returning 返回值  要与方法中的參数的名字相相应 -->
                   <aop:after-returning method= "commit"   pointcut-ref="perform" returning="val" />

                   <!-- 终于通知 不管目标方法是否有异常。都运行 -->
                   <aop:after method= "finnalyMethod" pointcut-ref="perform" />

                   <!-- 异常通知 throwing 获取目标方法抛出的异常信息 -->
                   <aop:after-throwing method= "throwingMethod"  pointcut-ref="perform" throwing="ex" />

                   <!-- 相当于 代理中invoke 方法,能够控制切入点的运行 -->
                   <aop:around method= "aroundMethod" pointcut-ref="perform" />

               </aop:aspect>
         </aop:config >
    </beans>

    关于切入点表达式:切入点表达式匹配的是方法。一个方法的完整声明为:
    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
              throws-pattern?)
    

    问号代表可有可无,没有问号代表一定要有!

    以下是一个方法完整声明的演示样例:
    切入点表达式演示样例:
    • execution(public * *(..))  全部的公共方法
    • execution(* set*(..))  以set开头的随意方法
    • execution(* com.xyz.service.AccountService.*(..))com.xyz.service.AccountService类里的全部的方法
    • execution(* com.xyz.service.*.*(..)) com.xyz.service包下的全部类的全部的方法
    • execution(* com.xyz.service..*.*(..)) com.xyz.service包及子包中全部的类的全部的方法
    • execution(* cn.itheima03.spring..*.*(String,*,Integer))
    • execution(* cn.itheima03.*.*.spring.*..*.*(..))  參数..代表随意类型的随意參数,參数能够是0个
             如cn.itheima03.a.b.spring.c.d.A.a()能匹配最后一个表达式。


    2.java代码:

    public interface ClassesDao {
         public void saveClasses(Classes classes);
         
         public void updateClasses(Classes classes);
         
         public List<Classes> getClasses();
    }
    ===========================================
    public class ClassesDaoImpl extends HibernateUtils{

         public String saveClasses(Classes classes) {
               int a = 1/0;
               sessionFactory.getCurrentSession().save(classes);
               return "aaaa" ;
         }

         public List<Classes> getClasses() {
               return sessionFactory .getCurrentSession().createQuery("from Classes").list();
         }

         public void updateClasses(Classes classes) {
               sessionFactory.getCurrentSession().update(classes);
         }

    }
    ===========================================
    public class HibernateUtils {
         public static SessionFactory sessionFactory;
         static{
              Configuration configuration = new Configuration();
              configuration.configure();
               sessionFactory = configuration.buildSessionFactory();
         }
    }
    ===========================================
    public class MyTransaction extends HibernateUtils{
         private Transaction transaction;
         /**
          * 前置通知
          *    JoinPoint 可以调用该API得到连接点的一些信息
          */
         public void beginTransaction(JoinPoint joinPoint){
              System. out.println(joinPoint.getSignature().getName());
               this.transaction = sessionFactory.getCurrentSession().beginTransaction();
         }
         
         /**
          * 后置通知
          *   1、获取目标方法的返回值
          */
         public void commit(Object val){
              System. out.println(val);
               this.transaction .commit();
         }
         
         /**
          * 终于通知
          */
         public void finnalyMethod(){
              System. out.println("finally method" );
         }
         
         /**
          * 异常通知
          */
         public void throwingMethod(Throwable ex){
               /**
               * 输出目标方法的异常信息
               */
              System. out.println(ex.getMessage());
         }
         
         /**
          * 围绕通知
          *    1、假设不运行joinPoint.proceed();。目标方法是不运行的
          *    2、在目标方法运行的上下文加入内容
          */
         public void aroundMethod(ProceedingJoinPoint joinPoint){
               try {
                  System. out.println("aaaa" );
                  joinPoint. proceed();//运行目标方法
                  System. out.println("bbbb" );
              } catch (Throwable e) {
                  e.printStackTrace();
              }
         }
    }
    ===========================================
    /**
     * 注意的点
     *    1、代理对象的方法体的内容就是拦截器 中invoke方法体的内容
     *    2、在client,用代理对象调用方法的时候进去了invoke方法
     */
    public class ClassesDaoTest {
         @Test
         public void testSaveClasses(){
              ApplicationContext context = new ClassPathXmlApplicationContext("cn/itheima03/spring/aop/xml/applicationContext.xml" );
              ClassesDaoImpl classesDao = (ClassesDaoImpl)context.getBean("classDao" );
              Classes classes = new Classes();
              classes.setCname( "afds");
              classesDao.saveClasses(classes);
         }
    }


    四.多切面的样例

    假如查看工资须要经过日志管理,安全管理,权限管理后才干查看工资。

    目标类:查看工资的类
    切面:日志管理,安全管理。权限管理
    切入点:查看工资的方法

    1.java代码:
    /**
     * 切面
     * 日志管理
     */
    public class Logger {
         public void interceptor() {
              System. out.println("logging" );
         }
    }
    ===========================================
    /**
     * 安全管理
     */
    public class Security {
         public void interceptor() {
              System. out.println("security" );
         }
    }
    ===========================================
    /**
     * 权限管理
     */
    public class Privilege{
         
         private String access;

         public String getAccess() {
               return access ;
         }

         public void setAccess(String access) {
               this.access = access;
         }

         public void interceptor(ProceedingJoinPoint joinPoint) {
               if("admin" .equals(this.access)){
                   try {
                       joinPoint.proceed();
                  } catch (Throwable e) {
                       e.printStackTrace();
                  }
              } else{
                  System. out.println("对不起,没有权限查看...." );
              }
         }
    }
    ===========================================
    /**
     * 目标类
     */
    public class SalaryManagerImpl implements SalaryManager{

         @Override
         public void showSalary() {
              System. out.println("正在查看工资" );
         }
         
    }
    ===========================================
    public class SalaryTest {
         @Test
         public void test(){
              ApplicationContext context= new ClassPathXmlApplicationContext("cn/itheima03/spring/aop/multiaspect/applicationContext.xml" );
              SalaryManager salarmManager=(SalaryManager) context.getBean("salaryManager" );
              salarmManager.showSalary();
         }
    }
    ===========================================

    2.配置文件:
    <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" >

         <!--目标类, 切面类,aop  -->

         <bean id="salaryManager" class="cn.itheima03.spring.aop.multiaspect.SalaryManagerImpl" ></bean>
         
         <bean id="logger" class="cn.itheima03.spring.aop.multiaspect.Logger" ></bean>
         <bean id="security" class="cn.itheima03.spring.aop.multiaspect.Security" ></bean>
         <bean id="privilege" class="cn.itheima03.spring.aop.multiaspect.Privilege" >
               <property name= "access" value="admin" ></property>
         </bean >
         
         <aop:config >
               <!--切入点  -->
               <aop:pointcut expression="execution(* cn.itheima03.spring.aop.multiaspect.SalaryManagerImpl.*(..))" id ="sm"/>
               <!-- 切面 -->
               <aop:aspect ref= "logger">
                   <aop:before method= "interceptor" pointcut-ref="sm" />
               </aop:aspect>
              
               <aop:aspect ref= "security">
                   <aop:before method= "interceptor" pointcut-ref="sm" />
               </aop:aspect>
              
               <aop:aspect ref= "privilege">
                   <!--围绕切入点  -->
                   <aop:around method= "interceptor" pointcut-ref="sm" />
               </aop:aspect>
         </aop:config >
    </beans>



  • 相关阅读:
    Linux上的文件管理类命令都有哪些,其常用的使用方法及其相关示例演示
    总结软连接和硬连接区别,并用实例操作说明
    描述文件的元数据信息有哪些,分别表示什么含义,如何查看?如何修改文件的时间戳信息?
    Git Shell push_code 脚本
    YDD的铁皮锅——C/C++内存概念
    Linux Shell 常见用法及问题
    MFC 设置鼠标样式(SetSystemCursor函数问题)
    Qt QTableView自定义列表(插入图片)
    Github libinjection库研究总结
    Windows/Linux:VMware虚拟机用内网IP通讯
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/6859674.html
Copyright © 2011-2022 走看看