Spring框架學習的第三天

代理模式

代理模式是常用的Java 設計模式,它的特徵是代理類與委託類有同樣的接口,代理類主要負責爲委託類預處理消息、過濾消息、把消息轉發給委託類,以及事後處理消息等。代理類與委託類之間通常會存在關聯關係,一個代理類的對象與一個委託類的對象關聯,代理類的對象本身並不真正實現服務,而是通過調用委託類的對象的相關方法,來提供特定的服務。

  1. 注意:
    委託類對象就是我們後面說到的 目標對象(需要【被】代理的對象)
    代理類對象就是我們後面說到的 代理對象(目標對象就是需要這個對象做爲代理)
  2. 按照代理類的創建時期,代理類可分爲兩種。
    靜態代理類:
    由程序員創建或由特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。
    動態代理類:在程序運行時,運用反射機制動態創建而成。

靜態代理

例如:
接口:HelloService
委託類:HelloServiceImpl
代理類:HelloServiceProxy

public interface HelloService{
  public String echo(String msg);
  public Date getTime();
}

public class HelloServiceImpl implements HelloService{
  public String echo(String msg){
    return "echo:"+msg;
  }
  public Date getTime(){
   return new Date();
  }
}

public class HelloServiceProxy implements HelloService{
  private HelloService helloService; //表示被代理的HelloService 實例
  public HelloServiceProxy(HelloService helloService){
    this.helloService=helloService;
  }
  public void setHelloServiceProxy(HelloService helloService){
     this.helloService=helloService;
  }
  public String echo(String msg){
    System.out.println("before calling echo()"); //目標方法調前處理
    //調用委託類對象的方法(也就是目標對象方法/被代理對象方法)
    //這個方法纔是我們真正要執行的方法
    String result=helloService.echo(msg); 
    System.out.println("after calling echo()"); //目標方法調用後處理
    return result;
  }
  public Date getTime(){
    System.out.println("before calling getTime()"); //目標方法調前處理

    //調用委託類對象的方法(也就是目標對象方法/被代理對象方法)
    //這個方法纔是我們真正要執行的方法
    Date date=helloService.getTime();

    System.out.println("after calling getTime()"); //目標方法調用後處理
    return date;
   }
}

main:

   HelloService helloService=new HelloServiceImpl();
   HelloService helloServiceProxy=new HelloServiceProxy(helloService);
   System.out.println(helloServiceProxy.echo("hello"));

動態代理

與靜態代理類對照的是動態代理類,動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。動態代理類不僅簡化了編程工作,而且提高了軟件系統的可擴展性,因爲Java 反射機制可以生成任意類型的動態代理類。 java.lang.reflect 包下面的Proxy類和InvocationHandler 接口提供了生成動態代理類的能力。
例子:
接口:

public interface IStudentService {

void save(Student s);

void delete(long id);

Student find(long id);

 }

日誌類:

public class StudentLogger {

public void log(String msg){
    System.out.println("log: "+msg);
}

}

實現類

public class StudentServiceImpl implements IStudentService {
public void delete(long id) {
    // 記錄日誌
    System.out.println("student is deleted...");
}

public Student find(long id) {
    // 記錄日誌
    System.out.println("student is found...");
    return null;
}

public void save(Student s) {
    // 記錄日誌
    System.out.println("student is saved...");
}
}

//InvocationHandler接口的實現類,java的動態代理中需要使用

public class MyHandler implements InvocationHandler {
//目標對象
private Object target; 
private StudentLogger logger = new StudentLogger();

public MyHandler() {
}

public MyHandler(Object target) {
    this.target = target;
}

// 參數1 將來所產生的代理對象 Proxy4$
// 參數2 將來需要調用到的目標對象裏面真正的那個方法的鏡像
// 參數3 將來調用方法的時候所傳的參數
public Object invoke(Object proxy, Method m, Object[] args)
        throws Throwable {
    // 獲得將來所調用方法的名字
    String methodName = m.getName();
    // 用日誌記錄輸出一下
    logger.log(methodName + " is invoked...");
    // 用反射的方式去調用將來需要真正調用的方法.
    Object o = m.invoke(target, args);

    return o;
}
get/set
....
 }

main:

//目標對象
IStudentService service = new StudentServiceImpl();
//service是我們的目標對象。
//我們要給目標對象產生代理對象。
//目標對象service只能單獨執行delete方法。
//但是我們需要的是:先執行log日誌方法再執行delete方法。
//目標對象service做不到這個要求,所以我們要給目標對象service
//生成一個代理對象去完成這倆個操作.

//怎麼給目標對象生成代理對象:
//JDK動態代理的方式

//獲得目標對象的Class對象
Class c = service.getClass();
//獲得目標對象的類加載器對象
ClassLoader classLoader = c.getClassLoader();

//獲得目標對象所實現的所有接口
Class[] interfaces = c.getInterfaces();

//獲得一個InvocationHandler接口的實現類對象,並把目標對象傳進去
InvocationHandler h = 
        new MyHandler(service);

//參數1 目標對象的類加載器對象
//參數2 目標對象所實現的所有接口. Class類型數組
//參數3 InvocationHandler接口的實現類對象
IStudentService proxy = 
    (IStudentService)Proxy.newProxyInstance
    (classLoader, interfaces, h);
//這裏的proxy是一個實現了IStudentService接口動態生成的代理類的對象
proxy.delete();

CGLib代理

JDK實現動態代理需要實現類通過接口定義業務方法,對於沒有接口的類,如何實現動態代理呢,這就需要CGLib了。CGLib採用了非常底層的字節碼技術,其原理是通過字節碼技術爲目標對象創建一個子類對象,並在子類對象中攔截所有父類方法的調用,然後在方法調用前後調用後都可以加入自己想要執行的代碼。JDK動態代理與CGLib動態代理都是Spring AOP的採用的代理方式。

簡單的實現

這是一個需要被代理的類,也就是父類,通過字節碼技術創建這個類的子類,實現動態代理。

public class SayHello {
 public void say(){
     System.out.println("hello everyone");
 }
}

注意:在cglib方式中,目標對象作爲父類,代理對象作爲目標對象動態生成的子類對象

  1. 該類實現了創建一個類的子類的方法(cglib給一個類生成代理對象的方式)
  2. getProxy(SuperClass.class)方法通過參數即父類的class對象,創建出它的一個子類對象,也就是cglib方式的代理對象
  3. intercept()方法攔截所有目標類方法的調用,
  4. obj表示將來生成的代理對象,
  5. method爲目標類中方法的反射對象,args爲方法的動態入參,
  6. mproxy爲代理類(子類)中方法的反射對象。
  7. mproxy.invokeSuper(obj, args)通過代理類調用目標對象(父類)中的方法。
    public class CglibProxy implements MethodInterceptor{

     public Object getProxy(Class clazz){
     Enhancer enhancer = new Enhancer();
     //設置誰是父類
     enhancer.setSuperclass(clazz);
     enhancer.setCallback(this);
     //通過字節碼技術動態創建子類實例
     return enhancer.create();
     }

//實現MethodInterceptor接口方法

 public Object intercept(Object obj, Method method, Object[] args,
     MethodProxy mproxy) throws Throwable {
     System.out.println("前置代理");
     //通過代理類調用父類中的方法
     Object result = mproxy.invokeSuper(obj, args);
     System.out.println("後置代理");
     return result;
  }
 }

main:

   CglibProxy proxy = new CglibProxy();
   //通過生成子類的方式創建代理類
   SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);
   proxyImp.say();

輸出結果:
前置代理
hello everyone
後置代理

Spring實現AOP(Aspect Oriented Programming)是依賴JDK動態代理和CGLIB代理(不同情況spring會自己選擇一種方式)。

JDK動態代理和CGLIB代理的對比:
JDK動態代理
其代理對象必須是某個接口的實現,它是通過在運行期間創建一個接口的實現類來完成對目標對象的代理。
CGLIB代理
實現原理類似於JDK動態代理,只是它在運行期間生成的代理對象是針對目標類擴展的子類。CGLIB是高效的代碼生成包,底層是依靠ASM(開源的java字節碼編輯類庫)操作字節碼實現的。

所以spring會有以下倆種選擇動態代理實現方式的情況:

  • 如果目標對象實現了接口,默認情況下會採用JDK的動態代理實現AOP
  • 如果目標對象沒有實現了接口,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間自動選擇;

認識AOP中的一些基本概念,然後在一個一個的例子中,不斷的加強對這些概念的理解同時要能自己表述出每個概念的含義

AOP          面向切面編程

aspect        切面/切面類

joinPoint    連接點
        在spring的aop中只有 類中的方法 可以做連接點,每一個方法都可以是一個連接點.
    
pointCut    切入點 
        一組連接點的集合

advice        通知/攔截器 
        用來控制切面類將來到底是織入到切入點的前面、後面或者是拋異常的時候。

adivsor        增強器
        用來篩選類中的哪些方法是我們的連接點(哪些方法需要被攔截).

target        目標對象

proxy        代理對象

wave        織入
  1. 前置通知(Before advice):
    在某連接點(join point)之前執行的通知

  2. 返回後通知(After returning advice):
    在某連接點(join point)正常完成後執行的通知:例如,一個方法沒有拋出任何異常,正常返回。

  3. 拋出異常後通知(After throwing advice):
    在方法拋出異常退出時執行的通知。

  4. 後通知(After (finally) advice):
    當某連接點退出的時候執行的通知

  5. 環繞通知(Around Advice):
    包圍一個連接點(join point)的通知,例如事務的處理,就需要這樣的通知,因爲事務需要在方法前開啓,在方法後提交

在Spring中,Advice是由spring中的幾個接口來指定(就像action類由struts2中的action接口來指定一樣),主要有以下幾種:

Before Advice

    public interface MethodBeforeAdvice extends BeforeAdvice {
    void before(Method m, Object[] args, Object target) throws Throwable;
     }

例如:
//有一下幾個類或者接口:
Account.java

    private int id;
    private String name;
    private double balance;//餘額
    get/set
    ...

AccountDao.java

    //取款 賬號減去多少錢
    void withdraw(Account acc,double amt);
    //存款 賬號加上多少錢
    void deposit(Account acc,double amt);

AccountDaoImpl.java

    //簡單的實現接口中的抽象方式

IAccountService.java

    //銀行賬號的一個操作:例如轉賬
    void bankAction();

AccountServiceImpl.java

    private AccountDao accountDao;
    private Account account;
    //轉賬
    public void bankAction(){
        accountDao.withdraw(account, 100);
        accountDao.deposit(account, 100);
    }
    get/set
    ...

//切面類

public class MyLogger {
    public void log(String msg){
        System.out.println("log:"+msg);
    }
 }

我們要做的事情:在轉賬方法(bankAction)執行之前進行一個日誌輸出

//前置通知:作用Spring會在目標方法執行之前調用這個before方法

public class BeforeAdvice implements MethodBeforeAdvice {
    //切面類
    private MyLogger logger;

    // 參數1 將來我們需要調用的目標對象中的方法鏡像
    // 參數2 將來調用方法的時候所傳過來的參數
    // 參數3 目標對象
   //將來在調用目標對象方法之前,會先執行這個before方法
    //在此方法只需要去寫,代理對象要新增的功能呢=,不需要手動調用目標對象
    //所執行的方法。
    public void before(Method m, Object[] args, Object target) throws Throwable {

        logger.log(m.getName() + " is invoked..");

        /*
         * 注意:這裏一定不要自己手動的用反射去 調用這個目標對象中的方法,
         * 因爲spring 會幫我們去調用的,如果我們這個再去調用這個方法,
         * 那麼這這個方法會被調用倆次.
         * 
         * m.invoke(target,args);
         * 
         */
    }
    get/set
}

配置xml文件: 注意ProxyFactoryBean的配置,htmlsingle中搜索即可

    <!-- 配置切面類 -->
    <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>
    
    <!-- 配置advice -->
    <bean name="beforeAdvice" 
    class="com.briup.aop.before.BeforeAdvice">
    <!-- 注入切面類對象 -->
    <property name="logger" ref="logger"></property>
    </bean>
    
    <!-- 配置dao層對象 -->
    <bean id="dao" class="com.briup.aop.dao.AccountDaoImpl"/>
    
    <!-- 配置目標對象 -->
    <bean name="target" 
    class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
    </bean>
    
    <!-- 配置代理對象 -->
    <!-- 這裏使用的是spring的一個代理對象工廠類產生的 -->
    <bean name="proxy" 
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 注入目標對象 -->
    <property name="target" ref="target"></property>
    
    <!-- 注入目標對象所實現的接口 可以有多個接口 -->
    <property name="proxyInterfaces">
        <list>
            <value>com.briup.aop.service.IAccountService</value>
        </list>
    </property>
    
    <!-- 注入advice  可以有多個 -->
    <property name="interceptorNames">
        <list>
            <value>beforeAdvice</value>
        </list>
    </property>
    
    </bean>

After advice

public interface AfterReturningAdvice extends Advice {
    void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable;
}

例如:

public class AfterAdvice implements AfterReturningAdvice {
    private MyLogger logger;
    
    //參數1 目標對象中的方法執行完返回值
    //參數2 所執行方法的鏡像對象
    //參數3 執行方法時候所傳的參數
    //參數4 目標對象
    //將來調用目標對象的方法之後會執行這個afterReturning方法
    public void afterReturning(Object returnValue, Method method,
            Object[] args, Object target) throws Throwable {
        
        logger.log("after returning " + " target=" + target
                + " method Name=" + method.getName() + " args are:" + args
                + " returnValue=" + returnValue);
    }
    get/set
}

xml配置文件:

<!-- 配置切面類 -->
<bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>

<!-- 配置advice -->
<bean name="afterAdvice"
    class="com.briup.aop.after.AfterAdvice">
    <property name="logger" ref="logger"></property>    
</bean>

<!-- 配置dao層對象 -->
<bean id="dao" class="com.briup.aop.dao.AccountDaoImpl" />

<!-- 配置目標對象 -->
<bean name="target"
    class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
</bean>

<!-- 配置代理對象 -->
<!-- 這裏使用的是spring的一個代理對象工廠類產生的 -->
<bean name="proxy"
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 注入目標對象 -->
    <property name="target" ref="target"></property>

    <!-- 注入目標對象所實現的接口 可以有多個接口 -->
    <property name="proxyInterfaces">
        <list>
            <value>com.briup.aop.service.IAccountService</value>
        </list>
    </property>

    <!-- 注入advice  可以有多個 -->
    <property name="interceptorNames">
        <list>
            <value>afterAdvice</value>
        </list>
    </property>

</bean>

注意:另外一個返回後通知接口:AfterReturningAdvice的使用方式和這個是類似的,但是需要注意它們倆個之間的區別

環繞Advice:

public interface MethodInterceptor extends Interceptor {
      Object invoke(MethodInvocation invocation) throws Throwable;
}

例如:

public class AroundAdvice implements MethodInterceptor {
private MyLogger logger;

public Object invoke(MethodInvocation mi) throws Throwable {
    // mi.getMethod()獲得將來要調用的方法的鏡像
    //在目標方法執行之前做日誌
    logger.log(mi.getMethod().getName() + " is start...");
    
    // 這個方法就是用來調用目標對象中的方法的
    Object returnValue = mi.proceed();
    
    //在目標方法執行之後做日誌
    logger.log(mi.getMethod().getName() + " is end...");

    return returnValue;
}
get/set

xml配置文件:

    <!-- 配置切面類 -->
    <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>
    
    <!-- 配置advice -->
    <bean name="aroundAdvice" 
    class="com.briup.aop.around.AroundAdvice">
    <!-- 注入切面類對象 -->
    <property name="logger" ref="logger"></property>
    </bean>
    
    <!-- 配置dao層對象 -->
    <bean name="dao" class="com.briup.aop.dao.AccountDaoImpl"/>
     
    <!-- 配置目標對象 -->
    <bean name="target" 
    class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
    </bean>
    
    <!-- 配置代理對象 -->
    <!-- 這裏使用的是spring的一個代理對象工廠類產生的 -->
    <bean name="proxy" 
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 注入目標對象 -->
    <property name="target" ref="target"></property>
    
    <!-- 注入目標對象所實現的接口 可以有多個接口 -->
    <property name="proxyInterfaces">
        <list>
            <value>com.briup.aop.service.IAccountService</value>
        </list>
    </property>
    
    <!-- 注入advice 可以有多個 -->
    <property name="interceptorNames">
        <list>
            <value>aroundAdvice</value>
        </list>
    </property>
    </bean>

Throws Advice

//ThrowsAdvice 是一個空接口,起標識作用

public interface ThrowsAdvice extends Advice {

}

例如:

public class ThrowingAdvice implements ThrowsAdvice {
    private MyLogger logger;

    public MyLogger getLogger() {
        return logger;
    }

    public void setLogger(MyLogger logger) {
        this.logger = logger;
    }

    //這裏這個方法的名字一定要叫afterThrowing
    //參數可以是1個也可以是四個
    //1個參數的時候只能是一個異常類型的參數
    //如果是4個參數的話,參數的順序也一定要是下面的順序
    public void afterThrowing(Method method, Object[] args, Object target,Exception e) {
        logger.log(e.getMessage());
    }
    
    //下面這樣寫也可以
    /*
    public void afterThrowing(Exception e) {
        
        logger.log(e.getMessage());
    }
    */
    get/set
}

配置xml文件:

    <!-- 配置切面類 -->
    <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>
    
    <!-- 配置advice -->
    <bean name="throwAdvice" class="com.briup.aop.throwException.ThrowingAdvice">
    <!-- 注入切面類對象 -->
    <property name="logger" ref="logger"></property>
    </bean>
    
    <!-- 配置dao層對象 -->
    <bean id="dao" class="com.briup.aop.dao.AccountDaoImpl"/>
    
    <!-- 配置目標對象 -->
    <bean name="target" 
    class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
    </bean>
    
    <!-- 配置代理對象 -->
    <!-- 這裏使用的是spring的一個代理對象工廠類產生的 -->
    <bean name="proxy" 
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 注入目標對象 -->
    <property name="target" ref="target"></property>
    
    <!-- 注入目標對象所實現的接口 可以有多個接口 -->
    <property name="proxyInterfaces">
        <list>
            <value>com.briup.aop.service.IAccountService</value>
        </list>
    </property>
    
    <!-- 注入advice  可以有多個 -->
    <property name="interceptorNames">
        <list>
            <value>throwAdvice</value>
        </list>
    </property>
    </bean>

advisor

作用:篩選要攔截(要代理)的方法,之前的advice是把目標對象中的所有方法全部都進行代理
指定爲advisor的接口爲:

public interface PointcutAdvisor {
    Pointcut getPointcut();
    Advice getAdvice();
} 

spring中已經給我們提供了實現類RegexpMethodPointcutAdvisor,在xml中直接配使用就可以了

xml配置文件:

<bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>

<!-- 配置advice -->
<bean name="beforeAdvice" 
class="com.briup.aop.before.BeforeAdvice">
    <!-- 注入切面類對象 -->
    <property name="logger" ref="logger"></property>
</bean>

<!-- 配置advisor 增強器-->
<!-- 作用:篩選要攔截(要代理)的方法 -->
<bean name="advisor" 
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <!-- 注入advice 表示增強器要在哪一個advice起作用-->
    <property name="advice" ref="beforeAdvice"></property>
    <!-- 注入需要被攔截的目標對象中的方法(連接點) -->
    <property name="patterns">
        <list>
            <value>.*bankAction</value>
        </list>
    </property>
</bean>

<bean id="dao" 
 class="com.briup.aop.dao.AccountDaoImpl"/>
<!-- 配置目標對象 -->
<bean name="target" 
class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
</bean>

<!-- 配置代理對象 -->
<!-- 這裏使用的是spring的一個代理對象工廠類產生的 -->
<bean name="proxy" 
class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 注入目標對象 -->
    <property name="target" ref="target"></property>
    
    <!-- 注入目標對象所實現的接口 可以有多個接口 -->
    <property name="proxyInterfaces">
        <list>
            <value>com.briup.aop.service.IAccountService</value>
        </list>
    </property>
    
    <!-- 注入advice/advisor  可以有多個 -->
    <property name="interceptorNames">
        <list>
            <value>advisor</value>
        </list>
    </property>
</bean>

AutoProxy 自動代理:DefaultAdvisorAutoProxyCreator類的使用

使用原因:在配置文件中我們往往需要給很多個目標對象設置代理對象,那麼上面例子的方式就需要每個目標對象的代理對象都需要配置一套類似的標籤
自動代理:可以用很少的配置爲xml文件中的目標對象自動的生成對應的代理對象

xml配置文件:

<!-- 配置切面類 -->
<bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>

<!-- 配置advice -->
<bean name="beforeAdvice" 
class="com.briup.aop.before.BeforeAdvice">
    <!-- 注入切面類對象 -->
    <property name="logger" ref="logger"></property>
</bean>

<!-- 配置advisor -->
<!-- 作用:篩選要攔截的方法 -->
<bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <!-- 注入advice -->
    <property name="advice" ref="beforeAdvice"></property>
    <!-- 注入需要被攔截的目標對象中的方法 -->
    <property name="patterns">
        <list>
            <value>.*bankAction</value>
            <value>.*deposit</value>
            <value>.*withdraw</value>
        </list>
    </property>
</bean>

<bean id="dao" class="com.briup.aop.dao.AccountDaoImpl"/>
 
<!-- 配置目標對象 -->
<bean name="target" 
class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
</bean>

<bean name="target2" 
class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
</bean>

<bean name="target3" 
class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
</bean>


<!-- 配置代理對象 -->
<!-- 這裏使用自動代理的方式 autoproxy -->
<!-- 注意:這不是一個工廠類,所以不能用過proxy來拿代理對象 -->
<bean name="proxy" 
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
</bean>

使用自動代理的時候需要注意的方面:

  1. 當前的配置裏面一定要有一個advisor的配置
  2. 不需要向自動代理類中注入任何信息
  3. 不管目標對象是否實現了一個或多接口,自動代理的方式都能夠爲它產生代理對象(CGLib的方式).
  4. 從spring容器中拿代理對象的時候,需要通過目標對象的名字來拿。

AutoProxyByName 通過名字進行自動代理:BeanNameAutoProxyCreator類的使用

使用原因:雖然自動代理可以很方便的給xml文件中的目標對象設置對應的代理對象,但是並不是xml文件中的所有對象都是我們的目標對象,我們更想希望可以進一步篩選出某幾個對象爲我們的目標對象
名字進行自動代理:解決了上面的問題,給我們提供了篩選目標對象的配置方式

xml配置文件:

<!-- 配置切面類 -->
<bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>

<!-- 配置advice -->
<bean name="beforeAdvice" 
class="com.briup.aop.before.BeforeAdvice">
    <!-- 注入切面類對象 -->
    <property name="logger" ref="logger"></property>
</bean>


<!-- 配置advisor -->
<!-- 作用:篩選要攔截的方法 -->
<bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <!-- 注入advice -->
    <property name="advice" ref="beforeAdvice"></property>
    <!-- 注入需要被攔截的目標對象中的方法 -->
    <property name="patterns">
        <list>
            <value>.*bankAction</value>
            <value>.*deposit</value>
            <value>.*withdraw</value>
        </list>
    </property>
</bean>

<bean id="dao" 
 class="com.briup.aop.dao.AccountDaoImpl"/>
 
<!-- 配置目標對象 -->
<bean name="target" 
class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
</bean>

<bean name="target2" 
class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
</bean>

<bean name="target3" 
class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
</bean>



<!-- 配置代理對象 -->
<!-- 這裏使用自動代理的方式 autoproxybyname -->
<bean name="proxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <!-- 注入需要被代理的對象名字 -->
       <property name="beanNames">
           <list>
               <value>target</value>
               <value>target2</value>
               <value>dao</value>
           </list>
       </property>
       
       <!-- 注入advice或者advisor -->
       <property name="interceptorNames">
           <list>
               <value>advisor</value>
           </list>
       </property>
</bean>

使用自動代理的時候需要注意的方面:

  1. 當前的配置裏面有沒有advisor的配置都沒關係
  2. 需要向自動代理類中注入被代理目標對象的名字已經advice或者advisor
  3. 不管目標對象是否實現了一個或多接口,自動代理的方式
    都能夠爲它產生代理對象.
  4. 從spring容器中拿代理對象的時候,需要通過目標對象的
    名字來拿。

Spring框架的學習第一天
Spring框架的學習第二天

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章