1. 程式人生 > 其它 >spring學習14:代理模式

spring學習14:代理模式

spring學習14:代理模式

  • 代理:

    • 就是幫一些人做一些事;

       

 

  • 為什麼要學習代理模式?

    • 因為這就是SpringAOP的底層;

    • 面試高頻:【Spring AOP】和【Spring MVC】

 

  • 代理模式:

    • 靜態代理模式;

    • 動態代理模式;

 

 

  • 靜態代理模式:

    • 角色分析:

      • 抽象角色:一般會使用介面或者抽象類來解決;

      • 真實角色:被代理的角色;

      • 代理角色:代理真實角色,代理真實角色後,我們一般會做一些附屬操作(租房);

      • 客戶:訪問代理物件的人;

 

  • 開發步驟:

    • 介面:

      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() {
             host.rent();
             hetong();
             seeHouse();
             fee();
        }

         //看房
         public void seeHouse(){
             System.out.println("中介帶你看房");
        }

         //收中介費
         public void fee(){
             System.out.println("收中介費");
        }

         //簽約同
         public void hetong(){
             System.out.println("籤合同");
        }


      }
    • 客戶端訪問代理角色:

      public class Client {
         public static void main(String[] args) {
             //房東要租房子
             Host host=new Host();
             //代理:中介幫房東租房子,但是呢?代理角色一般會有一些附屬操作!
             Proxy proxy = new Proxy(host);
             //你不用面對房東,直接找中介租房即可!
             proxy.rent();

        }
      }

       

 

 

  • 靜態代理模式的好處:

    • 可以使真實角色的操作更加純粹,不用去關注一些公共的業務;

    • 公共業務也就交給了代理角色,實現了業務的分工

    • 公共業務發生拓展的時候,方便集中管理

       

  • 靜態代理模式的缺點:

    • 一個真實角色就會產生一個代理角色,程式碼量會翻倍,開發效率會變低;

 



 

  • 加深理解:

    • 面向物件7大原則【重點】;

    • 聊聊AOP

       

 

 

  • 代理案例:介面

    public interface UserService {

        void add();
        void delete();
        void update();
        void query();

    }
  • 代理案例:真實角色

    **
    * 真實角色:
    * 1,增加日誌功能;
    * 2,程式中有個原則:儘量不要去改變原有程式碼;
    *
    */
    public class UserServiceImpl implements UserService {

       public void add() {
           //System.out.println("使用了add方法");
           System.out.println("增加了一個使用者");
      }

       public void delete() {
          // System.out.println("使用了add方法");
           System.out.println("刪除了一個使用者");
      }

       public void update() {
          // System.out.println("使用了add方法");
           System.out.println("修改了一個使用者");
      }

       public void query() {
           //System.out.println("使用了add方法");
           System.out.println("查詢了一個使用者");
      }

       //1,改動原有的業務程式碼,在公司中是大忌;

    }
  • 代理案例:代理角色

    /**
    * 代理角色
    */
    public class UserPorxyImpl implements UserService {

       private UserServiceImpl userService;

       public void setUserService(UserServiceImpl userService) {
           this.userService = userService;
      }


       public void add() {
           print("add");
           userService.add();
      }

       public void delete() {
           print("delete");
           userService.delete();
      }

       public void update() {
           print("update");
           userService.update();
      }

       public void query() {
           print("query");
           userService.query();
      }

       //列印日誌
       public void print(String msg){
           System.out.println("print"+msg);
      }
    }
  • 代理案例:前端呼叫

    /**
    * 測試
    */
    public class Client {
       public static void main(String[] args) {

           UserServiceImpl userService=new UserServiceImpl();
           UserPorxyImpl userPorxy = new UserPorxyImpl();
           userPorxy.setUserService(userService);
           userPorxy.query();
      }
    }

 

 

 



 

  • 動態代理模式:

    • 動態代理的底層都是反射;

    • 動態代理和靜態代理的角色一樣;

      • 抽象角色;

      • 真實角色;

      • 代理角色;

    • 動態代理的代理類是動態生成的,不是我們直接寫好的;

 

  • 動態代理分為2大類:

    • 基於介面的動態代理;(JDK動態代理)【我們在這裡使用】

    • 基於類的動態代理;(cglib)

    • Java位元組碼實現:javasist

 

  • 需要了解2個類:Proxy:代理,InvocationHandler:呼叫處理程式

    • InvocationHandler:

    • Proxy:

       

 

  • 動態代理模式的好處:

    • 可以使真實角色的操作更加純粹,不用去關注一些公共的業務;

    • 公共業務也就交給了代理角色,實現了業務的分工

    • 公共業務發生拓展的時候,方便集中管理

    • 一個動態代理類代理的是一個介面,一般就是對應一類業務;

    • 一個動態代理類可以代理多個類,只要是實現了同一個介面即可;

       

 

 

  • 程式碼案例:介面

    public interface Rent {
       void rent();
    }
  • 程式碼案例:真實角色

    public class Host implements Rent {
       public void rent() {
           System.out.println("房東出租房屋");
      }
    }
  • 程式碼案例:代理處理類

    package com.ljxdemo.demo03;

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;

    /**
    * 因為代理類需要動態生成:
    * 所以需要一個生成代理類的程式:這個類會自動生成代理類
    */
    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);
      }

       //處理代理例項,並返回結果
       public Object invoke(Object proxy, Method method, Object[] args) throws
           Throwable {
           //動態代理的本質,就是使用反射機制實現!
           seeHouse();
           Object invoke = method.invoke(rent, args);
           fee();
           return invoke;
      }

       public void seeHouse(){
           System.out.println("中介帶看房子!");
      }

       public void fee(){
           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就是動態生成的,我們並沒有寫
           proxy.rent();
      }
    }

     

 



 

  • 程式碼優化:

    • 實現萬能代理工具類;

    • 測試;

 

  • 程式碼案例:實現萬能代理工具類

    /**
    * 因為代理類需要動態生成:
    * 所以需要一個生成代理類的程式:這個類會自動生成代理類
    */
    public class ProxyInvocationHandler implements InvocationHandler {

       //被代理的介面
       private Object target;

       public void setTarget(Object target) {
           this.target = target;
      }

       //生成代理物件
       public Object getProxy(){
           return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                                         target.getClass().getInterfaces(),this);
      }

       //處理代理例項,並返回結果
       public Object invoke(Object proxy, Method method, Object[] args) throws
           Throwable {
           //動態代理的本質,就是使用反射機制實現!
           log(method.getName());
           Object invoke = method.invoke(target, args);
           return invoke;
      }


       //增加一個功能
       public void log(String msg){
           System.out.println("執行了"+msg+"方法");
      }

    }
  • 程式碼案例:測試

    public class Client {
       public static void main(String[] args) {

           //真實角色
           UserServiceImpl userService = new UserServiceImpl();
           //代理角色:不存在
           ProxyInvocationHandler pih = new ProxyInvocationHandler();
           //設定要代理的物件
           pih.setTarget(userService);
           //動態生成代理類
           UserService proxy = (UserService) pih.getProxy();
           //
           proxy.delete();

      }
    }