现在有一个非常流行的名称叫做
面向横切面编程
,也就是AOP(Aspect Oriented Programming),其核心就是采用了动态代理机制,既然这么重要,我们就来看看动 态代理是如何实现的
先上代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义接口
interface UserService {
void save(String username);
}
// 实现接口的类
class UserServiceImpl implements UserService {
@Override
public void save(String username) {
System.out.println("保存用户: " + username);
}
}
class UserServiceProxy implements InvocationHandler {
private final UserService target;
public UserServiceProxy(UserService target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在方法调用前执行额外的逻辑
System.out.println("Before method: " + method.getName());
// 调用目标对象的方法
Object result = method.invoke(target, args);
// 在方法调用后执行额外的逻辑
System.out.println("After method: " + method.getName());
return result;
}
}
public class DynamicProxyDemo {
public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 创建代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class<?>[] { UserService.class },
new UserServiceProxy(userService)
);
// 调用代理对象的方法
proxy.save("Alice");
}
}
输出:
Before method: save
保存用户: Alice
After method: save
这段代码使用了
Proxy.newProxyInstance( UserService.class.getClassLoader(), new Class<?>[] { UserService.class }, new UserServiceProxy(userService) )
方法来创建一个代理对象,以下是每个参数的解释:
-
UserService.class.getClassLoader()
:这是第一个参数,它指定了代理类的类加载器。在这里,
我们使用了
UserService
类的类加载器来加载代理类
。这确保了代理类与目标接口 (
UserService
) 在同一个类加载器中。 -
new Class<?>[] { UserService.class }
:这是第二个参数,它是一个接口数组,
表示代理类需要实现的接口(
注意是实现所有接口
)
。在这里,我们只有一个接口
UserService
,因此传递了一个包含该接口的数组。 -
new UserServiceProxy(userService)
:这是第三个参数,它是一个
InvocationHandler
类型的对象,用于处理代理对象上的方法调用。在这里,我们创建了一个
UserServiceProxy
的实例,
该代理会在调用代理对象上的方法时执行
UserServiceProxy
中定义的逻辑
。
所以,这段代码的目的是创建一个代理对象,这个代理对象实现了
UserService
接口,并且在调用
UserService
接口中的方法时,会委派给
UserServiceProxy
中的
invoke
方法来执行额外的逻辑,如在方法调用前后打印日志等。
这样,我们可以在不修改原始
UserService
实现的情况下,添加额外的行为或功能。
但是以上代码有个问题:
需要为每个接口都创建一个独立的代理类,不够灵活
。所以可以使用Java的动态代理与反射机制来实现一个通用的代理类,而不需要为每个接口都编写一个特定的代理类。
上代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义接口
interface UserService {
void save(String username);
}
// 实现接口的类
class UserServiceImpl implements UserService {
@Override
public void save(String username) {
System.out.println("保存用户: " + username);
}
}
class GenericProxy<T> implements InvocationHandler {
private T target;
public GenericProxy(T target) {
this.target = target;
}
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new GenericProxy<>(target)
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在方法调用前执行额外的逻辑
System.out.println("Before method: " + method.getName());
// 调用目标对象的方法
Object result = method.invoke(target, args);
// 在方法调用后执行额外的逻辑
System.out.println("After method: " + method.getName());
return result;
}
}
public class DynamicProxyDemo {
public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 创建代理对象,不再需要为每个接口编写特定的代理类
UserService proxy = GenericProxy.createProxy(userService);
// 调用代理对象的方法
proxy.save("Alice");
}
}
输出:
Before method: save
保存用户: Alice
After method: save
这种方式可以更灵活地创建代理对象,无需为每个接口都创建一个独立的代理类,从而提高了代码的可维护性和可扩展性。