# JavaSec101 - P2: Java Dynamic Proxy (NOT DONE)
Ở bài trước mình đã đề cập đến cơ chế **Java Reflection** trong java, đến với bài hôm nay sẽ là một chủ đề khác là **Dynamic Proxy** trong java.
**Dynamic Proxy** lại có liên quan chặt chẽ với **Java Reflection** vậy nên nếu bạn chưa đọc về reflection thì có thể ngó qua [phần 1](https://hackmd.io/Sc09QTQCRrCg0_5Pnr4ebg) một chút nhé :D
Từ "Proxy" trong **Dynamic Proxy** không phải proxy mà chúng ta hay nhắc tới trong mạng máy tính. Proxy ở đây là một class được xây dựng sẵn trong thư viện chuẩn của java là `java.lang.reflect.Proxy`
Và class này được xây dựng dựa trên một pattern trong design pattern là `proxy pattern`
Nếu bạn hứng thú muốn tìm hiểu về design pattern thì có thể tham khảo [ở đây](https://viblo.asia/p/tong-hop-cac-bai-huong-dan-ve-design-pattern-23-mau-co-ban-cua-gof-3P0lPQPG5ox)
## Proxy
Proxy là một đối tượng đứng ở giữa đối tượng client và đối tượng mà client đó muốn sử dụng (target object)

Đối tượng proxy kiểm soát truy cập đối với đối tượng mục tiêu.
Khả năng kiểm soát truy cập của đối tượng proxy nằm ở 4 yếu tố:
1. Synchronization (Đồng bộ hóa)
2. Authentication (Xác thực)
3. Remote Access (truy cập từ xa)
4. Lazy instantiation (đã đươc đề cập trong link mình đính kèm ở trên)
Có 2 kiểu proxy trong java là:
* Static proxy
* Dynamic proxy
Trước khi đi vào chi tiết hai kiểu proxy này, hãy xem sự khác biệt khi có Proxy object và không có Proxy object.
### Vehicle Example With No Proxy
Đầu tiên, sẽ thế nào nếu client có thể truy cập vào một đối tượng (phương tiện) mà không thông qua proxy

```java
public interface IVehicle {
public void start();
public void stop();
public void forward();
public void reverse();
public String getName();
}
```
Một class `Car` implements interface `IVehicle`:
```java
public class Car implements IVehicle {
private String name;
public Car(String name) {this.name = name;}
public void start() {
System.out.println("Car " + name + " started");
}
// stop(), forward(), reverse() implemented similarly.
// getName() not shown.
}
```
Class `Client` truy xuất trực tiếp vào class `Car`:
```java
public class Client1 {
public static void main(String[] args) {
IVehicle v = new Car("Botar");
v.start();
v.forward();
v.stop();
}
}
```
output:
```java
Car Botar started
Car Botar going forward
Car Botar stopped
```
Có thể thấy là client có thể truy xuất trực tiếp vào Car object mà không hề có sự theo dõi hay kiểm soát nào (ý mình là ví dụ có thể log lại hành động của người dùng hay authen rồi mới cho truy xuất)
### Vehicle Example With Proxy
Bây giờ chúng ta sẽ thêm một `Proxy object` ở giữa. Cụ thể ở đây mình sẽ thêm một `static proxy`

```java
public class VehicleProxy implements IVehicle {
private IVehicle v;
public VehicleProxy(IVehicle v) {this.v = v;}
public void start() {
System.out.println("VehicleProxy: Begin of start()");
v.start();
System.out.println("VehicleProxy: End of start()");
}
// stop(), forward(), reverse() implemented similarly.
// getName() not shown.
}
```
và khi client muốn truy xuất vào Car object thì phải đi qua Proxy object này
```java
public class Client2 {
public static void main(String[] args) {
IVehicle c = new Car("Botar");
IVehicle v = new VehicleProxy(c);
v.start();
v.forward();
v.stop();
}
}
```
output:
```java
VehicleProxy: Begin of start()
Car Botar started
VehicleProxy: End of start()
VehicleProxy: Begin of forward()
Car Botar going forward
VehicleProxy: End of forward()
VehicleProxy: Begin of stop()
Car Botar stopped
VehicleProxy: End of stop()
```
Có thể thấy chúng ta hoàn toàn có thể kiểm soát (log, authen) user khi muốn truy xuất vào Car object mà không làm thay đổi class `Car`
### Static Proxy
Vậy static proxy ở đây là gì?
**Static proxy** là Proxy class mà chúng ta phải viết trước khi chương trình được compile và mối quan hệ giữa proxy class và target object phải được viết trước khi chương trình chạy
#### Ưu điểm của proxy nói chung và static proxy nói riêng
Proxy có thể được sử dụng để thêm các hành vi, code mà không làm thay đổi class gốc (Car object như ví dụ trên)
Thường thì các lib được thêm từ bên ngoài rất khó để có thể chỉnh sửa và thêm code -> chúng ta có thể viết một proxy class để thêm.
Ví dụ: chúng ta có thể viết một proxy class cho `java.net.HttpUrlConnection` log hết tất cả các user, service request đến mà không chỉnh sửa gì class `HttpUrlConnection`
Ưu điểm nữa khi sử dụng proxy là tính bảo mật. Các bạn có thể đọc về **Remote Proxy** được đề cập trong bài design patten ở trên.
#### Nhược điểm của static proxy
Sẽ thế nào nếu số class cần được kiểm soát tăng lên? Static proxy phải được viết trước khi chạy nên viết hết luông?
Khi mà interface được bổ sung method, field, ... Thì cũng lại đi sửa hết các proxy class?
Đó chính là điểm hạn chế của static proxy.
**Vậy làm sao để cải thiện điểm hạn chế này?**
Đó chính là gen Proxy class một cách tự động (dyanamic generate)
### Dynamic proxy
Dynamic proxy là proxy class được gen ra trong runtime. Để hiểu sâu hơn về cơ chế gen thì các bạn có thể đọc thêm về cơ chế load class của JVM ở bài trước mình có viết một chút hoặc [JVM in Depth](https://mohibulsblog.netlify.app/posts/java/100daysofjava/day44/) (Mình sẽ cố gắng note về chủ đề này sau =(( lười was)
#### Quá trình xử lí của dynamic proxy sẽ như sau:
1. Client call một hành động nào đó của target object
2. System tạo ra một proxy object trong runtime dựa trên client call.
3. Proxy object gọi một method invoke() để thực hiện hành động cho mỗi lệnh call.
4. Proxy thực hiện hành động call của client tới target object

Để tạo một dynamic proxy chúng ta sử dụng `Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)`
Trong đó:
* **ClassLoader** là nơi để load class dynamic proxy
* **interfaces** là mảng các interfaces muốn implements
* **InvocationHandler** là một InvocationHandler để forward các yêu cầu gọi method từ proxy object tới target object như hình.
### InvocationHandler
Cần phải có một **InvocationHandler** vì để nó foward method call từ proxy đến target object
Nhớ lại mục đích chính của Proxy là điều khiển việc thực thi của một Object ban đầu khác, bằng cách tạo một lớp bọc (Wrap) bên ngoài lớp gốc. Tham số này chính là **thực thể của lớp gốc đó sau khi đã implement interface InvocationHandler**
```java
import java.lang.reflect.*;
/**
* Class VehicleHandler.
*/
public class VehicleHandler implements InvocationHandler {
private IVehicle v;
public VehicleHandler(IVehicle v) {this.v = v;}
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
System.out.println("Vehicle Handler: Invoking " +
m.getName());
return m.invoke(v, args);
}
}
```
ví dụ
```java
Object proxy = Proxy.newProxyInstance(null, new Class[] { IVehicle.class }, handler);
```
Hãy hiểu đoạn lệnh `Proxy.newProxyInstance(...)` thực hiện công việc như sau:
Class Proxy cung cấp phương thức `newProxyInstance` để tạo ra một lớp proxy động **$Proxy0** ở runtime
Sau đó Class **$Proxy0** này tạo một thực thể của nó, gán vào biến proxy.
>Để ý vế trái phép gán, ta có thể thấy biến này có kiểu Object. Vì sao lớp $Proxy0 trên lại tạo ra một instance có kiểu là Object? Lớp này được tạo ra ở giai đoạn runtime, ở giai đoạn lập trình, hay compile, nó chưa được tạo ra, nên bạn sẽ không thể biết được lớp này cụ thể là lớp tên gì, hay lớp nào cả, vậy nên đơn giản nhất, dùng một biến kiểu Object để tham chiếu tới thực thể vừa tạo ra này
Class **$Proxy0** này, sẽ implement các interface trong mảng `new Class[] {...}`
Thực thể **proxy** được tạo ra bao gồm:
* Tất cả các method trong các Interface mà lớp gốc sẽ implement (các method của các phần tử trong mảng kiểu Class - tham số thứ 2 của method `newProxyInstance`, trong ví dụ trên là lớp **IVehicle** nên sẽ có
* start()
* forward()
* stop()
* Tất cả các method được định nghĩa trong lớp Object (toString(), equals(),...).
Còn tham số handler? Như đã nêu ở trên, tham số này chính là lớp gốc sau khi đã implement interface InvocationHandler
Khi có bất kì phương thức nào gọi trên đối tượng proxy, phương thức đó sẽ không được thực thi ngay lập tức, mà hàm `public Object invoke` sẽ được thực thi.
* Phương thức gốc được gọi ban đầu sẽ được "đóng gói" lại, truyền vào phương thức public Object invoke của handler dưới dạng tham số Method m.
* Tham số của phương thức ban đầu cũng sẽ được "đóng gói" và truyền vào dưới dạng tham số thứ 3 Object[] args
* Tham số đầu tiên Object proxy là proxy của handler này.
Phương thức gốc sẽ được thực thi bằng lệnh `m.invoke(target, args)`. Lưu ý phân biệt tên method invoke của interface **InvocationHandler** và method `m.invoke` của đối tượng Method m.
Client access proxy:
```java
import java.lang.reflect.*;
/**
* Class Client3.
* Interacts with a Car Vehicle through a dynamically
* generated VehicleProxy.
*/
public class Client3 {
public static void main(String[] args) {
IVehicle c = new Car("Botar");
ClassLoader cl = IVehicle.class.getClassLoader();
IVehicle v = (IVehicle) Proxy.newProxyInstance(cl,
new Class[] {IVehicle.class}, new VehicleHandler(c));
v.start();
v.forward();
v.stop();
}
}
```
kết quả:
```java
Vehicle Handler: Invoking start
Car Botar started
Vehicle Handler: Invoking forward
Car Botar going forward
Vehicle Handler: Invoking stop
Car Botar stopped
```
Cảm ơn mọi người đã đọc đến tận đây. Đây là một chủ đề mà mình đọc nhiều nguồn nhưng có lẽ vẫn chưa thực sự hiểu rõ hết vì nó khá liên quan đến design pattern nữa. Mình chỉ đọc đến đâu có gắng viết theo ý hiểu đến đó, chắc sẽ có update trong tương lai. Hi vọng có thể có ích đối với mọi người <3
## Nguồn tham khảo:
https://mohibulsblog.netlify.app/posts/java/100daysofjava/day59/#static-proxy
https://web.archive.org/web/20150226062232/http://userpages.umbc.edu/~tarr/dp/lectures/DynProxies-2pp.pdf
https://www.cnblogs.com/whirly/p/10154887.html
https://www.liaoxuefeng.com/wiki/1252599548343744/1264804593397984
https://viblo.asia/p/class-proxy-trong-java-va-cac-ung-dung-yMnKMYvgK7P