jdk动态代理

简介

动态代理是对静态代理的一种优化,静态代理当需要代理的接口增加时,代理类需要实现多个接口,导致代码冗余不符合开闭原则,jdk中,使用
1、Proxy:提供静态方法newProxyInstance()创建动态代理的class和实例(只管生成对象)
2、InvocationHandler:invoke()方法增强服务(只管对象需要做的事)
实现动态代理

代码实现

接口类:

1、AFactory

/**
 * 生成自定义型号电脑
 */
public interface AFactory {
    void productComputer(String modeNumber);
}

2、BFactory

/**
 * 生成自定义大小汽车
 */
public interface BFactory {
    void productCar(Integer size);
}

接口实现类(被代理类):

1、CarFactory


public class CarFactory implements BFactory {
    @Override
    public void productCar(Integer size) {
        System.out.println("生产汽车大小为 = [" + size + "]");
    }
}

2、ComputerFactory

public class ComputerFactory implements AFactory {
    @Override
    public void productComputer(String modeNumber) {
        System.out.println("生产电脑型号为 = [" + modeNumber + "]");
    }
}

处理器实现类(实现InvocationHandler)

此处,我将Proxy.newProxyInstance()获取代理类也放到该类中

/**
 * 相当于一个代购公司
 * 1、Proxy:提供静态方法newProxyInstance()创建动态代理的class和实例(只管生成对象)
 * 2、InvocationHandler:invoke()方法增强服务(只管对象需要做的事)
 *
 * 动态代理:代理类是没有.java文件的,是由jvm在内存中直接生成.class文件
 */
public class InvocationCompany implements InvocationHandler {
    //被代理对象
    private Object factory;

    public InvocationCompany(Object factory) {
        this.factory = factory;
    }


    public void setFactory(Object factory) {
        this.factory = factory;
    }


    /**
     * 通过Proxy.newProxyInstance生成真正的代理对象,其名字为$proxy***
     * Proxy.newProxyInstance(类加载器,被代理类实现接口,InvocationHandler)
     */
    public Object getProxy(){
        return Proxy.newProxyInstance(factory.getClass().getClassLoader(),
                factory.getClass().getInterfaces(),this);
    }

    /**
     *
     * @param proxy 真正生成的代理对象,其名字为$proxy***,
     * 不要在invoke直接输出proxy,否则会不停递归,产生栈溢出StackOverflowError错误
     * @param method 方法
     * @param args 方法传参
     * @return 方法返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doBefore();
        String methodName= method.getName();//获取方法名
        System.out.println(" methodName = [" + methodName + "]");
        Object obj=method.invoke(factory,args);//通过反射获取到需要执行的方法,obj为方法执行返回值
        doAfter();
        return null;
    }

    //前置增强
    public void doBefore(){
        System.out.println("为你找到最好的工厂");
    }

    //后重增强
    public void doAfter(){
        System.out.println("精美包装,三年保修");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        ComputerFactory computerFactory=new ComputerFactory();
        CarFactory carFactory=new CarFactory();

        InvocationCompany invocationCompany=new InvocationCompany(computerFactory);

        /**
         * 此处只能用接口转换,如果用实现类强转则会报无法类型强转错误
         * 因为接口实现类是一个具体的类,他对接口的方法已经做了实现。
         * 而动态代理本质上就是在运行时实现接口,生成接口实现类,实现接口方法,所以只能强转接口,不能强转子类
         */
        AFactory computerFactoryProxy=(AFactory)invocationCompany.getProxy();
        computerFactoryProxy.productComputer("A");
        System.out.println("=================================");
        invocationCompany.setFactory(carFactory);
        BFactory carCompanyProxy=(BFactory)invocationCompany.getProxy();
        carCompanyProxy.productCar(1000);

    }
}

总结

jdk代理实现无论是静待代理还是动态代理,都要求代理类和被代理了实现同一个接口
在这里插入图片描述
不同的是在静态代理中,代理类是我们创建的一个包含被代理类的实现接口的类,但在动态代理中,这个代理类是由jvm在内存中帮我们创建的一个以$proxy**命名的类,它没有java文件
在这里插入图片描述
jvm字节生成class文件,调用类加载器生成class类
那这个类如何知道我们代理需要实现那个接口呢?是通过
Proxy.newProxyInstance(类加载器,被代理类实现接口,InvocationHandler)的第二个参数,将被代理类的实现接口传回;
那怎么知道我们需要增强哪个方法呢?
是同过将我们所实现的InvocationHandler实现类传回,赋值给Proxy中的InvocationHandler属性,再调用我们所实现的invoke方法便得知所要增强的方法(invoke中是通过反射获取到实现的方法)
注意

不要在invoke直接输出proxy,否则会不停递归,产生栈溢出StackOverflowError错误,因为这个proxy就是我们实际上生成的proxy代理类,再invoke中调用它就等与自己递归自己,不停递归
改参数实际上是jvm再
其作用:只有proxy 实例在InvocationHandler 实现类里加载才能产生第二个参数method (静态代码块是虚拟机加载类的时候执行的参考

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值