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>



  • 相关阅读:
    Hadoop集群(三) Hbase搭建
    Hadoop集群(二) HDFS搭建
    Hadoop集群(一) Zookeeper搭建
    Redis Cluster 添加/删除 完整折腾步骤
    Redis Cluster在线迁移
    Hadoop分布式HA的安装部署
    Describe the difference between repeater, bridge and router.
    what is the “handover” and "soft handover" in mobile communication system?
    The main roles of LTE eNodeB.
    The architecture of LTE network.
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/6859674.html
Copyright © 2011-2022 走看看