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