天天看點

Spring的初體驗-3

一. Spring AOP 面向切面程式設計(也叫面向方面程式設計)

  1. AOP本質上就是一種代理模式

    Aspect Oriented Programming(AOP)是 Spring架構中的核心内容之一。本質上是一種代理模式——Spring AOP就是基于動态代理的。

Spring的初體驗-3

有了動态代理,Spring就可以對其管理的對象的業務邏輯處理流程進行幹預——Spring可以在處理流程中插一腳,幹點什麼事。

Spring的初體驗-3

可以幹點什麼呢?

分離業務代碼,提高程式的可重用性。

  1. AOP的應用場景和要解決的問題
Spring的初體驗-3

AOP的應用場景是互相獨立的各個類的方法中總存在着一些相同的業務代碼。這些相同的業務代碼由于是分布在不相幹的各個類中(類之間甚至沒有公共的接口),要想通過繼承關系(垂直方向的代碼複用)進行代碼複用比較困難。把重複的代碼封裝成公共的方法再調用又會造成對各個類的代碼侵入(增加了耦合度)。是以就希望能有一種方式可以把分布在不同類方法中的相同代碼段抽離出來複用,又不會對原來的各個類造成代碼的侵入。AOP應運而生。

  1. 使用AOP複用代碼
Spring的初體驗-3

AOP的方法就是利用動态代理,代理各目标對象,然後将各個被代理類方法中相同的代碼片段統一拿到代理類中。這樣就好像在各個并列的被代理對象中橫向切一刀,把公共的代碼切片拿出來放到代理類中統一處理——這是一種橫向的代碼複用方式。

  1. 具體概念可以參考​​這裡​​
  2. 代碼執行個體
  • ​​對面的男孩看過來​​
  • ​​對面的女孩看過來​​

二. Spring AOP的示例

  1. Spring中使用AOP涉及的jar包
aopalliance.jar
aspectjweaver-1.6.6.jar
spring-aspects-4.0.6.RELEASE.jar      
  1. Spring的配置檔案配置AOP
<?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.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <bean id="studentServiceAspect" class="com.bee.advice.StudentServiceAspect"></bean>
    
    <bean id="studentService" class="com.bee.service.impl.StudentServiceImpl"></bean>
    
    <aop:config>
        <aop:aspect id="studentServiceAspect" ref="studentServiceAspect">
            AOP隻能作用于方法,下邊的定義是用于比對方法的(包括傳回值,函數名,參數)。
            比對的方法就是StudentService接口中定義的抽象方法。
            <aop:pointcut expression="execution(* com.bee.service.*.*(..))" id="businessService"/>
            <aop:before method="doBefore" pointcut-ref="businessService"/>
            <aop:after method="doAfter" pointcut-ref="businessService"/>
            <aop:around method="doAround" pointcut-ref="businessService"/>
            <aop:after-returning method="doAfterReturning" pointcut-ref="businessService"/>
            <aop:after-throwing method="doAfterThrowing" pointcut-ref="businessService" throwing="ex"/>
        </aop:aspect> 
    </aop:config>
</beans>      
execution(  *     com.bee.service.   *    .     *        ( .. )    )      
  1. 定義被代理的對象(目标對象Target)
package com.bee.service;

public interface StudentService {
  void addStudent(String name);
}
------------------------------------------------------------------------
package com.bee.service.impl;

public class StudentServiceImpl implements StudentService{
  @Override
  public void addStudent(String name) {
    // System.out.println("開始添加學生"+name); 不使用AOP産生的代碼侵入
    System.out.println("添加學生"+name); //目标對象的業務邏輯
    System.out.println(1/0); //目标對象産生異常
    // System.out.println("完成學生"+name+"的添加"); 不使用AOP産生的代碼侵入
  }
}      
  1. 定義切面(Aspect)

    這裡定義的是橫向抽取出來的公共代碼。

package com.bee.advice;

public class StudentServiceAspect {

  public void doBefore(JoinPoint jp){
    System.out.println("類名:"+jp.getTarget().getClass().getName());
    System.out.println("方法名:"+jp.getSignature().getName());
    System.out.println("開始添加學生:"+jp.getArgs()[0]);
  }
  
  public void doAfter(JoinPoint jp){
    System.out.println("類名:"+jp.getTarget().getClass().getName());
    System.out.println("方法名:"+jp.getSignature().getName());
    System.out.println("學生添加完成:"+jp.getArgs()[0]);
  }
  
  public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
    System.out.println("添加學生前");
    Object retVal=pjp.proceed(); //執行目标對象比對的方法
    System.out.println(retVal);
    System.out.println("添加學生後");
    return retVal; //傳回目标對象比對方法的傳回值
  }
  
  public void doAfterReturning(JoinPoint jp){
    System.out.println("傳回通知");
  }
  
  public void doAfterThrowing(JoinPoint jp,Throwable ex){
    System.out.println("異常通知");
    System.out.println("異常資訊:"+ex.getMessage());
  }
}      
  1. 測試
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
StudentService studentService=(StudentService)ac.getBean("studentService");
studentService.addStudent("張麻子");