Java三种代理模式

一、静态代理
静态代理通常用于对原有程序进行功能扩充,在编译的时候就将接口、实现类、代理类都手动完成。

简单例子:
接口:

public interface UserDao {
    void save();
}

实现类:

public class UserImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("保存");
    }
}

代理类:

public class ProxyClass implements UserDao {
    private UserImpl user;
    public ProxyClass(UserImpl user){
        this.user = user;
    }

    @Override
    public void save() {
        System.out.println("开启事务");
        user.save();
        System.out.println("提交事务");
    }
}

测试:

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        UserDao user = new UserImpl();
        ProxyClass proxyClass = new ProxyClass(user);
        proxyClass.save();
    }

}
/*
打印结果:
开启事务
保存
提交事务
*/

可以看到,代理类和被代理类要实现同一个接口,这会产生多余的接口实现,而且当接口增多之后,静态代理就会变得很困难,会显得很臃肿;除此之外,当接口增加方法之后,代理类和被代理类都要进行修改,这不是我们想要的,因此,静态代理从某种程度上来说不够好。

二、动态代理
当我们需要很多代理的时候,如果每一个都是手动去实现,岂不是太难受了,浪费了大量的时间不说,还产生很多冗余代码,此时,动态代理就是一个比较好的选择了。
动态代理,又被称为JDK代理,底层是反射,只在需要代理的地方才会加载,不会再编译期生成.class文件,动态代理要求目标对象必须实现接口,但是代理对象不必实现接口。
动态代理必须用到的JDK API有一个类 java.lang.reflect Proxy,和一个接口 java.lang.reflect InvocationHandler,InvocationHandler接口中只有一个invoke方法(JDK1.8),如下

public Object invoke(Object proxy, Method method, Object[] args) //参数含义分别为代理实例、调用的方法、方法的参数列表
        throws Throwable;

InvocationHandler接口的invoke方法用于处理方法调用并返回结果。

而Proxy类主要动到的是这个静态方法

public static Object newProxyInstance(ClassLoader loader, //类加载器
                                          Class<?>[] interfaces, //目标对象实现的接口
                                          InvocationHandler h) 
        throws IllegalArgumentException

看下动态代理的demo
接口类

public interface UserDao {
    void save();
}

目标对象类

public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("保存");
    }
}

代理对象类

public class ProxyClass {
    private Object target;

    public ProxyClass(Object target){
        this.target = target;
    }

    public Object getProxyInstance(){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("开启事务");
                Object o = method.invoke(target,args);
                System.out.println("关闭事务");
                return null;
            }
        });
    }
}

测试

public class Main {
    public static void main(String[] args){
        UserDao userDao = new UserDaoImpl();  //多态,向上转型
        UserDao userDao1 = (UserDao) new ProxyClass(userDao).getProxyInstance();
        userDao1.save();
    }
}

动态代理实现过程:
因为通过使用接口指向实现类的实例的多态实现方式,可以有效的将具体的实现与调用之间解耦,便于后期修改与维护。具体的说就是我们在代理类中创建一个私有成员变量(private修饰),使用接口来指向实现类的对象,然后在该代理类中的方法中使用这个创建的实例来调用实现类中的相应方法来完成业务逻辑功能。

private Object target;

    public ProxyClass(Object target){
        this.target = target;
    }

上面代码通过这个构造器可以创建代理类的实例,创建的同时还能将具体实现类的实例与之绑定(target指的就是实现类的实例,这个实例需要在测试类中创建并作为参数来创建代理类的实例)。

静态代理中我们测试类中直接创建代理类的对象,使用代理类的对象来调用其方法即可,若是别的接口(这里指的是别的调用方)要调用Iuser的方法,也可以使用此法
动态代理中要复杂的多,首先我们要将之前提到的实现类的实例创建(补充完整),然后利用这个实例作为参数,调用代理来的带参构造器来创建“代理类实例对象”,这里加引号的原因是因为它并不是真正的代理类的实例对象,而是创建真正代理类实例的一个参数,这个实现了InvocationHandler接口的类严格意义上来说并不是代理类,我们可以将其看作是创建代理类的必备中间环节,这是一个调用处理器,也就是处理方法调用的一个类,不是真正意义上的代理类,可以这么说:创建一个方法调用处理器实例。
  下面才是真正的代理类实例的创建,之前创建的”代理类实例对象“仅仅是一个参数

UserDao userDao1 = (UserDao) new ProxyClass(userDao).getProxyInstance();

三、cglib代理
JDK代理在某种程度上来说已经足够完美了,但是它仍有不足之处就是面向接口编程,如果为了实现代理而为每个需要代理的类创建一个毫无意义的接口是很烦的,也是没必要的,于是就产生了cglib代理。cglib代理不必面向接口,在Spring AOP就使用了cglib代理。
CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。CGLIB代理真正的达到了代理类无侵入。
使用cglib代理之前别忘了引入jar包或者maven依赖。
UserDao

public class UserDao{

    public void save() {
        System.out.println("保存");
    }
}
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class ProxyFactory implements MethodInterceptor{

    private Object target;//维护一个目标对象
    public ProxyFactory(Object target) {
        this.target = target;
    }
    
    //为目标对象生成代理对象
    public Object getProxyInstance() {
        //工具类
        Enhancer en = new Enhancer();
        //设置父类
        en.setSuperclass(target.getClass());
        //设置回调函数
        en.setCallback(this);
        //创建子类对象代理
        return en.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开启事务");
        // 执行目标对象的方法
        Object returnValue = method.invoke(target, args);
        System.out.println("关闭事务");
        return null;
    }
}

测试

public class TestProxy {

    @Test
    public void testCglibProxy(){
        //目标对象
        UserDao target = new UserDao();
        //代理对象
        UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();
        //执行代理对象方法
        proxy.save();
    }
}
/*
结果:
开启事务
保存数据
关闭事务
*/

注意:
cglib代理无需实现接口,通过生成类字节码实现代理,比反射稍快,不存在性能问题,但cglib会继承目标对象,需要重写方法,所以目标对象不能为final类。

以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值