动态代理

动态代理思想的分析


我们想在已经可以运行的代码中添加右侧的2行代码

在种情况下如果我们直接修改,被称为侵入式修改,很可能和导致我们的所以代码都崩溃

我们又不能修改原有的代码又要插入新的功能,我们该怎么办呢?




中介怎么知道要去代理唱歌和跳舞这些方法的呢?


我们将需要代理的行为写在接口里面,代理方法和鸡哥都需要实现接口

动态代理的实现(代理实现)

对于为什么代理方和被代理方为什么都要实现接口的理解(接口里面都是被代理的行为)?

1.代理方实现了接口保证了这些行为都会被代理
2.被代理方法实现了这个接口保证了他里面一定拥有这些行为
总结:这为精准代理提供了保证

在中java专门提供了一个方法用于生成代理的对象

我们想调用代理的sing方法,在该方法的底层会自动调用invoke方法


当我们准备调用sing方法 invoke中的方法对象就是sing的对象,传入的就是sing传入的参数(鸡你太美)。并开始下面的invoke的方法题,执行sing的准备工作


接着回去找大明星唱歌,把“只因你太美”传递给大明星中的sing方法,然后sing方法开始执行

在大明星中的sing方法中将“谢谢进行返回”返回到代理类中,然后代理类进行返回,返回到测试类中

大明星类

package com.cook.trend;
//实现动态代理
//BigStar重写接口中的所有方法
public class BigStar implements Star{
    private String name;

    public BigStar() {
    }

    public BigStar(String name)  {
        this.name = name;
    }
    //唱歌
    @Override
    public String sing(String name){
        System.out.println(this.name+"正在唱"+name);
        return "谢谢观众";
    }
    //跳舞
    @Override
    public void dance(){
        System.out.println(this.name+"正在跳舞");
    }
    //
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    public String toString() {
        return "BigStar{name = " + name + "}";
    }

    public static void main(String[] args) {

    }
}

创建代理类

package com.cook.trend;

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


/*
需求:
    外面的人想要大明星唱一首歌
    1.获取代理对象
       代理对象= ProxyUtil.creatProxy(大明星的对象)
    2.再调用代理的唱歌方法
        代理对象.唱歌方法
            在调用代理的唱歌方法时,会在内部调用invoke方法进行准备工作
 */


/*
* 类的作用:
*   创建一个代理
 */
public class ProxyUtil {

    /*
    *方法的作用:
    *   给一个明星的对象,创建一个代理
    *形参:被代理的明星对象
    *返回值:给明星创建的代理
    *
     */
    public static Star createProxy(BigStar bigStar){
        /*
        java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:
        public static Object newProxyInstance (ClassLoader loader,Class<?>[]interfaces,InvocationHander h)
        参数一:用于指定哪个类加载器,去加载生成的代理类
        参数二:指定接口,这些接口用于指定生成的代理长什么样,也就是有那些方法
        参数三:用来指定生成的代理对象要干什么事情(意思就是代理需要干的准备工作)
         */
        final 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 {
                            /*
                            *参数一:代理的对象
                            *参数二:要运行的方法 sing
                            *参数三:调用sing 方法时,传递的实参
                             */
                        //1.判断需要代理的行为并准备进行准备工作
                        if("sing".equals(method.getName())){
                            System.out.println("准备话筒,收钱");
                        }else if("dance".equals(method.getName())){
                            System.out.println("准备场地,收钱");

                        }
                            //2.去找大明星跳舞(调用大明星的跳舞的行)
                      return   method.invoke(bigStar,args);

                    }
                }
        );

        return star;
    }
}

代理接口

package com.cook.trend;
//书写想要被代理的行为
public interface Star {
    //1.唱歌
    public String sing(String name);
    //2.跳舞
    public void dance();
}

测试类

package com.cook.trend;

public class Test {
    public static void main(String[] args) {
        /*
        需求:
             外面的人想要大明星唱一首歌
             实现过程:
                1.获取代理的对象
                    代理对象 = ProUtil.crateProxy(大明星对象)
                 2.再调用代理的唱歌方法
                    代理对象.唱歌的方法("只因你太美")
         */
        //1.获取代理对象
        BigStar bigStar = new BigStar("鸡哥");
        final Star star = ProxyUtil.createProxy(bigStar);
         //2.调用代理的唱歌方法
        final String result = star.sing("只因你太美");
        System.out.println(result);
         //3.调用跳舞的方法
        star.dance();
    }
}

运行结果

posted @ 2023-03-24 21:17  一往而深,  阅读(21)  评论(0编辑  收藏  举报