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);
}
}