10.SSM框架集~代理模式

10.SSM框架集~代理模式

本文是上一篇文章的後續,詳情點擊該鏈接

代理模式的概念

       代理模式是Java常見的設計模式之一。所謂代理模式是指客戶端並不直接調用實際的對象,而是通過調用代理,來間接的調用實際的對象。 爲什麼要採用這種間接的形式來調用對象呢?一般是因爲客戶端不想直接訪問實際的對象,或者訪問實際的對象存在困難,因此通過一個代理對象來完成間接的訪問。

代理模式的分類:

       1.靜態代理

       2.動態代理[JDK動態代理,CGLIB動態代理]

代理模式的角色

       抽象的類或者接口--定義完成一件怎樣的事情

       代理對象---完成這件事情的對象,直接面向用戶的

       被代理對象--完成事件背後的隱藏內容,用戶看不到

代理模式案例

       完成計算器案例,實現加減乘除操作

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.alvin</groupId>
    <artifactId>CodeSystem</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

    </dependencies>

</project>

在這裏插入圖片描述

Calculator接口

//定義接口
public interface Calculator{
    //加法
    Double add(Double num1, Double num2);
    //減法
    Double subtraction(Double num1, Double num2);
    //乘法
    Double multiplication(Double num1, Double num2);
    //除法
    Double division(Double num1, Double num2);
}

CalculatorImpl實現類

//實現接口
public class CalculatorImpl implements Calculator{

    public Double add(Double num1, Double num2) {
        Log4j.log("add",num1,num2);
        Double result = num1 + num2;
        return result;
    }

    public Double subtraction(Double num1, Double num2) {
        Log4j.log("subtraction",num1,num2);
        Double result = num1 - num2;
        return result;
    }

    public Double multiplication(Double num1, Double num2) {
        Log4j.log("multiplication",num1,num2);
        Double result = num1 * num2;
        return result;
    }

    public Double division(Double num1, Double num2) {
        Log4j.log("division",num1,num2);
        Double result = num1 / num2;
        return result;
    }
}

Log4j

//日誌功能
public class Log4j {
    public  static void log(String  method,Double num1,Double num2){
        System.out.println("當前執行的方法爲" + method  + ", 參數一:" + num1+ ", 參數二:" + num2);
    }
}

測試

public class MyCalculator {
    public static void main(String[] args) {
        Calculator calculator = new CalculatorImpl();
        double result = calculator.add(7.0,9.0);
        System.out.println(result);
    }
}

在這裏插入圖片描述

       但其實我們發現這樣寫會有一個弊端,那就是每當寫一個方法,都要在方法裏面改參數,那麼假如我們要寫五百個方法,就也要改五百次嘛?那麼,我們就來試試更好的方案!

JDK動態代理

動態代理簡介

       動態代理有別於靜態代理,是根據代理的對象,動態創建代理類。這樣,就可以避免靜態代理中代理類接口過多的問題。動態代理是實現方式,是通過反射來實現的,藉助Java自帶的java.lang.reflect.Proxy,通過固定的規則生成

在這裏插入圖片描述

CalculatorImpl稍微改變
class CalculatorImpl implements Calculator {

    public Double add(Double num1, Double num2) {
        Double result = num1 + num2;
        return result;
    }

    public Double subtraction(Double num1, Double num2) {
        Double result = num1 - num2;
        return result;
    }

    public Double multiplication(Double num1, Double num2) {
        Double result = num1 * num2;
        return result;
    }

    public Double division(Double num1, Double num2) {
        Double result = num1 / num2;
        return result;
    }
}
JDKProxy
public class JDKProxy  {
    public static Object  getInstance(final Object  object){

        return Proxy.newProxyInstance(object.getClass().getClassLoader(), new Class[]{Calculator.class}, new InvocationHandler() {

            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //記錄日誌功能闊贊實現
                Log4j.log(method.getName(),args[0],args[1]);
                //執行目標方法內容
                Object invoke = method.invoke(object, args);
                return invoke;
            }
        });
    }
}
測試
public class MyCalculator {
    public static void main(String[] args) {
        //返回的就是代理對象
        Calculator instance =(Calculator) JDKProxy.getInstance(new CalculatorImpl());
        //調用代理對象中Add方法
        Double add = instance.add(7.0, 5.0);
        //輸出結果
        System.out.println(add);
    }
}

在這裏插入圖片描述

       這個時候會發現,無論寫多少個方法,都無需修改代碼

CGLIB動態代理

JDK動態代理存在的問題

       JDK代理的產生必須要實現對應的接口的,如果沒有對應的接口,這個時候代理對象就沒有辦法產生。

解決的方案

       CGLIB動態代理

CGLIB代理

       cglib的原理是這樣,它生成一個繼承B的類型C(代理類),這個代理類持有一個MethodInterceptor,我們setCallback時傳入的。 C重寫所有B中的方法(方法名一致),然後在C中,構建名叫“CGLIB”+“$父類方法名$”的方法(下面叫cglib方法,所有非private的方法都會被構建),方法體裏只有一句話super.方法名(),可以簡單的認爲保持了對父類方法的一個引用,方便調用。

       這樣的話,C中就有了重寫方法、cglib方法、父類方法(不可見),還有一個統一的攔截方法(增強方法intercept)。其中重寫方法和cglib方法肯定是有映射關係的。

代碼實現

在這裏插入圖片描述

先在pom.xml裏面導入依賴

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>
CGLIBProxy類
public class CGLIBProxy {
    public static Object getProxy(final Object object){
        Enhancer enhancer = new Enhancer();
        //設置代理對象的父類
        enhancer.setSuperclass(object.getClass());
        //設置回調函數
        enhancer.setCallback(new MethodInterceptor() {
            //提供給用戶進行方法增強的代碼
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //代碼增強A
                System.out.println("代碼擴展AAAA");
                //反射執行目標對象
                Object invoke = method.invoke(object, objects);
                //執行目標對象
                System.out.println("代碼擴展BBB");
                return invoke;
            }
        });
        //使整個操作生效
        Object o = enhancer.create();
        return o;
    }
}
CalculatorImpl2
public class CalculatorImpl2 {

    public Double add(Double num1, Double num2) {
        Double result = num1 + num2;
        return result;
    }

    public Double subtraction(Double num1, Double num2) {
        Double result = num1 - num2;
        return result;
    }

    public Double multiplication(Double num1, Double num2) {
        Double result = num1 * num2;
        return result;
    }

    public Double division(Double num1, Double num2) {
        Double result = num1 / num2;
        return result;
    }
}
main
public class MyCalculator {
    @Test
    public static void main(String[] args) {
        //返回的是動態產生的代理對象
        CalculatorImpl2 proxy = (CalculatorImpl2) CGLIBProxy.getProxy(new CalculatorImpl2());
        //調用代理對象方法
        Double result = proxy.add(7.9, 8.0);

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