码迷,mamicode.com
首页 > 编程语言 > 详细

【Spring四】AOP之XML配置

时间:2015-07-21 18:51:12      阅读:137      评论:0      收藏:0      [点我收藏+]

标签:框架   spring   aop   

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)、当客户端调用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、在客户端,用代理对象调用方法的时候进去了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配置

标签:框架   spring   aop   

原文地址:http://blog.csdn.net/damogu_arthur/article/details/46988379

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!