Java-基础-动态代理

前言:

最近看了一节黑马讲师阿玮老师的Java基础课 -动态代理,现将笔记和总结汇总。因为是结合自己平时记笔记和看笔记的习惯,再加上一些通俗的语言。所以,不喜勿喷,不喜勿喷,不喜勿喷。

问题抛出:

1.为什么需要代理?
2.代理长什么样?
3.Java通过什么来保证代理的样子?

第一个问题:为什么需要代理?


  代理可以在不改变原先方法代码的基础上,无侵入式的给对象增强其他的功能。

  其调用模式为:调用者-》代理-》对象

对象只负责实现自身的业务逻辑,其他需要实现的业务则需要请一个对象帮忙实现,这个帮忙的对象就是代理对象。这样调用者想要调用目标对象之前,就需要先调用该目标对象的代理,然后再通过代理去调用目标对象。如果调用者直接调用对象的话,那这个对象只会实现自身的业务,而其它的业务就不会实现。

第二个问题:代理长什么样?


  代理里面就是对象要被代理的方法

  代理类Proxy在java.lang.reflect包下,该类中有一个静态方法newProxyInstance,就是用来创建代理,该方法中有三个参数,其作用分别为:

  • 参数一:用于指定哪个类加载器,去加载生成的字节码文件
    
  • 参数二:指定接口,用于指定生成的代理长什么样,也就是需要代理对象中的方法
    
  • 参数三:用来指定生成的代理对象需要干什么事情

其中参数三通过匿名内部类的方式实现具体的业务逻辑。

第三个问题:Java通过什么来保证代理的样子


  通过接口保证,后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法

代码实现:

废话不说上代码:

被代理的对象:

创建一个JavaBean对象,也就是目标对象,该对象有一个属性为name,还有两个方法 ,分别为sing(唱歌)和dance(跳舞)。

public class BigStar implements Star {
    private String name;

    public BigStar() {
    }

    public BigStar(String name) {
        this.name = name;
    }

    /**
     * 唱歌
     * @param songName
     * @return
     */
    public String sing(String songName) {
        System.out.println(this.name + "正在唱歌" + songName);
        return "谢谢";
    }

    /**
     * 跳舞
     */
    public void dance() {
        System.out.println(this.name + "正在跳舞");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}
 指定接口:

创建一个接口,里面则是需要被代理的方法

public interface Star {
    public String sing(String songName);

    public void dance();
}
代理对象:

创建代理对象,通过createProxy方法创建代理,其中通过代理类Proxy调用newProxyInstance方法,再传入三个参数:

ProxyUtil.class.getClassLoader()作用:加载生成的字节码文件

new Class[]{Star.class}作用:指定接口

new InvocationHandler()作用:通过匿名内部类的方式指定生成的代理对象需要干什么事情

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


public class ProxyUtil {

    /**
     * 创建代理
     * @param bigStar 被代理的对象
     */
    public static Star createProxy(BigStar bigStar) {
        Star star =(Star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),//参数一:用于指定哪个类加载器,去加载生成的字节码文件
                new Class[]{Star.class},//参数二:指定接口,这些接口用于指定生成的代理长什么样,也就是需要代理对象中的方法
                //参数三:用来指定生成的代理对象需要干什么事情
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /*
                        * 参数一:代理的对象(一般不用管)
                        * 参数二:需要运行的方法
                        * 参数三:方法的参数
                        * */
                        //判断被调用的方法名字,跟去方法名走对应的逻辑
                        if("sing".equals(method.getName())) {
                            System.out.println("--------开始调用方法" + method.getName() + "--------");
                            System.out.println("明星准备唱歌了...");
                        }else  if("dance".equals(method.getName())) {
                            System.out.println("--------开始调用方法" + method.getName() + "--------");
                            System.out.println("明星开始跳舞了...");
                        }
                        return method.invoke(bigStar, args);
                    }
                }
        );
        return star;
    }
}
测试类:
public class Test {
    public static void main(String[] args) {
        //获取代理对象
        BigStar bigStar = new BigStar("鸡哥");
        Star proxy = ProxyUtil.createProxy(bigStar);

        //调用方法
        String res = proxy.sing("《你好,我有一个毛衫》");
        System.out.println(res);

        proxy.dance();

    }
}
运行结果:

执行流程:

讲完整体逻辑之后,我们来看一下具体的执行流程吧:

首先,由Test(调用者)类先调用代理获取代理对象,再由代理对象调用sing方法,在方法的底层会自动调用匿名内部类中的invoke方法,将sing方法和参数歌名分别传递给method和args对象。这时,invoke方法中通过if语句判断需要执行的对应的业务,之后method调用其invoke方法通过反射机制调用并传参给BigStar类中的sing方法,最后通过return将字符串“谢谢”返回给res打印出来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值