java基础——静态代理和动态代理
java代理模式有静态代理和动态代理两种实现方式
一、静态代理
代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。
优点:
可以在不修改目标对象的前提下扩展目标对象的功能。
缺点:
冗余:由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
不易维护:一旦接口增加方法,目标对象与代理对象都要进行修改。
**静态代理的特点**
1、目标角色固定
2、在应用程序执行前就得到目标角色
3、代理对象会增强目标对象的行为
4、有可能存在多个代理 引起"类爆炸"(缺点)
二、动态代理
动态代理利用了 JDK API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。
动态代理又被称为 JDK 代理或接口代理。静态代理与动态代理的区别主要在:
1、静态代理在编译时就已经实现,编译完成后代理类是一个实际的 class 文件
2、动态代理是在运行时动态生成的,即编译完成后没有实际的 class 文件,而是在运行时动态生成类字节码,并加载到 JVM 中
注意:动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。
JDK 中生成代理对象主要涉及两个类,第一个类为 java.lang.reflect.Proxy,通过静态方法 newProxyInstance 生成代理对象,第二个为 java.lang.reflect.InvocationHandler 接口,通过 invoke 方法对业务进行增强
**动态代理的特点**
1、目标对象不固定
2、在应用程序执行时动态创建目标对象
3、代理对象会增强目标对象的行为
三、代码实例
1、创建一个person接口,这个接口就是租客和中介的公共接口,这个接口有一个rentHouse()方法。
public interface Person { //租房 public void rentHouse(); }
2、创建租客Renter类,实现上述接口
public class Renter implements Person{ @Override public void rentHouse() { System.out.println("租客租房成功!"); } }
3、静态代理
1)创建中介类RenterProxy,同样实现Person接口,但是还另外持有一个租客类对象public class RenterProxy implements Person{ private Person renter; public RenterProxy(Person renter){ this.renter = renter; } @Override public void rentHouse() { System.out.println("中介找房东租房,转租给租客!"); renter.rentHouse(); System.out.println("中介给租客钥匙,租客入住!"); } }
2)测试
public class StaticProxyTest { public static void main(String[] args) { Person renter = new Renter(); RenterProxy proxy = new RenterProxy(renter); proxy.rentHouse(); } }
运行结果:
中介找房东租房,转租给租客!
租客租房成功!
中介给租客钥匙,租客入住!
4、动态代理
1)创建RenterInvocationHandler类,这个类实现了InvocationHandler接口,并持有一个被代理类的对象,InvocationHandler中有一个invoke方法,所有执行代理对象的方法都会被替换成执行invoke方法。然后通过反射在invoke方法中执行代理类的方法。在代理过程中,在执行代理类的方法前或者后可以执行自己的操作,这就是spring aop的主要原理。
public class RenterInvocationHandler<T> implements InvocationHandler{ //被代理类的对象 private T target; public RenterInvocationHandler(T target){ this.target = target; } /** * proxy:代表动态代理对象 * method:代表正在执行的方法 * args:代表调用目标方法时传入的实参 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //代理过程中插入其他操作 System.out.println("租客和中介交流"); Object result = method.invoke(target, args); return result; } }
2)测试
public class ProxyTest { public static void main(String[] args) { //创建被代理的实例对象 Person renter = new Renter(); //创建InvocationHandler对象 InvocationHandler renterHandler = new RenterInvocationHandler<Person>(renter); //创建代理对象,代理对象的每个执行方法都会替换执行Invocation中的invoke方法 Person renterProxy = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(),new Class<?>[]{Person.class}, renterHandler); renterProxy.rentHouse(); //也可以使用下面的方式创建代理类对象,Proxy.newProxyInstance其实就是对下面代码的封装 /*try { //使用Proxy类的getProxyClass静态方法生成一个动态代理类renterProxy Class<?> renterProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[]{Person.class}); //获取代理类renterProxy的构造器,参数为InvocationHandler Constructor<?> constructor = renterProxyClass.getConstructor(InvocationHandler.class); //使用构造器创建一个代理类实例对象 Person renterProxy = (Person)constructor.newInstance(renterHandler); renterProxy.rentHouse(); // } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }*/ } }
执行结果:
租客和中介交流
租客租房成功!
参考:
https://blog.csdn.net/zjshuster/article/details/126439883
https://blog.csdn.net/qq_34609889/article/details/85317582
https://blog.csdn.net/longzorg_cn/article/details/129115728
https://blog.csdn.net/m0_67499084/article/details/124810718
一个person接口,这个接口就是租客和中介的公共接口,这个接口有一个rentHouse()方法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
2019-04-07 排序算法的各项比较以及各自的特点