【Spring Framework】10、代理模式
阿新 • • 發佈:2021-07-11
為什麼要學習代理模式?因為這就是Spring AOP 的底層!【Spring AOP 和 Spring MVC】
代理模式的分類:
- 靜態代理
- 動態代理
1、靜態代理
角色分析:
- 抽象角色:一般會使用介面或抽象類來解決
- 真實角色:被代理角色
- 代理角色:代理真實角色,代理真實角色後,我們一般會做一些附屬操作
測試程式碼
1、介面
package com.xg.demo01;
// 租房
public interface Rent {
public void rent();
}
2、真實角色
package com.xg.demo01; // 房東 public class Host implements Rent { @Override public void rent() { System.out.println("房東要出租房子"); } }
3、代理角色
package com.xg.demo01; public class Proxy implements Rent { private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } @Override public void rent() { host.rent(); seeHost(); contract(); fare(); } // 看房 public void seeHost() { System.out.println("中介帶你看房。"); } // 籤合同 public void contract() { System.out.println("籤租賃合同"); } // 收中介費 public void fare() { System.out.println("中介,收中介費。"); } }
4、客戶端訪問代理
package com.xg.demo01;
public class Client {
public static void main(String[] args) {
// 房東有房子出租
Host host = new Host();
// 代理,中介幫房東出租房子,但是代理角色一般會有一些附屬操作!
Proxy proxy = new Proxy(host);
// 不用面對房東,直接找中介即可
proxy.rent();
}
}
代理模式的好處
- 可以使真實角色的操作更加純粹,不用去關注一些公共的業務
- 公共業務交給了代理!實現了業務的分工!
- 公共業務發生擴充套件的時候,方便集中管理!
缺點:
- 一個真實角色就會產生一個代理角色;程式碼量會翻倍,開發效率會變低
為什麼要新增代理類
- 改變原有的業務程式碼在公司中是大忌
- 原則:儘量不要改變原有的程式碼
加深理解
1、介面
package com.xg.demo02;
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
2、真實角色
package com.xg.demo02;
// 真實物件
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加一個使用者");
}
@Override
public void delete() {
System.out.println("刪除一個使用者");
}
@Override
public void update() {
System.out.println("更新一個使用者");
}
@Override
public void query() {
System.out.println("查詢一個使用者");
}
}
3、代理角色
package com.xg.demo02;
public class UserServiceProxy implements UserService {
private UserServiceImpl userService;
public UserServiceProxy() {
}
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
@Override
public void add() {
log("add");
userService.add();
}
@Override
public void delete() {
log("delete");
userService.delete();
}
@Override
public void update() {
log("update");
userService.update();
}
@Override
public void query() {
log("query");
userService.query();
}
// 列印日誌 方式
public void log(String msg) {
System.out.println("[DEBUG]使用了" + msg + "方法");
}
}
4、客戶端訪問代理
package com.xg.demo02;
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy userServiceProxy = new UserServiceProxy();
userServiceProxy.setUserService(userService);
userServiceProxy.add();
}
}
2、動態代理
- 動態代理和靜態代理角色一樣
- 動態代理的代理類是動態生成的,不是我們直接寫好的!
- 動態代理分為兩大類:基於介面的動態代理,基於類的動態代理
- 基於介面:JDK動態代理【使用】
- 基於類:cglib
- Java位元組碼:javasist
需要了解兩個類:Proxy:代理,InvocationHandler:呼叫處理程式
-
InvocationHandler
是由代理例項的呼叫處理程式實現的介面 。每個代理例項都有一個關聯的呼叫處理程式。 當在代理例項上呼叫方法時,方法呼叫將被編碼並分派到其呼叫處理程式的
invoke
方法。 -
Proxy
提供了建立動態代理類和例項的靜態方法,它也是由這些方法建立的所有動態代理類的超類。
測試程式碼
1、介面
package com.xg.demo03;
// 租房
public interface Rent {
public void rent();
}
2、真實角色
package com.xg.demo03;
// 房東
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房東要出租房子");
}
}
3、InvocationHandler 自動生成代理
package com.xg.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);
}
// 處理代理例項並返回結果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(rent, args);
seeHost();
contract();
fare();
return invoke;
}
public void seeHost() {
System.out.println("中介帶你看房。");
}
public void contract() {
System.out.println("籤租賃合同");
}
public void fare() {
System.out.println("中介,收中介費。");
}
}
4、代理物件
package com.xg.demo03;
public class Client {
public static void main(String[] args) {
// 真實角色
Host host = new Host();
// 代理角色:暫時沒有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
// 通過呼叫程式處理角色來處理要呼叫的介面物件!
pih.setRent(host); // 這裡的proxy就是動態生成的,並沒有寫
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
加深理解
代理 UserService
InvocationHandler 自動生成代理
package com.xg.demo04;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 使用這個類,自動生成代理類!
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);
}
// 處理代理例項並返回結果
@Override
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("[DEBUG]執行了" + msg + "方法");
}
}
``
Client
package com.xg.demo04;
import com.xg.demo02.UserService;
import com.xg.demo02.UserServiceImpl;
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.add();
}
}
動態代理的好處
- 可以使真實角色的操作更加純粹,不用去關注一些公共的業務
- 公共業務交給了代理!實現了業務的分工!
- 公共業務發生擴充套件的時候,方便集中管理!
- 一個動態代理類代理的是一個介面,一般是對應一類業務
- 一個動態代理可以代理多個類,只要實現了同一個介面