Java面向对象_29 动态代理


静态代理

了解了代理模式,直接看代码:
在这里插入图片描述

/**
 * @Author: Forward Seen
 * @CreateTime: 2022/03/31 15:10
 * @Description:
 */
public interface TargetService {
    /**
     * 接口中默认的方法,该案例目的是要增强该方法的功能
     */
    void service();
}
/**
 * @Author: Forward Seen
 * @CreateTime: 2022/03/31 15:10
 * @Description: 目标对象
 * 代理的目的是增强该类的对象的功能,我们称作该类的对象叫目标对象
 */
public class Target implements TargetService{
    @Override
    public void service() {
        System.out.println("The program is running!");
    }
}
/**
 * @Author: Forward Seen
 * @CreateTime: 2022/03/31 15:20
 * @Description: 这里的代理对象TargetProxy目的是用于增强Target对象的功能,可以理解为给
 * Target的方法添加代码
 */
public class TargetProxy implements TargetService{

    private TargetService target;

    public TargetProxy(TargetService target){
        this.target = target;
    }

    /**
     * 增强后的方法
     * 在原方法前增加代码称作前置增强
     * 在原方法后增加代码称作后置增强
     * 很明显,代理对象的方法,其实就是在目标对象上做一些扩展
     */
    @Override
    public void service() {
        System.out.println("前置增强。。。");
        target.service();
        System.out.println("后置增强。。。");
    }
}
public class Test {
    public static void main(String[] args) {
        //正常使用目标对象的方法
        Target target = new Target();
        target.service();
        System.out.println("------------------------------");
        //使用代理对象
        TargetProxy targetProxy = new TargetProxy(target);
        targetProxy.service();
    }
}

在这里插入图片描述
代理类实现了目标类的方法的扩展,像这样,代理模式中的所有角色(代理对象、目标对象、目标对象的接口)在编译期就确定好了的,就是静态代理,而动态代理是在程序运行时增强代码的功能。

静态代理可以避免创建一个大对象,使用一个小对象就能代替真实的大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。

动态代理

前面介绍了静态代理,虽然静态代理模式很好用,但是静态代理还是存在一些局限性的, 比如使用静态代理模式需要程序员手写很多代码,这个过程是比较浪费时间和精力的。一旦 需要代理的类中方法比较多,或者需要同时代理多个对象的时候,这无疑会增加很大的复杂度。

动态代理中的代理类并不要求在编译期就确定,而是可以在运行期动态生成,从而实现对目标对象的代理功能。

反射是动态代理的一种实现方式。

动态代理主要有两种实现方式:

  • jdk代理:基于接口的动态代理技术
    在这里插入图片描述
    目标对象的方法需要被增强,这个目标对象必须有接口,在运行期间要基于这个接口动态地生成代理对象,而这个代理对象是基于接口的,目标接口有什么方法,目标对象也就有什么方法,而动态代理生成的对象也有对应的方法,这样就保证代理对象跟目标对象有相同的方法。
  • cglib代理:基于父类的动态代理技术
    在这里插入图片描述
    cglib代理没有了接口,cglib技术是为目标对象动态地生成代理对象或者说生成子对象,子对象的有目标对象的全部方法,且子对象的功能更加强大,注意这不是继承,而是代理对象是基于目标对象的,它是在程序运行时动态生成的。调用的时候调用的是代理对象,而代理对象内部是调用目标对象,只不过在调用的时候有其他代码的介入,进而增强目标对象。

使用JDK实现动态代理

public interface TargetService {
    /**
     * 接口中默认的方法,该案例目的是要增强该方法的功能
     */
    void service();
}

/**
 * @Author: Forward Seen
 * @CreateTime: 2022/03/31 15:10
 * @Description: 目标对象
 * 代理的目的是增强该类的对象的功能,我们称作该类的对象叫目标对象
 */
public class Target implements TargetService {
    @Override
    public void service() {
        System.out.println("The program is running!");
    }
}
public class TargetProxy {

    public static Object getInstance(TargetService target){
        //增强对象
        Advice advice = new Advice();
        /**
         * @param 1.目标对象的类加载器
         * @param 2.目标对象相同的接口字节码对象数组
         * @param
         * @return 动态生成的代理对象,用TargetService父接口接收
         */
        TargetService proxyTarget = (TargetService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 调用代理对象的任何方法 实质执行的都是invoke方法
                     * @param proxy 代理对象
                     * @param method 代理的方法
                     * @param args 方法的参数
                     * @return 方法的返回值
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        advice.before(); //前置增强
                        Object invoke = method.invoke(target, args); //执行目标方法
                        advice.after(); //后置增强
                        return invoke;
                    }
                }
        );
        return proxyTarget;
    }
}
    public static void main(String[] args) {
        //目标对象
        Target target = new Target();
        //创建代理对象
        TargetService proxyTarget = (TargetService) TargetProxy.getInstance(target);
        //调用代理对象的增强方法
        proxyTarget.service();
    }

在这里插入图片描述

使用cglib实现动态代理

与jdk方式不一样的是,cglib不需要接口了,只要目标对象,代理对象就类似于目标对象的子类。
cglib属于第三方框架,我们的Spring框架底层用的就是cglib,所以我们可以导入Spring的核心jar包来作为实现环境。
在这里插入图片描述
这次目标对象不需要接口了哦

/**
 * @Author: Forward Seen
 * @CreateTime: 2022/03/31 15:10
 * @Description: 目标对象
 */
public class Target {
    public void service() {
        System.out.println("The program is running!");
    }
}

代理对象的实现几乎与上面一致

public class TargetProxy {
    public static Target getInstance(Target target){
        //1.创建增强器
        Enhancer enhancer = new Enhancer();
        //2.设置父类(目标)
        enhancer.setSuperclass(Target.class);
        //3.设置回调
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("前置增强。。");
                Object invoke = method.invoke(target, objects);
                System.out.println("后置增强。。");
                return invoke;
            }
        });
        //4.创建代理对象
        return (Target)enhancer.create();
    }
}

使用代理对象

public class Test {
    @org.junit.Test
    public void testCglib(){
        Target target = TargetProxy.getInstance(new Target());
        target.service();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值