浅谈 Java 动态代理的实现
什么是动态代理?
Java 中的代理分为静态代理和动态代理两种。静态代理需要事先写好代理类,通过程序员手动编写的方式,代理对象和目标对象之间的关系就已经确定了。而动态代理是在程序运行时动态生成的代理对象,不需要事先写好代理类。动态代理可以根据目标对象动态地生成代理对象,无需为每个目标对象都编写代理类,增强代码的可重用性。
实现步骤
动态代理的实现需要以下步骤:
- 定义一个接口,为某个类的接口创建一个代理对象。
- 创建实现 InvocationHandler 接口的类,它必须实现 invoke() 方法,该方法在代理对象中被调用。
- 实现 jdk 动态代理的 Proxy 类,它提供了创建动态代理类的静态方法,同时可以实现多个接口。
示例一
假设有一个接口计算器(Calculator),它有一个 add() 方法,实现两个数字相加。我们使用动态代理为其创建代理对象,实现输出日志的功能。
public interface Calculator {
int add(int a, int b);
}
public class CalculatorHandler implements InvocationHandler {
private Calculator calculator;
public CalculatorHandler(Calculator calculator) {
this.calculator = calculator;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before method executed.");
Object result = method.invoke(calculator, args);
System.out.println("after method executed.");
return result;
}
}
public class Demo {
public static void main(String[] args) {
Calculator calculator = new CalculatorImpl();
Calculator proxy = (Calculator) Proxy.newProxyInstance(
Calculator.class.getClassLoader(),
new Class[]{Calculator.class},
new CalculatorHandler(calculator));
int result = proxy.add(1, 2);
System.out.println("result: " + result);
}
}
此时,我们调用代理对象的 add() 方法,控制台将打印出 before method executed. 和 after method executed.,表示代理对象的方法已经被调用。
示例二
假设有一个接口用户服务(UserService),它提供了查找用户和更新用户信息的方法。我们使用动态代理为其创建代理对象,实现缓存用户信息的功能,即先从缓存中查找用户信息,若找不到,则从数据库中查找用户信息并更新缓存,若找到则直接返回缓存中的用户信息。
public interface UserService {
User findUserById(int id);
void updateUser(User user);
}
public class UserServiceHandler implements InvocationHandler {
private UserService userService;
private Map<Integer, User> cache = new HashMap<>();
public UserServiceHandler(UserService userService) {
this.userService = userService;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Integer userId = (Integer) args[0];
if ("findUserById".equals(method.getName())) {
User user = cache.get(userId);
if (user != null) {
return user;
}
user = (User) method.invoke(userService, args);
cache.put(userId, user);
return user;
} else if ("updateUser".equals(method.getName())) {
method.invoke(userService, args);
User user = (User) args[0];
cache.put(user.getId(), user);
return null;
} else {
return method.invoke(userService, args);
}
}
}
public class Demo {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new UserServiceHandler(userService));
User user1 = proxy.findUserById(1);
System.out.println("user1: " + user1);
User user2 = proxy.findUserById(1);
System.out.println("user2: " + user2);
user1.setName("John");
proxy.updateUser(user1);
User user3 = proxy.findUserById(1);
System.out.println("user3: " + user3);
}
}
此时,我们调用代理对象的 findUserById() 方法,第一次输出将从数据库中获取用户信息,第二次输出将从缓存中获取用户信息,第三次输出将从数据库中重新获取用户信息并更新缓存,验证了缓存用户信息的功能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈Java动态代理的实现 - Python技术站