静态代理VS动态代理

1.概述

代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

举个例子:
在租房的时候,有的人会通过房东直租,有的人会通过中介租房。中介一般是不是会提供一些额外的服务,这里的中介就相当于代理。

2.静态代理

2.1 具体案列

package com.demo.jtdl;

/**
 * 抽象对象
 */
public interface Subject {
    void getGloryCrystal();
}

package com.demo.jtdl;

/**
 * 真实角色
 */
public class Player implements Subject{
    @Override
    public void getGloryCrystal() {
        System.out.println("玩家获得一颗荣耀水晶");
    }
}

package com.demo.jtdl;

public class TaoBaoProxy implements Subject {
    private Subject subject;

    public TaoBaoProxy(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void getGloryCrystal() {
        System.out.println("提醒玩家扫码上号");
        subject.getGloryCrystal();
        System.out.println("交货收钱");
    }
}

package com.demo.jtdl;

public class Test {
    public static void main(String[] args) {
        TaoBaoProxy proxy=new TaoBaoProxy(new Player());
        proxy.getGloryCrystal();
    }
}

结果
在这里插入图片描述

2.2 静态代理的缺点

静态代理的缺点:一个代理类只能代理一个真实角色,一个系统中的真实角色有很多,此时就必须编写多个对应代理角色,此时就非常麻烦,而且会造成类的臃肿。

3.动态代理

3.1 动态代理实现方式

1.JDK实现:JDK Proxy基于反射
2.第三方类实现:CGLIB基于ASM(一个Java 字节码操作框架)

3.2基于接口的JDK动态代理

1.定义目标类,即被代理的类。
2.通过实现InvocationHandler接口来自定义自己的InvocationHandler;重写invoke方
法,在此方法中定义增强逻辑。
3.通过Proxy.newProxyInstance方法获得代理对象。
4.通过代理对象调用目标方法。

具体的代码实现如下

package com.demo.dtdl;

public interface UserService {
    void read();
}

package com.ruoyi.web.cglib;

public class UserServiceImpl implements UserService{
    @Override
    public void read() {
        System.out.println("去读书");
    }
}
package com.demo.dtdl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {
    private Object target;

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


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        /**
         * 参数一Object proxy:代理的对象
         * 参数二Method method:要运行的方法
         * 参数三Object[] args:调用方法时,传递的实参
         *
         */
        System.out.println("准备书本");
        Object invoke = method.invoke(target, args);
        System.out.println("读书结束");
        return invoke;
    }
}

package com.demo.dtdl;

import java.lang.reflect.Proxy;

public class MyTest {
    public static void main(String[] args) {
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(new UserServiceImpl());
        /**
         * 获取代理对象
         *  参数一:用于指定用哪个类加载器,去加载生成的代理类
         *  参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
         *  参数三:用来指定生成的代理对象要干什么事情
         */
        UserService proxyUserService = (UserService)Proxy.newProxyInstance(
                UserServiceImpl.class.getClassLoader(),
                UserServiceImpl.class.getInterfaces(),
                myInvocationHandler
        );
        proxyUserService.read();
    }
}

结果:
在这里插入图片描述

3.3 基于类的CGLIB动态代理

1.引入CGLIB的相关依赖。
2.定义目标类,即被代理的类。
3.创建代理类实现CGLIB的MethodInterceptor接口,并重写intercept方法,在此方法中定义增强逻辑。
4.使用Enhancer类创建代理对象,设置目标类、回调对象等参数。
5.调用代理对象的方法,实现代理行为。

具体的代码实现如下

           <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>3.3.0</version>
            </dependency>
package com.ruoyi.web.cglib;

public interface UserService {
    void read();
}
package com.ruoyi.web.cglib;

public class UserServiceImpl implements UserService{
    @Override
    public void read() {
        System.out.println("去读书");
    }
}

package com.ruoyi.web.cglib;

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

import java.lang.reflect.Method;

public class CglibInterceptor implements MethodInterceptor {

    private UserService userService;

    public CglibInterceptor(UserService userService) {
        this.userService = userService;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("准备书本");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("读书结束");
        return result;
    }
}

    @org.junit.Test
    public void  test(){
        //得到方法拦截器
        CglibInterceptor cglibInterceptor = new CglibInterceptor(new UserServiceImpl());
        //使用cglib框架生成目标类的子类(代理类)实现增强
        Enhancer enhancer = new Enhancer();
        //设置父类字节码
        enhancer.setSuperclass(UserServiceImpl.class);
        //设置拦截操作
        enhancer.setCallback(cglibInterceptor);

        UserService  userService = (UserService)enhancer.create();
        userService.read();
    }

在这里插入图片描述

3.4 JDK Proxy与CGLIB的区别:

基于接口 vs基于类

1.JDK Proxy 只能代理接口类型,它通过实现指定接口并生成代理对象来实现代理功能。
2.CGLIB 可以代理普通的类,它通过继承目标类,并在子类中重写方法来实现代理。

实现方式:

1.JDK Proxy 是基于反射机制实现的,它利用 Java 的反射 API动态生成代理对象。
2.CGLIB 使用了字节码生成库,直接操作字节码生成代理类。相比于JDK 代理的反射调用,CGLIB 的方法调用更快速。

性能:

1.由于 CGLIB 是直接对字节码进行操作,所以在创建和执行代理对象时通常比 JDK 代理更快速。
2.JDK Proxy 的性能略低,因为它涉及到反射调用的开销。JDK8 版本已经优化,性能与 CGLIB 差不多

库依赖:

1.JDK Proxy 是 Java 标准库的一部分,无需额外的依赖。
2.CGLIB 需要引入相关的第三方库。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值