首页 > Java > java教程 > 正文

Java中动态代理和静态代理的示例分析

WBOY
发布: 2023-05-05 21:37:08
转载
1531 人浏览过

    0、代理模式

    为什么要学习代理模式?这是SpringAOP的底层【SpringAOP和SpringMVC】

    代理模式的分类:

    • 静态代理

    • 动态代理

    1、静态代理

    静态代理中,我们对目标对象的每个方法的增强都是手动完成的(后面会具体演示代码_),非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(_需要对每个目标类都单独写一个代理类)。 实际应用场景非常非常少,日常开发几乎看不到使用静态代理的场景。

    角色分析:

    • 抽象角色:一般会使用接口或者抽象类来解决

    • 真实角色:被代理的角色

    • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作

    • 客户:访问代理对象的人!

    代码步骤:

    1、接口

    public interface Rent {
        public void rent();
    }
    登录后复制
    登录后复制

    2、真实角色

    //房东
    public class Host implements Rent {
        public void rent() {
            System.out.println("房东要租房子");
        }
    }
    登录后复制

    3、代理角色

    public class Proxy implements Rent{
        private Host host;
        public Proxy() {
        }
        public Proxy(Host host) {
            this.host = host;
        }
        public void rent(){
            seeHouse();
            host.rent();
            fare();
        }
        //看房
        public void seeHouse(){
            System.out.println("中介带你看房");
        }
        //收中介费
        public void fare(){
            System.out.println("中介收费");
        }
    }
    登录后复制

    4、客服端访问代理角色

    public class Client {
        public static void main(String[] args) {
            Host host = new Host();
            //代理,代理角色一般会有附属操作!
            Proxy proxy = new Proxy(host);
            proxy.rent();
        }
    }
    登录后复制

    代理模式的好处:

    • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务

    • 公共也就交给代理角色!实现业务的分工!

    • 公共业务发生扩展的时候,方便集中管理!

    缺点:

    一个真实角色会产生一个代理角色;从JVM角度来看,静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的class文件。

    2、 加深理解

    AOP,的底层代理模式

    Java中动态代理和静态代理的示例分析

    3、动态代理

    • 动态代理和静态代理角色一样

    • 动态代理的代理类是动态生成的,不是我们直接写好的!

    • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理

      • 基于接口——JDK动态代理

      • 基于类:cglib动态代理

      • java字节码实现:javasist

    需要了解两个类:Proxy: 代理类,InvocationHandler : 调用处理程序

    从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

    //Proxy是生成动态代理类,提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
    //InvocationHandler-- invoke 调用处理程序并返回接口, 是由代理实例的调用处理程序实现的接口 。
    登录后复制

    动态代理的好处:

    • 可以使真实角色的操作更加纯粹!不用去关系一些公共的业务

    • 公共也就交给代理角色!实现

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){
    }
    登录后复制

    1.loader :类加载器,用于加载代理对象。

    2.interfaces : 被代理类实现的一些接口;

    3.h : 实现了 InvocationHandler 接口的对象;

    要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。

    public interface InvocationHandler {
        Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    }
    登录后复制

    1.proxy :动态生成的代理类

    2.method : 与代理类对象调用的方法相对应

    3.args : 当前 method 方法的参数

    动态代理的例子

    1、定义接口

    public interface Rent {
        public void rent();
    }
    登录后复制
    登录后复制

    2、实现租房的接口

    public class Host implements Rent {
        @Override
        public void rent() {
            System.out.println("房东要租房");
        }
    }
    登录后复制

    3、定义一个JDK动态代理类

    public class DebugInvocationHandler implements InvocationHandler {
        /**
         * 代理类中的真实对象
         */
        private final Object target;
        public DebugInvocationHandler(Object target){
            this.target = target;
        }
        /**
         * 当你使用代理对象调用方法的时候实际会调用到这个方法
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //调用方法前
            System.out.println("before method" + method.getName());
            Object res = method.invoke(target, args);
            //调用方法后
            System.out.println("after method" + method.getName());
            return res;
        }
    }
    登录后复制

    invoke() 方法: 当我们的动态代理对象调用原生方法的时候,最终实际上调用到的是 invoke() 方法,然后 invoke() 方法代替我们去调用了被代理对象的原生方法。

    4、获取代理对象的工厂类

    public class JdkProxyFactory {
        public static Object getProxy(Object target){
            return Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    new DebugInvocationHandler(target)
            );
        }
    }
    登录后复制

    getProxy() :主要通过Proxy.newProxyInstance()方法获取某个类的代理对象

    5、实际使用

    public static void main(String[] args) {
            //Rent rent = new Host();
            //Rent rentProxy= (Rent) Proxy.newProxyInstance(rent.getClass().getClassLoader(), rent.getClass().getInterfaces(),new DebugInvocationHandler(rent));
            Rent rentProxy = (Rent)JdkProxyFactory.getProxy(new Host());
            rentProxy.rent();
        }
    登录后复制

    运行上述代理的输出

    before methodrent
    房东要租房
    after methodrent

    以上是Java中动态代理和静态代理的示例分析的详细内容。更多信息请关注PHP中文网其他相关文章!

    相关标签:
    来源:yisu.com
    本站声明
    本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
    热门教程
    更多>
    最新下载
    更多>
    网站特效
    网站源码
    网站素材
    前端模板
    关于我们 免责声明 Sitemap
    PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!