web自動化中影響頁面定位的場景有哪些?
阿新 • • 發佈:2021-12-15
謹慎參考
代理模式
代理模式是一種使用代理物件來執行目標物件的方法並在代理物件中增強目標物件方法的一種設計模式。
使用原因
- 使用者不想或者不能直接引用一個委託物件,此時代理模式起到一個
中介
的功能 - 開放封閉原則:當我們需要額外增加功能,比如判斷許可權,快取,可以通過修改代理類而不需要對真實類進行修改
- 實現解耦和隱藏具體實現
應用場景
-
靜態代理:控制對委託類的訪問(使用、修改或者遮蔽部分功能),降低消耗
-
動態代理:攔截類中的方法,並在方法的前後進行一些公共的操作,如spring中的切面程式設計(aop)
示例程式碼
靜態代理
- 使用者類(測試類)可以不需要感知到被代理類(RealCarShop)
- 特點在於控制,控制對於代理類的訪問
- 維護比較麻煩,代理類需要定義和維護與代理類一樣的介面,當介面較多時,程式碼量大
/** * 使用者賣車介面 * * @author weitian.chen * @date 2021/12/15 18:15 */ public interface Human { /** * 賣車 * * @return void * @author weitian.chen * @date 2021/12/15 */ void sellCar(); } /** * 代理車行 * * @author weitian.chen * @date 2021/12/15 18:17 */ public class RealCarShop implements Human { private final String human; private final String customer; public RealCarShop(String human, String customer) { this.human = human; this.customer = customer; } @Override public void sellCar() { System.out.println(human + "尋找買家"); findCar(); result(); } public void findCar() { System.out.println(customer + "尋找賣家"); } public void result() { System.out.println(human + "和" + customer + "買賣成功"); } } /** * 代理類 * 對真實物件進行一些擴充套件 * @author weitian.chen * @date 2021/12/15 18:25 */ public class ProxyCarShop implements Human { private final String human; private final String customer; private final Human car; public ProxyCarShop(String human, String customer) { this.human = human; this.customer = customer; car = new RealCarShop(human, customer); } @Override public void sellCar() { if (check(human, customer)) { if (checkSpecial(customer)) { System.out.println(human + "不想賣給陳琛琛"); }else { car.sellCar(); } } } /** * 判斷使用者名稱是否為空 * * @param human * @param customer * @return java.lang.Boolean * @author weitian.chen * @date 2021/12/16 */ public Boolean check (String human, String customer) { return customer != null && human != null; } /** * 判斷是否為特殊使用者 * * @param customer * @return java.lang.Boolean * @author weitian.chen * @date 2021/12/16 */ public Boolean checkSpecial (String customer) { String special = "陳琛琛"; return customer.equals(special); } } /** * 測試類 * * @author weitian.chen * @date 2021/12/15 18:29 */ public class Test { public static void main(String[] args) { Human test = new ProxyCarShop("陳琛琛", "陳晨橙"); Human test1 = new ProxyCarShop("岑晨晨", "陳琛琛"); test.sellCar(); System.out.println("-----------------------------"); test1.sellCar(); } }
JDK動態代理
- JDK動態代理所使用的
代理物件
會在程式執行階段呼叫到代理物件
時才由JVM建立 - 每個代理類都會實現一個表示內部處理邏輯的
InvocationHandler
介面 - 當呼叫代理物件所代理的介面中的方法時,呼叫資訊會傳遞給
InvocationHandler
的invoke
方法 - 被代理物件必須實現介面
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 動態代理實現類 * * @author weitian.chen * @date 2021/12/16 15:46 */ public class CarShopJdkProxyHandler implements InvocationHandler { private final Object realCarShop; public CarShopJdkProxyHandler(Object realCarShop) { this.realCarShop = realCarShop; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("交易開始"); Object result = method.invoke(realCarShop, args); System.out.println("交易完成"); return result; } } /** * 測試類 * * @author weitian.chen * @date 2021/12/15 18:29 */ public class Test { public static void main(String[] args) { System.out.println("動態代理"); System.out.println("-----------------------------"); //測試動態代理 Human test2 = (Human) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] {Human.class}, new CarShopJdkProxyHandler(new RealCarShop("陳某某", "陳謀謨"))); test2.sellCar(); } }
Cglib動態代理
一個開源專案,能夠代理普通類
,不必實現介面
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
public class Car {
private final String human;
private final String customer;
public RealCarShop(String human, String customer) {
this.human = human;
this.customer = customer;
}
public void sellCar() {
System.out.println(human + "尋找買家");
findCar();
result();
}
public void findCar() {
System.out.println(customer + "尋找賣家");
}
public void result() {
System.out.println(human + "和" + customer + "買賣成功");
}
}
// 動態代理類(實現方法攔截器介面) //
// MethodInterceptor介面來自net.sf.cglib.proxy.MethodInterceptor或org.springframework.cglib.proxy.MethodInterceptor
public class CglibProxy implements MethodInterceptor {
public Object createCglibProxy(Class<?> targetClass) {
Enhancer enhancer = new Enhancer(); // 建立增強器,用來建立動態代理類
enhancer.setSuperclass(targetClass); // 為增強器指定要代理的業務類,即為生成的代理類指定父類
enhancer.setCallback(this); // 設定回撥(對於代理類上所有方法的呼叫,都會呼叫CallBack)
return enhancer.create(); // 建立動態代理類物件並返回
// 以上語句可簡化為:return Enhancer.create(targetClass, this); //
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理開始"); // 擴充套件進行額外的功能操作(如鑑權、計時、日誌等)
Object result = methodProxy.invokeSuper(proxy, args);
System.out.println("cglib代理結束"); // 擴充套件進行額外的功能操作(如鑑權、計時、日誌等)
return result;
}
}
特點:
- 無法final/static的方法(通過繼承被代理的類實現,所以無法動態代理final類)
- 可以代理普通類
Spring中使用jdk和cglib相結合的方式進行實現動態代理
實踐應用
AOP
面向切面程式設計,通過預編譯
方式和執行期間動態代理
實現程式功能的統一維護的一種技術
Spring中模組的關鍵單元是類,在AOP中模組的關鍵單元是切面,以下是與AOP相關的基本概念
- 切面(ASPECT):配置類,我們所想要實現的內容。
- 通知(Advice):切面必須要完成的工作。即,它是類中的一個方法。
- 目標(Target):被通知物件。
- 代理(Proxy):向目標物件應用通知之後建立的物件。
- 切入點(PointCut):切面通知執行的“地點”的定義。
- 連線點(JointPoint):與切入點匹配的執行點。
示例程式碼
實現方式多樣,可參考該文章:Spring學習總結(二)——靜態代理、JDK與CGLIB動態代理、AOP+IoC
總結
AOP實現原理即採用動態代理的方式,對目標物件進行”強化“,新增相關的前置、後置、環繞或返回異常等場景下的內容,讓業務更加靈活,開發更加方便有效