Spring學習筆記——AOP

靜態代理和動態代理

靜態代理:

角色:

1.抽象接口(租房:接口)

2.真實角色(比如房東小張:實現類實現抽象接口)

3.代理角色(代理真實角色,比如中介,負責幫小張賣方:實現類實現抽象接口,同時擁有小張這個成員屬性,它可以調用小張實現的方法,並且增加自己的方法在裏面)

4.客戶(買房人:比如測試類,直接new 真實角色,並把真實角色傳入new 代理角色中)

例子:

//抽象接口:租房
public interface Rent {
   public void rent();
}
//真實角色: 房東
public class Host implements Rent{
   public void rent() {
       System.out.println("房屋出租");
  }
}
//代理角色:中介
public class Proxy implements Rent {

   private Host host;
   public Proxy() { }
   public Proxy(Host host) {
       this.host = host;
  }

   //租房
   public void rent(){
       seeHouse();
       host.rent();
       fare();
  }
   //看房
   public void seeHouse(){
       System.out.println("帶房客看房");
  }
   //收中介費
   public void fare(){
       System.out.println("收中介費");
  }
}
//客戶類,一般客戶都會去找代理!
public class Client {
   public static void main(String[] args) {
       //房東要租房
       Host host = new Host();
       //中介幫助房東
       Proxy proxy = new Proxy(host);

       //你去找中介!
       proxy.rent();
  }
}

核心思想:沒有改變房東的代碼,通過構造了新實現類中介,增強了房東的功能。對房東類進行了擴展。

即,我們在不改變原來的代碼的情況下,實現了對原有功能的增強,這是AOP中最核心的思想

動態代理

在靜態代理的例子中,Proxy類把房東小張作爲成員變量,因此它只能代理小張(代碼寫死了)。如果存在其他房東也需要被代理,那對每個房東都需要寫它的代理對象。因此引入動態代理,只需寫一個代理對象,實現所有房東都能被代理。

動態代理分爲兩類 : 一類是基於接口動態代理 , 一類是基於類的動態代理:基於接口的動態代理----JDK動態代理,基於類的動態代理--cglib

兩個關鍵類:InvocationHandler     和     Proxy

實現動態代理的步驟:

新建代理類繼承InvocationHandler(把要代理的抽象接口作爲屬性傳入),重寫invoke方法。對該接口調用靜態類Proxy.newProxyInstance()方法返回代理對象。

//抽象角色:租房
public interface Rent {
   public void rent();
}
//真實角色: 房東,房東要出租房子
public class Host implements Rent{
   public void rent() {
       System.out.println("房屋出租");
  }
}
public class ProxyInvocationHandler implements InvocationHandler {
   private Rent rent;

   public void setRent(Rent rent) {
       this.rent = rent;
  }

   //生成代理類,重點是第二個參數,獲取要代理的抽象角色!之前都是一個角色,現在可以代理一類角色
   public Object getProxy(){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(),
               rent.getClass().getInterfaces(),this);
  }

   // proxy : 代理類 method : 代理類的調用處理程序的方法對象.
   // 處理代理實例上的方法調用並返回結果
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       seeHouse();
       //核心:本質利用反射實現!
       Object result = method.invoke(rent, args);
       fare();
       return result;
  }

   //看房
   public void seeHouse(){
       System.out.println("帶房客看房");
  }
   //收中介費
   public void fare(){
       System.out.println("收中介費");
  }

}
//租客
public class Client {

   public static void main(String[] args) {
       //真實角色
       Host host = new Host();
       //代理實例的調用處理程序
       ProxyInvocationHandler pih = new ProxyInvocationHandler();
       pih.setRent(host); //將真實角色放置進去!
       Rent proxy = (Rent)pih.getProxy(); //動態生成對應的代理類!
       proxy.rent();
  }

}

AOP方面

首先導入依賴

<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.9.4</version>
</dependency>

方式1:自己實現增強類(實現spring提供的接口) + xml配置       ——>見ref

方式2:自定義切入類 + xml配置       ——>見ref

方式3:註解

第一步:編寫一個註解實現的增強類

package com.kuang.config;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class AnnotationPointcut {
   @Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
   public void before(){
       System.out.println("---------方法執行前---------");
  }

   @After("execution(* com.kuang.service.UserServiceImpl.*(..))")
   public void after(){
       System.out.println("---------方法執行後---------");
  }

   @Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
   public void around(ProceedingJoinPoint jp) throws Throwable {
       System.out.println("環繞前");
       System.out.println("簽名:"+jp.getSignature());
       //執行目標方法proceed
       Object proceed = jp.proceed();
       System.out.println("環繞後");
       System.out.println(proceed);
  }
}

 

第二步:在Spring配置文件中,註冊bean,並增加支持註解的配置

<!--第三種方式:註解實現-->
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>

 

Reference:

狂神說公衆號:https://www.bilibili.com/video/BV1WE411d7Dv

靜態/動態代理模式:https://mp.weixin.qq.com/s/McxiyucxAQYPSOaJSUCCRQ

AOP就這麼簡單:https://mp.weixin.qq.com/s/zofgBRRrnEf17MiGZN8IJQ

 

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