动态代理是指在程序运行时动态地创建一个代理对象,代理对象可以替代被代理者进行一些操作,而且可以在不改变被代理者的情况下扩展代理对象的功能。
在编程语言中,动态代理是使用反射机制来实现的。通常情况下,代理对象是实现了与被代理对象相同的接口的一个类。通过调用代理对象的方法,代理对象会在调用被代理对象的方法之前或之后加入一些逻辑,从而实现对被代理对象的控制和扩展。
动态代理在实际应用中非常广泛,例如在AOP(面向切面编程)中常用于对方法进行添加切面逻辑;在RPC(远程过程调用)中可用于实现远程方法调用;在ORM(对象关系映射)中可用于实现对数据库操作的封装等等。
在Java中,动态代理是一种运行时创建代理对象的机制,代理对象的行为由代理类动态生成,并在运行时被指定。动态代理会自动将所有接口方法的调用分派到一个处理器(InvocationHandler)上。处理器负责将方法调用转发给实际对象,并可以进行一些预处理或后处理操作。
Proxy类是Java标准库中的一个类,用于创建代理对象。通过Proxy类,我们可以使用Java动态代理机制创建一个实现指定接口的动态代理类对象。
在使用动态代理时,需要先定义一个接口,该接口包含需要代理的方法。然后创建一个InvocationHandler对象实现对代理方法的处理。最后使用Proxy类的静态方法newProxyInstance()生成代理对象。
动态代理常用于AOP(面向切面编程)和RPC(远程过程调用)等场景中。
方法名 | 返回值类型 | 描述 |
---|---|---|
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) | Object | 创建一个实现指定接口的代理对象 |
isProxyClass(Class<?> cl) | booleam | 判断一个类是否是动态代理类 |
getProxyClass(ClassLoader loader, Class<?>… interfaces) | Class<?> | 获取指定接口的动态代理类 |
示例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface IUserManager {
void addUser(String username, String password);
}
class UserManager implements IUserManager {
@Override
public void addUser(String username, String password) {
System.out.println("添加用户:" + username + ", 密码:" + password);
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("正在执行方法 " + method.getName() + "...");
return method.invoke(target, args);
}
}
public class Main {
public static void main(String[] args) {
IUserManager userManager = new UserManager();
MyInvocationHandler invocationHandler = new MyInvocationHandler(userManager);
IUserManager userManagerProxy = (IUserManager)Proxy.newProxyInstance(
userManager.getClass().getClassLoader(),
userManager.getClass().getInterfaces(),
invocationHandler);
userManagerProxy.addUser("admin", "123456");
}
}
输出结果:
正在执行方法 addUser...
添加用户:admin, 密码:123456
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface IUserManager {
void addUser(String username, String password);
void deleteUser(String username);
}
class UserManager implements IUserManager {
@Override
public void addUser(String username, String password) {
System.out.println("添加用户:" + username + ", 密码:" + password);
}
@Override
public void deleteUser(String username) {
System.out.println("删除用户:" + username);
}
}
class LoggerImpl implements InvocationHandler {
private Object target;
public LoggerImpl(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置日志");
Object result = method.invoke(target, args);
System.out.println("后置日志");
return result;
}
}
public class Main {
public static void main(String[] args) {
IUserManager userManager = new UserManager();
LoggerImpl loggerImpl = new LoggerImpl(userManager);
IUserManager userManagerProxy = (IUserManager)Proxy.newProxyInstance(
userManager.getClass().getClassLoader(),
userManager.getClass().getInterfaces(),
loggerImpl);
userManagerProxy.addUser("admin", "123456");
userManagerProxy.deleteUser("testUser");
}
}
输出结果:
前置日志
添加用户:admin, 密码:123456
后置日志
前置日志
删除用户:testUser
后置日志
在这个例子中,我们使用动态代理添加了日志功能,通过调用Proxy.newProxyInstance()
方法,创建了一个IUserManager
接口的代理对象userManagerProxy
,并在LoggerImpl
类中实现了前置日志和后置日志的输出。当我们调用userManagerProxy
的方法时,实际上是调用了invoke()
方法,在该方法中处理了前置日志、调用实际对象的方法以及后置日志。