动态代理的理解

一:动态代理和静态代理的区别

静态代理:了解设计模式中的代理模式的童鞋应该都知道,如果想要生成代理类,需要让代理类和被代理类实现同一个接口,并且在代理类中添加被代理类的引用,代理类方法实现中添加代理逻辑,并决定是否调用被代理类方法,这种通过硬编码的方式指定代理类与被代理类的方式,叫静态代理。可以明显看出,静态代理类与被代理类是强耦合的,如果要代理100个类,你就得写100个代理类
动态代理:其实动态代理与静态代理的本质一样,最终程序运行时都需要生成一个代理对象实例,通过它来完成相关增强以及业务逻辑,只不过静态代理需要硬编码的方式指定,而动态代理则是以动态方式生成代理(有编译时操作字节码生成的方式、运行时通过反射、字节码生成的方式)。动态生成的好处很明显,代理逻辑与业务逻辑是互相独立的,没有耦合,代理1个类或100个类要做的事情没有任何区别

说到耦合,必须把AOP拿来说道说道:传统面向对象思想中,如果想要实现功能复用,要么继承、要么引用,无论哪种方式,对代码都有一定的侵入性,耦合无可避免,侵入性啥意思?简单来说:如果你想要用它增强你程序的功能,你必须改动你的程序代码,那它就具有侵入性。如果只有一点两点需要增强还好说,如果大量的功能点需要被增强,工作量就会很大,代码也不太优雅。想象一下,如果你对外公开了一系列的接口,现在领导说了,接口要加权限控制。在哪加?最笨的当然就是写个程序验证的逻辑,然后每个接口都拿来调用一遍。这也正是面向对象思想的短板,在要为程序新增一些通用功能时,只能通过耦合的方式才能进行。AOP正是为此而生,AOP旨在通过一种无耦合的方式来为程序带来增强。而动态代理,就是AOP实现方式中的一种

二:动态代理相关的类

Proxy:生成动态代理的实例
InvocationHandler:
每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。(invoke()方法可以通过反射加载被代理的类的方法)

三:代码实现

1:接口

package com.wyj.demo03;

public interface UserService {
    void deleteUser();
    void addUser();
    void updateUser();
    void selectUser();
}

2:实现类

package com.wyj.demo03;

import com.wyj.demo03.UserService;

public class UserServiceImp implements UserService {
    @Override
    public void deleteUser() {
        System.out.println("删除一个用户");
    }
    @Override
    public void addUser() {
        System.out.println("增加一个用户");
    }
    @Override
    public void updateUser() {
        System.out.println("修改一个用户");
    }
    @Override
    public void selectUser() {
        System.out.println("查询一个用户");
    }
}

3:生成动态代理类的程序

package com.wyj.demo03;

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

//生成代理类的程序
public class ProxyInvocationHandler implements InvocationHandler {

   //被代理的类
   private Object target;

   //设置要代理的类(这个就是我们具体要代理的类)
   public void setTarget(Object target) {
        this.target = target;
   }

   //生成得到代理类(这里我们返回的是一个接口 也就是被代理的类 所实现的接口)
   public Object getProxy() {
       return Proxy.newProxyInstance(target.getClass().getClassLoader(),
               target.getClass().getInterfaces(),this);
   }

    /**
     *
     * @param proxy :被代理的对象
     * @param method:被代理的对象的方法
     * @param args :被代理的对象的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       log(method.getName());
       Object invoke = method.invoke(target, args);//在反射中通过 方法名.invoke(类名);传统方法中 类名.方法名();
        return invoke;
    }

    //增加需求 打印日志
    public void log(String msg) {
        System.out.println("调用了"+msg);
    }
}

其中的参数解析
类加载机制:
首先我们要了解一下类的加载机制,在每创建一个Java类时,都会生产一个.class文件,在内存中对应也会生成一个class对象,来表示该类的类型信息,我们可以用.class来获取这个类的所有信息,也可以通过getClass()方法来读取这个类的所有信息,比如getClass().getInterfaces()获取类的接口信息等。在Java类加载时,要通过一个类加载器classloader来将生成的Java类加载到JVM中才能执行。理解了类的加载机制后,我们再看代码中的newProxyInstance方法,在这个方法中,我们将被代理对象传进来后.
在这里插入图片描述

在Proxy.newProxyInstance方法中,共有三个参数:
1、target.getClass().getClassLoader()目标对象通过getClass方法获取类的所有信息后,调用getClassLoader()方法来获取类加载器。获取类加载器后,可以通过这个类型的加载器,在程序运行时,将生成的代理类加载到JVM即Java虚拟机中,以便运行时需要!
2、target.getClass().getInterfaces()获取被代理类的所有接口信息,以便于生成的代理类可以具有代理类接口中的所有方法。
3、this:我们使用动态代理是为了更好的扩展,比如在方法之前做什么,之后做什么等操作。这个时候这些公共的操作可以统一交给代理类去做。这个时候需要调用实现了InvocationHandler 类的一个回调方法。由于自身实现了这个方法,所以将this传递过去。
(也就是在这个ProxyInvocationHandler 类自身中实现一些需求的方法)

4:实现过程

package com.wyj.demo03;

public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImp serviceImp = new UserServiceImp();
        //代理角色不存在
        ProxyInvocationHandler handler = new ProxyInvocationHandler();
        //设置被代理的对象
        handler.setTarget(serviceImp);
        //得到代理类对象(这个是我们返回是一个接口,我们的被代理类是实现的一个接口)
        UserService proxy = (UserService) handler.getProxy();
        proxy.deleteUser();
    }
}

实现过程的解析:
代理类是在运行时创建的实现指定的接口列表(称为代理接口)的类 。
代理实例(proxy)是代理类的一个实例。 每个代理实例(proxy)都有一个关联的调用处理程序对象(handler),它实现接口InvocationHandler 。
通过其代理接口之一的代理实例上的方法,调用将被分派到实例调用处理程序的invoke方法,传递代理实例,标识调用方法的java.lang.reflect.Method对象以及包含参数的类型为Object的数组。 调用处理程序适当地处理编码方法调用,并且返回的结果将作为方法在代理实例上调用的结果返回。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天向上的菜鸡杰!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值