Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,28 @@
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.8.2</junit.version>
<lombok.version>1.18.36</lombok.version>
<spring-boot-starter-web.version>3.4.5</spring-boot-starter-web.version>
<guava.version>33.4.0-jre</guava.version>
<commons-lang3.version>3.12.0</commons-lang3.version>
</properties>

<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.4.5</version>
<version>${spring-boot-starter-web.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.4.0-jre</version>
<version>${guava.version}</version>
</dependency>
<!-- JUnit 5 -->
<dependency>
Expand All @@ -49,7 +53,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
<version>${commons-lang3.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/proxy/dynamicproxy/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package proxy.dynamicproxy;

import proxy.service.OrderService;

import java.math.BigDecimal;

public class App {

public static void main(String[] args) {
// jdk dynamic proxy
OrderService proxy = new OrderServiceJdkProxyFactory().createProxy();
proxy.createOrder("user123", "prod456", new BigDecimal("199.99"));
System.out.println();
proxy.cancelOrder("order789");

System.out.println("========================================================");

// cglib dynamic proxy
proxy = new OrderServiceCglibProxyFactory().createProxy();
proxy.createOrder("user123", "prod456", new BigDecimal("199.99"));
System.out.println();
proxy.cancelOrder("order789");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package proxy.dynamicproxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import proxy.service.AuthService;
import proxy.service.LogService;
import proxy.service.OrderService;
import proxy.service.impl.AuthServiceImpl;
import proxy.service.impl.LogServiceImpl;
import proxy.service.impl.OrderServiceImpl;

import java.lang.reflect.Method;

public class OrderServiceCglibProxyFactory {
private final OrderService orderService;
private final AuthService authService;
private final LogService logService;
private final OrderServiceProxyProcess orderServiceProxyProcess;

public OrderServiceCglibProxyFactory() {
this.orderService = new OrderServiceImpl();
this.authService = new AuthServiceImpl();
this.logService = new LogServiceImpl();
this.orderServiceProxyProcess = new OrderServiceProxyProcess();
}

public OrderService createProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(orderService.getClass());
enhancer.setCallback(new OrderServiceMethodInterceptor());
return (OrderService) enhancer.create();
}

private class OrderServiceMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// before
orderServiceProxyProcess.processBefore(method, args, authService, logService);

// invoke real objects
Object result = proxy.invokeSuper(obj, args);

// after
orderServiceProxyProcess.processAfter(method, args, authService, logService);

return result;
}
}
}
50 changes: 50 additions & 0 deletions src/main/java/proxy/dynamicproxy/OrderServiceJdkProxyFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package proxy.dynamicproxy;

import proxy.service.AuthService;
import proxy.service.LogService;
import proxy.service.OrderService;
import proxy.service.impl.AuthServiceImpl;
import proxy.service.impl.LogServiceImpl;
import proxy.service.impl.OrderServiceImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class OrderServiceJdkProxyFactory {
private final OrderService orderService;
private final AuthService authService;
private final LogService logService;
private final OrderServiceProxyProcess orderServiceProxyProcess;

public OrderServiceJdkProxyFactory() {
this.orderService = new OrderServiceImpl();
this.authService = new AuthServiceImpl();
this.logService = new LogServiceImpl();
this.orderServiceProxyProcess = new OrderServiceProxyProcess();
}

public OrderService createProxy() {
return (OrderService) Proxy.newProxyInstance(
orderService.getClass().getClassLoader(),
orderService.getClass().getInterfaces(),
new OrderServiceInvocationHandler()
);
}

private class OrderServiceInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// before
orderServiceProxyProcess.processBefore(method, args, authService, logService);

// invoke real objects
Object result = method.invoke(orderService, args);

// after
orderServiceProxyProcess.processAfter(method, args, authService, logService);

return result;
}
}
}
40 changes: 40 additions & 0 deletions src/main/java/proxy/dynamicproxy/OrderServiceProxyProcess.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package proxy.dynamicproxy;

import proxy.service.AuthService;
import proxy.service.LogService;

import java.lang.reflect.Method;

public class OrderServiceProxyProcess {

public void processBefore(Method method, Object[] args, AuthService authService, LogService logService) {
String methodName = method.getName();
if ("createOrder".equals(methodName)) {
String userId = (String) args[0];
authService.checkPermission(userId, "CREATE_ORDER");
logService.log("Begin to create order", userId, (String) args[1], args[2].toString());
} else if ("cancelOrder".equals(methodName)) {
String orderId = (String) args[0];
String userId = getUserIdByOrderId(orderId);
authService.checkPermission(userId, "CANCEL_ORDER");
logService.log("Start canceling orders", userId, orderId);
}
}

public void processAfter(Method method, Object[] args, AuthService authService, LogService logService) {
String methodName = method.getName();
if ("createOrder".equals(methodName)) {
String userId = (String) args[0];
logService.log("Order creation completed", userId, (String) args[1], args[2].toString());
} else if ("cancelOrder".equals(methodName)) {
String orderId = (String) args[0];
String userId = getUserIdByOrderId(orderId);
logService.log("Order cancellation completed", userId, orderId);
}
}

private String getUserIdByOrderId(String orderId) {
return STR."user_\{orderId.hashCode()}"; // Mock
}

}
5 changes: 5 additions & 0 deletions src/main/java/proxy/service/AuthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package proxy.service;

public interface AuthService {
void checkPermission(String userId, String permission);
}
5 changes: 5 additions & 0 deletions src/main/java/proxy/service/LogService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package proxy.service;

public interface LogService {
void log(String action, String... params);
}
9 changes: 9 additions & 0 deletions src/main/java/proxy/service/OrderService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package proxy.service;

import java.math.BigDecimal;

public interface OrderService {
void createOrder(String userId, String productId, BigDecimal amount);

void cancelOrder(String orderId);
}
11 changes: 11 additions & 0 deletions src/main/java/proxy/service/impl/AuthServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package proxy.service.impl;

import proxy.service.AuthService;

public class AuthServiceImpl implements AuthService {
@Override
public void checkPermission(String userId, String permission) {
System.out.printf("[validate permission] user[%s] permission[%s]\n", userId, permission);
//do sth...
}
}
12 changes: 12 additions & 0 deletions src/main/java/proxy/service/impl/LogServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package proxy.service.impl;

import proxy.service.LogService;

import java.util.Arrays;

public class LogServiceImpl implements LogService {
@Override
public void log(String action, String... params) {
System.out.printf("[log record] operation[%s] params%s\n", action, Arrays.toString(params));
}
}
19 changes: 19 additions & 0 deletions src/main/java/proxy/service/impl/OrderServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package proxy.service.impl;

import proxy.service.OrderService;

import java.math.BigDecimal;

public class OrderServiceImpl implements OrderService {
@Override
public void createOrder(String userId, String productId, BigDecimal amount) {
System.out.printf("create order: user[%s] product[%s] amount[%s]\n", userId, productId, amount);
// do sth...
}

@Override
public void cancelOrder(String orderId) {
System.out.printf("cancel order: [%s]\n", orderId);
// do sth...
}
}
14 changes: 14 additions & 0 deletions src/main/java/proxy/staticproxy/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package proxy.staticproxy;

import java.math.BigDecimal;

public class App {
public static void main(String[] args) {
OrderServiceStaticProxy proxy = new OrderServiceStaticProxy();

proxy.createOrder("user123", "prod456", new BigDecimal("199.99"));
System.out.println();
proxy.cancelOrder("order789");
}

}
52 changes: 52 additions & 0 deletions src/main/java/proxy/staticproxy/OrderServiceStaticProxy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package proxy.staticproxy;

import proxy.service.AuthService;
import proxy.service.LogService;
import proxy.service.OrderService;
import proxy.service.impl.AuthServiceImpl;
import proxy.service.impl.LogServiceImpl;
import proxy.service.impl.OrderServiceImpl;

import java.math.BigDecimal;

public class OrderServiceStaticProxy {
private final OrderService orderService;
private final AuthService authService;
private final LogService logService;

public OrderServiceStaticProxy() {
this.orderService = new OrderServiceImpl();
this.authService = new AuthServiceImpl();
this.logService = new LogServiceImpl();
}

public void createOrder(String userId, String productId, BigDecimal amount) {
// before
authService.checkPermission(userId, "CREATE_ORDER");
logService.log("Begin to create order", userId, productId, amount.toString());

// invoke real objects
orderService.createOrder(userId, productId, amount);

// after
logService.log("Order creation completed", userId, productId, amount.toString());
}

public void cancelOrder(String orderId) {
// before
String userId = getUserIdByOrderId(orderId);
authService.checkPermission(userId, "CANCEL_ORDER");
logService.log("Start canceling orders", userId, orderId);

// invoke real objects
orderService.cancelOrder(orderId);

// after
logService.log("Order cancellation completed", userId, orderId);
}

private String getUserIdByOrderId(String orderId) {
return STR."user_\{orderId.hashCode()}"; // Mock
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package Singleton;
package singleton;

import java.io.Serial;
import java.io.Serializable;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package Singleton;
package singleton;

public enum EnumSingleton {
INSTANCE
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package Singleton;
package singleton;

public final class StaticInnerClassSingleton {
private StaticInnerClassSingleton() {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package singleton;

import Singleton.DoubleCheckedLockingSingleton;
import common.utils.SerializationUtils;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import static org.junit.jupiter.api.Assertions.*;

Expand Down Expand Up @@ -32,7 +32,7 @@ public void testReflectionAttack() {
DoubleCheckedLockingSingleton instance1 = DoubleCheckedLockingSingleton.getInstance();

//Attempt to create a second instance through reflection
assertThrows(RuntimeException.class, () -> {
assertThrows(InvocationTargetException.class, () -> {
DoubleCheckedLockingSingleton instance2 = constructor.newInstance();
}, "An exception should be thrown to prevent reflection from creating an instance");

Expand Down