静态代理
静态代理需要先定义接口,被代理对象与代理对象一起实现相同的接口,然后通过调用相同的方法来调用目标对象的方法
。
可以看见,代理类无非是在调用委托类方法的前后增加了一些操作。委托类的不同,也就导致代理类的不同。
某公司生产电视机,在当地销售需要找到一个代理销售商。那么客户需要购买电视机的时候,就直接通过代理商购买就可以。
代码示例:
电视机:
public class TV {
private String name;//名称
private String address;//生产地
public TV(String name, String address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return “TV{” +
“name='” + name + ‘’’ +
“, address='” + address + ‘’’ +
‘}’;
}
}
复制代码
创建公司接口:
public interface TVCompany {
/**
-
生产电视机
-
@return 电视机
*/
public TV produceTV();
}
复制代码
公司的工厂生产电视机:
public class TVFactory implements TVCompany {
@Override
public TV produceTV() {
System.out.println(“TV factory produce TV…”);
return new TV(“小米电视机”,“合肥”);
}
}
复制代码
代理商去下单拿货(静态代理类):
public class TVProxy implements TVCompany{
private TVCompany tvCompany;
public TVProxy(){
}
@Override
public TV produceTV() {
System.out.println("TV proxy get order … ");
System.out.println("TV proxy start produce … ");
if(Objects.isNull(tvCompany)){
System.out.println("machine proxy find factory … ");
tvCompany = new TVFactory();
}
return tvCompany.produceTV();
}
}
复制代码
消费者通过代理商拿货(代理类的使用):
public class TVConsumer {
public static void main(String[] args) {
TVProxy tvProxy = new TVProxy();
TV tv = tvProxy.produceTV();
System.out.println(tv);
}
}
复制代码
输出结果:
TV proxy get order …
TV proxy start produce …
machine proxy find factory …
TV factory produce TV…
TV{name=‘小米电视机’, address=‘合肥’}
Process finished with exit code 0
复制代码
小结:
-
优点:
静态代理模式在不改变目标对象的前提下,实现了对目标对象的功能扩展。
-
缺点:
静态代理实现了目标对象的所有方法,一旦目标接口增加方法,代理对象和目标对象都要进行相应的修改,增加维护成本。
如何解决静态代理中的缺点呢?答案是可以使用动态代理方式
动态代理
动态代理具有如下特点:
-
JDK动态代理对象不需要实现接口,只有目标对象需要实现接口。
-
实现基于接口的动态代理需要利用JDK中的API,在JVM内存中动态的构建
Proxy对象
。 -
需要使用到
java.lang.reflect.Proxy
,和其newProxyInstance
方法,但是该方法需要接收三个参数。
注意该方法是在Proxy类中是静态方法,且接收的三个参数依次为:
-
ClassLoader loader
:指定当前目标对象使用类加载器,获取加载器的方法是固定的。 -
Class<?>[] interfaces
:目标对象实现的接口的类型,使用泛型方式确认类型。 -
InvocationHandler h
:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入。
有一天公司增加了业务,出售的商品越来越多,售后也需要更上。但是公司发现原来的代理商,还要再培训才能完成全部的业务,于是就找了另外的
动态代理商B
。代理商B
承诺无缝对接公司所有的业务,不管新增什么业务,均不需要额外的培训即可完成。
代码示例:
公司增加了维修业务:
public interface TVCompany {
/**
-
生产电视机
-
@return 电视机
*/
public TV produceTV();
/**
-
维修电视机
-
@param tv 电视机
-
@return 电视机
*/
public TV repair(TV tv);
}
复制代码
工厂也得把维修业务搞起来:
public class TVFactory implements TVCompany {
@Override
public TV produceTV() {
System.out.println(“TV factory produce TV…”);
return new TV(“小米电视机”,“合肥”);
}
@Override
public TV repair(TV tv) {
System.out.println(“tv is repair finished…”);
return new TV(“小米电视机”,“合肥”);
}
}
复制代码
B代理商 全面代理公司所有的业务。使用Proxy.newProxyInstance
方法生成代理对象,实现InvocationHandler
中的 invoke
方法,在invoke
方法中通过反射调用代理类的方法,并提供增强方法。
public class TVProxyFactory {
private Object target;
public TVProxyFactory(Object o){
this.target = o;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("TV proxy find factory for tv… ");
Object invoke = method.invoke(target, args);
return invoke;
}
});
}
}
复制代码
购买、维修这两个业务 B代理
就可以直接搞定了。后面公司再增加业务,B代理也可以一样搞定。
public class TVConsumer {
public static void main(String[] args) {
TVCompany target = new TVFactory();
TVCompany tvCompany = (TVCompany) new TVProxyFactory(target).getProxy();
TV tv = tvCompany.produceTV();
tvCompany.repair(tv);
}
}
复制代码
感受:
其实我投简历的时候,都不太敢投递阿里。因为在阿里一面前已经过了字节的三次面试,投阿里的简历一直没被捞,所以以为简历就挂了。
特别感谢一面的面试官捞了我,给了我机会,同时也认可我的努力和态度。对比我的面经和其他大佬的面经,自己真的是运气好。别人8成实力,我可能8成运气。所以对我而言,我要继续加倍努力,弥补自己技术上的不足,以及与科班大佬们基础上的差距。希望自己能继续保持学习的热情,继续努力走下去。
也祝愿各位同学,都能找到自己心动的offer。
分享我在这次面试前所做的准备(刷题复习资料以及一些大佬们的学习笔记和学习路线),都已经整理成了电子文档
TVCompany tvCompany = (TVCompany) new TVProxyFactory(target).getProxy();
TV tv = tvCompany.produceTV();
tvCompany.repair(tv);
}
}
复制代码
感受:
其实我投简历的时候,都不太敢投递阿里。因为在阿里一面前已经过了字节的三次面试,投阿里的简历一直没被捞,所以以为简历就挂了。
特别感谢一面的面试官捞了我,给了我机会,同时也认可我的努力和态度。对比我的面经和其他大佬的面经,自己真的是运气好。别人8成实力,我可能8成运气。所以对我而言,我要继续加倍努力,弥补自己技术上的不足,以及与科班大佬们基础上的差距。希望自己能继续保持学习的热情,继续努力走下去。
也祝愿各位同学,都能找到自己心动的offer。
分享我在这次面试前所做的准备(刷题复习资料以及一些大佬们的学习笔记和学习路线),都已经整理成了电子文档
[外链图片转存中…(img-0Je2dWF8-1720123557255)]