Skip to content

Commit 51bdbe2

Browse files
committed
The Proxy Pattern
1 parent f0087f3 commit 51bdbe2

17 files changed

+305
-9
lines changed

pom.xml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,28 @@
1414
<maven.compiler.release>21</maven.compiler.release>
1515
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1616
<junit.version>5.8.2</junit.version>
17+
<lombok.version>1.18.36</lombok.version>
18+
<spring-boot-starter-web.version>3.4.5</spring-boot-starter-web.version>
19+
<guava.version>33.4.0-jre</guava.version>
20+
<commons-lang3.version>3.12.0</commons-lang3.version>
1721
</properties>
1822

1923
<dependencies>
2024
<dependency>
2125
<groupId>org.projectlombok</groupId>
2226
<artifactId>lombok</artifactId>
23-
<version>1.18.36</version>
27+
<version>${lombok.version}</version>
2428
<scope>provided</scope>
2529
</dependency>
2630
<dependency>
2731
<groupId>org.springframework.boot</groupId>
2832
<artifactId>spring-boot-starter-web</artifactId>
29-
<version>3.4.5</version>
33+
<version>${spring-boot-starter-web.version}</version>
3034
</dependency>
3135
<dependency>
3236
<groupId>com.google.guava</groupId>
3337
<artifactId>guava</artifactId>
34-
<version>33.4.0-jre</version>
38+
<version>${guava.version}</version>
3539
</dependency>
3640
<!-- JUnit 5 -->
3741
<dependency>
@@ -49,7 +53,7 @@
4953
<dependency>
5054
<groupId>org.apache.commons</groupId>
5155
<artifactId>commons-lang3</artifactId>
52-
<version>3.12.0</version>
56+
<version>${commons-lang3.version}</version>
5357
<scope>test</scope>
5458
</dependency>
5559
</dependencies>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package proxy.dynamicproxy;
2+
3+
import proxy.service.OrderService;
4+
5+
import java.math.BigDecimal;
6+
7+
public class App {
8+
9+
public static void main(String[] args) {
10+
// jdk dynamic proxy
11+
OrderService proxy = new OrderServiceJdkProxyFactory().createProxy();
12+
proxy.createOrder("user123", "prod456", new BigDecimal("199.99"));
13+
System.out.println();
14+
proxy.cancelOrder("order789");
15+
16+
System.out.println("========================================================");
17+
18+
// cglib dynamic proxy
19+
proxy = new OrderServiceCglibProxyFactory().createProxy();
20+
proxy.createOrder("user123", "prod456", new BigDecimal("199.99"));
21+
System.out.println();
22+
proxy.cancelOrder("order789");
23+
}
24+
25+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package proxy.dynamicproxy;
2+
3+
import org.springframework.cglib.proxy.Enhancer;
4+
import org.springframework.cglib.proxy.MethodInterceptor;
5+
import org.springframework.cglib.proxy.MethodProxy;
6+
import proxy.service.AuthService;
7+
import proxy.service.LogService;
8+
import proxy.service.OrderService;
9+
import proxy.service.impl.AuthServiceImpl;
10+
import proxy.service.impl.LogServiceImpl;
11+
import proxy.service.impl.OrderServiceImpl;
12+
13+
import java.lang.reflect.Method;
14+
15+
public class OrderServiceCglibProxyFactory {
16+
private final OrderService orderService;
17+
private final AuthService authService;
18+
private final LogService logService;
19+
private final OrderServiceProxyProcess orderServiceProxyProcess;
20+
21+
public OrderServiceCglibProxyFactory() {
22+
this.orderService = new OrderServiceImpl();
23+
this.authService = new AuthServiceImpl();
24+
this.logService = new LogServiceImpl();
25+
this.orderServiceProxyProcess = new OrderServiceProxyProcess();
26+
}
27+
28+
public OrderService createProxy() {
29+
Enhancer enhancer = new Enhancer();
30+
enhancer.setSuperclass(orderService.getClass());
31+
enhancer.setCallback(new OrderServiceMethodInterceptor());
32+
return (OrderService) enhancer.create();
33+
}
34+
35+
private class OrderServiceMethodInterceptor implements MethodInterceptor {
36+
@Override
37+
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
38+
// before
39+
orderServiceProxyProcess.processBefore(method, args, authService, logService);
40+
41+
// invoke real objects
42+
Object result = proxy.invokeSuper(obj, args);
43+
44+
// after
45+
orderServiceProxyProcess.processAfter(method, args, authService, logService);
46+
47+
return result;
48+
}
49+
}
50+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package proxy.dynamicproxy;
2+
3+
import proxy.service.AuthService;
4+
import proxy.service.LogService;
5+
import proxy.service.OrderService;
6+
import proxy.service.impl.AuthServiceImpl;
7+
import proxy.service.impl.LogServiceImpl;
8+
import proxy.service.impl.OrderServiceImpl;
9+
10+
import java.lang.reflect.InvocationHandler;
11+
import java.lang.reflect.Method;
12+
import java.lang.reflect.Proxy;
13+
14+
public class OrderServiceJdkProxyFactory {
15+
private final OrderService orderService;
16+
private final AuthService authService;
17+
private final LogService logService;
18+
private final OrderServiceProxyProcess orderServiceProxyProcess;
19+
20+
public OrderServiceJdkProxyFactory() {
21+
this.orderService = new OrderServiceImpl();
22+
this.authService = new AuthServiceImpl();
23+
this.logService = new LogServiceImpl();
24+
this.orderServiceProxyProcess = new OrderServiceProxyProcess();
25+
}
26+
27+
public OrderService createProxy() {
28+
return (OrderService) Proxy.newProxyInstance(
29+
orderService.getClass().getClassLoader(),
30+
orderService.getClass().getInterfaces(),
31+
new OrderServiceInvocationHandler()
32+
);
33+
}
34+
35+
private class OrderServiceInvocationHandler implements InvocationHandler {
36+
@Override
37+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
38+
// before
39+
orderServiceProxyProcess.processBefore(method, args, authService, logService);
40+
41+
// invoke real objects
42+
Object result = method.invoke(orderService, args);
43+
44+
// after
45+
orderServiceProxyProcess.processAfter(method, args, authService, logService);
46+
47+
return result;
48+
}
49+
}
50+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package proxy.dynamicproxy;
2+
3+
import proxy.service.AuthService;
4+
import proxy.service.LogService;
5+
6+
import java.lang.reflect.Method;
7+
8+
public class OrderServiceProxyProcess {
9+
10+
public void processBefore(Method method, Object[] args, AuthService authService, LogService logService) {
11+
String methodName = method.getName();
12+
if ("createOrder".equals(methodName)) {
13+
String userId = (String) args[0];
14+
authService.checkPermission(userId, "CREATE_ORDER");
15+
logService.log("Begin to create order", userId, (String) args[1], args[2].toString());
16+
} else if ("cancelOrder".equals(methodName)) {
17+
String orderId = (String) args[0];
18+
String userId = getUserIdByOrderId(orderId);
19+
authService.checkPermission(userId, "CANCEL_ORDER");
20+
logService.log("Start canceling orders", userId, orderId);
21+
}
22+
}
23+
24+
public void processAfter(Method method, Object[] args, AuthService authService, LogService logService) {
25+
String methodName = method.getName();
26+
if ("createOrder".equals(methodName)) {
27+
String userId = (String) args[0];
28+
logService.log("Order creation completed", userId, (String) args[1], args[2].toString());
29+
} else if ("cancelOrder".equals(methodName)) {
30+
String orderId = (String) args[0];
31+
String userId = getUserIdByOrderId(orderId);
32+
logService.log("Order cancellation completed", userId, orderId);
33+
}
34+
}
35+
36+
private String getUserIdByOrderId(String orderId) {
37+
return STR."user_\{orderId.hashCode()}"; // Mock
38+
}
39+
40+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package proxy.service;
2+
3+
public interface AuthService {
4+
void checkPermission(String userId, String permission);
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package proxy.service;
2+
3+
public interface LogService {
4+
void log(String action, String... params);
5+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package proxy.service;
2+
3+
import java.math.BigDecimal;
4+
5+
public interface OrderService {
6+
void createOrder(String userId, String productId, BigDecimal amount);
7+
8+
void cancelOrder(String orderId);
9+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package proxy.service.impl;
2+
3+
import proxy.service.AuthService;
4+
5+
public class AuthServiceImpl implements AuthService {
6+
@Override
7+
public void checkPermission(String userId, String permission) {
8+
System.out.printf("[validate permission] user[%s] permission[%s]\n", userId, permission);
9+
//do sth...
10+
}
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package proxy.service.impl;
2+
3+
import proxy.service.LogService;
4+
5+
import java.util.Arrays;
6+
7+
public class LogServiceImpl implements LogService {
8+
@Override
9+
public void log(String action, String... params) {
10+
System.out.printf("[log record] operation[%s] params%s\n", action, Arrays.toString(params));
11+
}
12+
}

0 commit comments

Comments
 (0)