代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,它允许你提供一个代理对象来控制对实际对象的访问。代理对象通常在客户端和目标对象之间充当中间人,可以在访问实际对象之前或之后执行某些操作。代理模式有多种用途,例如:
- 延迟初始化:只在实际需要时才创建目标对象。
- 访问控制:控制对目标对象的访问权限。
- 日志记录:在方法调用前后记录日志。
- 缓存:在代理类中实现缓存机制,减少目标对象的调用
在java中代理模式分几种常见模式:
1.静态代理
静态代理是指在编译时就确定的代理类。代理类和目标类实现相同的接口,代理类中持有目标类的实例,并在调用方法前后加入自定义逻辑。
简单理解:两个继承父类的兄弟,哥哥和弟弟,哥哥想要找父亲要点钱,叫弟弟去已自己的名义要然后交给哥哥
案例:
public interface BuyInter {
void buyFlower();
}
public class BlackAgency implements BuyInter{
private BuyInter buyInter;
public BlackAgency() {
this.buyInter = new User();
}
@Override
public void buyFlower() {
System.out.println("我是中介");
buyInter.buyFlower();
}
}
public class User implements BuyInter{
@Override
public void buyFlower() {
System.out.println("我买了鲜花");
}
}
public static void main(String[] args) {
// 普通静态代理
BuyInter buyInter = new BlackAgency(); //客户端不出现实际买鲜花的对象
buyInter.buyFlower();
2.动态代理
动态代理是指在运行时动态生成代理类。Java 提供了 java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler 来实现动态代理。
使用 java.lang.reflect.InvocationHandler实现动态代理案例
//必须实现一个接口,和静态代理一样
public interface UserService {
void addUser(String name);
void deleUser();
}
public class UserServerImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("我是添加方法: "+ name);
}
@Override
public void deleUser() {
System.out.println("我是删除方法: ");
}
}
public class LoggingInvocationHandler implements InvocationHandler {
private final Object target;
public LoggingInvocationHandler(Object target) {
this.target = target;
}
//代理商的模式发生了改变
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print("调用方法前=====方法名: " + method.getName());
if (args != null && args.length > 0) {
System.out.println("::参数方法: " + args[0]);
} else {
System.out.println("::没有参数");
}
Object invoke = method.invoke(target,args);
System.out.println("调用方法后=====方法名: "+method.getName());
return invoke;
}
}
//主函数main
// 使用jdk动态代理
UserService userServer = new UserServerImpl();
LoggingInvocationHandler handler = new LoggingInvocationHandler(userServer);
UserService user = (UserService)Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class<?>[]{UserService.class},
handler
);
user.addUser("张三");
user.deleUser();
在代理商方法体中有三个参数,分别是
- Object proxy:代理对象。这个参数是由 Proxy 类动态生成的代理实例。我们可以对其进行操作,但通常在 invoke 方法中并不使用这个参数。如果你需要知道哪个代理调用了该方法,可以用它。
- Method method:被调用的 Method 对象。这个参数描述了被代理对象上正在调用的方法,你可以通过它获取方法的名称、返回类型、参数类型等信息。
- Object[] args:调用方法的参数。这个参数是一个对象数组,包含代理方法调用时传入的所有参数。根据方法的参数类型,可以对这个数组进行适当的处理,例如调用目标对象方法时传递这些参数。
创建代理
- **InvocationHandler **:调用 Proxy.newProxyInstance 方法来创建一个代理对象,并将其强制转换为 Calculator 类型。Proxy.newProxyInstance 方法用于动态创建一个代理类的实例。
- calculator.getClass().getClassLoader(),:这一行代码指定了类加载器。代理类的创建需要使用目标对象的类加载器来加载代理类。这里我们使用 calculator 实例的类加载器。
- new Class<?>[]{Calculator.class}:这一行代码指定了代理类实现的接口。由于我们希望代理对象实现 Calculator 接口,因此传入一个包含 Calculator.class 的数组。
- new CalculatorInvocationHandler(calculator));:最后,我们创建了一个 CalculatorInvocationHandler 实例,并将其传递给 Proxy.newProxyInstance 方法。CalculatorInvocationHandler 类实现了 InvocationHandler 接口,并且包装了 calculator 对象。