Java动态代理是Java语言中一种非常常用的技术,它可以在运行时自动生成代理类,从而实现对目标对象的动态代理。其主要作用如下:
- AOP编程
动态代理作为AOP编程的重要手段之一,可以在不影响原有业务逻辑的情况下,在目标方法的前后进行一些通用逻辑的处理,例如日志、事务等。
- 拦截不合法调用
有时候我们希望限制某些对象的访问权限,或者对某些方法调用进行拦截,这时候可以使用动态代理进行实现。
下面我们通过两条示例来详细讲解Java动态代理的使用。
示例一:实现动态代理进行日志记录
在这个示例中,我们会创建一个代理类,在调用目标方法之前和之后打印日志,从而实现日志记录的功能。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LogProxy implements InvocationHandler {
private Object target; // 目标对象
/**
* 构造函数
* @param target 目标对象
*/
public LogProxy(Object target) {
this.target = target;
}
/**
* 代理方法
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("[Before] " + method.getName() + " is called");
Object result = method.invoke(target, args); // 调用目标方法
System.out.println("[After] " + method.getName() + " is called");
return result;
}
/**
* 获取代理对象
* @return 代理对象
*/
public Object getProxy() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
}
在这个代理类中,我们通过实现InvocationHandler
接口来自定义代理方法,然后在代理方法内部分别在目标方法调用前后打印日志。getProxy
方法用于生成代理对象。
下面是一个示例代码片段,对Calculator
对象进行代理:
Calculator target = new CalculatorImpl();
LogProxy proxy = new LogProxy(target);
Calculator calculatorProxy = (Calculator)proxy.getProxy();
int result = calculatorProxy.add(1, 2);
我们通过实例化CalculatorImpl
对象,然后创建LogProxy
类的实例并将其作为构造函数的参数传入,最后通过getProxy
方法来获取代理对象。然后就可以像正常调用Calculator
对象一样去调用代理对象。在实际执行过程中,代理类会在目标方法调用前、调用后打印日志。
示例二:实现动态代理限制对对象的访问
在这个示例中,我们会创建一个代理类,拦截对某个对象的访问,从而实现限制访问的功能。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class AccessLimitProxy implements InvocationHandler {
private Object target; // 目标对象
/**
* 构造函数
* @param target 目标对象
*/
public AccessLimitProxy(Object target) {
this.target = target;
}
/**
* 代理方法
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().startsWith("get")) {
System.out.println("Access limit: only set method is allowed");
return null;
} else {
return method.invoke(target, args); // 调用目标方法
}
}
/**
* 获取代理对象
* @return 代理对象
*/
public Object getProxy() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
}
在这个代理类中,我们通过实现InvocationHandler
接口来自定义代理方法。在代理方法中,我们检查当前调用的方法是否为get
开头,如果是,则说明当前对象只能进行设置操作,不可以进行获取操作,于是返回null
。如果不是,则调用目标方法。
下面是一个示例代码片段,对User
对象进行代理:
User user = new User();
AccessLimitProxy proxy = new AccessLimitProxy(user);
User userProxy = (User)proxy.getProxy();
userProxy.setName("Alice"); // 可以设置姓名
userProxy.setAge(18); // 可以设置年龄
String name = userProxy.getName(); // 不允许获取姓名
我们通过实例化User
对象,然后创建AccessLimitProxy
类的实例并将其作为构造函数的参数传入,最后通过getProxy
方法来获取代理对象。然后就可以像正常调用User
对象一样去调用代理对象。在实际执行过程中,代理类会在进行获取姓名时返回null
,即表示访问受到限制。