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>


【Spring四】AOP之XML配置的更多相关文章

  1. spring中aop以xml配置方式

    1 引jar包 springAOP\aopalliance.jar springAOP\aspectjrt.jar springAOP\aspectjweaver.jar springAOP\spri ...

  2. Spring中 aop的 xml配置(简单示例)

    示例: aop,即面向切面编程,面向切面编程的目标就是分离关注点. 比如:小明(一位孩子)想吃苹果,首先得要有苹果,其次才能吃.那么妈妈负责去买水果,孩子负责吃,这样,既分离了关注点,也减低了代码的复 ...

  3. Spring的配置文件ApplicationContext.xml配置头文件解析

    Spring的配置文件ApplicationContext.xml配置头文件解析 原创 2016年12月16日 14:22:43 标签: spring配置文件 5446 spring中的applica ...

  4. spring之aop概念和配置

    面向切面的一些概念: 简单说: 连接点就一些方法,在这些方法基础上需要额外的一些业务需求处理. 切入点就是方法所代表的功能点组合起来的功能需求. 通知就是那些额外的操作. 织入就是使用代理实现整个切入 ...

  5. Spring装配Bean---使用xml配置

    声明Bean Spring配置文件的根元素是<beans>. 在<beans>元素内,你可以放所有的Spring配置信息,包括<bean>元素的声明. 除了Bean ...

  6. 一步一步深入spring(6)--使用基于XML配置的spring实现的AOP

    上节我们提到了使用基于注解实现的AOP,这节我们将用基于xml配置的方式来实现的AOP. 1.首先建立一个类,作为切面类,这个类主要用来实现注解中各种通知要实现的方法. package com.yan ...

  7. Spring之AOP在XML中的配置方法

    AOP 即 Aspect Oriental Program 面向切面编程 先来一个栗子: <aop:config> <aop:pointcut id="loggerCutp ...

  8. Spring AOP-xml配置

    在spring AOP(一)中介绍了AOP的基本概念和几个术语,现在学习一下在XML中如何配置AOP. 在XML中AOP的配置元素有以下几种: AOP配置元素 描述 <aop:config> ...

  9. Spring AOP之xml 配置实现

    首先这个配置模式估计现在已经不用了,因为我在我们公司的项目里面并没有看到这么配置AOP相关的东西.不过,这个就和学习spring的控制反转(IOC)和依赖注入(DI)一样,刚刚开始的时候,都是从简单的 ...

随机推荐

  1. Android 简单的语音播报

    不解释快上车 Main.class package com.example.myapp; import android.app.AlertDialog;import android.os.Bundle ...

  2. 安卓TV盒子常见问题以及解决方法

    1.为什么requestfocus无效 原因:requestfocus不支持在Touch模式下的Focus; 解法方案:再加一个requestFocusFromTouch函数. 2.摄像头打开问题,调 ...

  3. org.springframework.data.repository.config.RepositoryConfigurationSource.getAttribute(Ljava/lang/String;)Ljava/util/Optional;

    升级springboot到2.0时,碰到了一大堆问题,上面异常原因是jar版本冲突了,有的模块忘记更新版本了,统一一下版本就可以了

  4. 「 HDU P2089 」 不要62

    和 HDOJ 3555 一样啊,只不过需要多判断个 ‘4’ 我有写 3555 直接去看那篇吧 这里只放代码 #include <iostream> #include <cstring ...

  5. Window下的———TOMCAT环境的配置

    1. 先去官方网站下载需要的猫(tomcat) http://tomcat.apache.org/ 2.下载好包,然后解压出来,放在你需要的位置上 3.去到配环境变量的地方,进行相应的环境配置     ...

  6. mysql运维常用

    一.用户授权 用户授权主要指: 1.可以限制用户访问那些库.表 2.可以限制用户对库.表执行select.create.delete.alter.drop等操作 3.可以限制用户登陆的IP.IP段.或 ...

  7. PHP+Python,轻量维护超轻松

    window下安装Python 直接去Python官网下载msi安装程序安装即可(选择自定义安装才能修改程序安装路径哦) widows下Python的数据库访问模块PyMysql的安装 1.open ...

  8. BZOJ 4919 [Lydsy1706月赛]大根堆 (SRM08 T3)

    [题解] 求一个序列的LIS有一个二分做法是这样的:f[i]表示长度为i的上升序列中最后一个数最小可以是多少,每次二分大于等于当前数字x的f[j],把f[j]修改为x:如果找不到这样的f[j],那就把 ...

  9. 洛谷 3178 [HAOI2015]树上操作

    [题解] 就是个树链剖分的模板题. #include<cstdio> #include<algorithm> #include<cstring> #define L ...

  10. 51NOD 1277 字符串中的最大值(KMP)

    >>点击进入原题测试<< 思路:用KMP优化的暴力写了一遍,超时!没有充分利用KMP中next数组的性质. 首先这个题是肯定要用到KMP算法的,然后会有一个next[]数组. ...