java 静态代理和动态代理

什么是代理

从字面意思来说,代理就是代替处理的意思。
从程序层面来说,代理就是代替某个程序,处理某个事情。

静态代理

场景1: 小明需要买基金。

public class Main {
    public static void main(String[] args) {
        Person xiaoming= new XiaoMing();
        boolean isSuccess = xiaoming.buy();//小明去买基金
        System.out.println("结果"+(isSuccess?"基金大涨":"被割韭菜"));
    }
}
interface Person{
    boolean buy();
}
class XiaoMing implements Person{
    @Override
    public boolean buy() {
        System.out.println("我是小明,我要买基金");
        return false;
    }
}

运行结果

我是小明,我要买基金
结果被割韭菜

场景2: 小明刚买了不久的基金,连跌几天,被割了韭菜,这时候小明找到了一个基金经理,让基金经理帮自己管理基金。

我们新增一个 基金经理的类,并传入一个被代理的人

public class Main {
    public static void main(String[] args) {
        Person fundManager = new FundManager(new XiaoMing()) ;//小明被基金经理代理了
        boolean isSuccess = fundManager.buy();//基金经理去买基金
        System.out.println("结果"+(isSuccess?"基金大涨":"被割韭菜"));
    }
}
interface Person{
    boolean buy();
}
class XiaoMing implements Person{
    @Override
    public boolean buy() {
        System.out.println("我是小明,我要买基金");
        return false;
    }
}
class FundManager implements Person{
    Person person;
    FundManager(Person person){
        this.person = person;
    }
    @Override
    public boolean buy() {
        person.buy();
        System.out.println("我是基金经理,我帮我的用户赚钱");
        return true;
    }
}

运行结果

我是小明,我要买基金
我是基金经理,我帮我的用户赚钱
结果基金大涨

场景3: 小明已经通过基金经理赚了不少钱,他需要卖出一部分,并且开始进行基金定投。

package cn.enncy.scs;
public class Main {
    public static void main(String[] args) {
        Person fundManager = new FundManager(new XiaoMing()) ;
        fundManager.buy();
        fundManager.sell();
        fundManager.autoInvestment();
    }
}
interface Person{
    boolean buy();
    boolean sell();
    boolean autoInvestment();
}
class XiaoMing implements Person{
    @Override
    public boolean buy() {
        System.out.println("我是小明,我要买基金");
        return false;
    }

    @Override
    public boolean sell() {
        System.out.println("我是小明,我要出售基金");
        return false;
    }

    @Override
    public boolean autoInvestment() {
        System.out.println("我是小明,我要定投基金");
        return false;
    }
}
class FundManager implements Person{
    Person person;
    FundManager(Person person){
        this.person = person;
    }
    @Override
    public boolean buy() {
        person.buy();
        System.out.println("我是基金经理,我帮我的用户赚钱");
        return true;
    }

    @Override
    public boolean sell() {
        return person.sell();
    }

    @Override
    public boolean autoInvestment() {
        return person.autoInvestment();
    }
}


结果

我是小明,我要买基金
我是基金经理,我帮我的用户赚钱
我是小明,我要出售基金
我是小明,我要定投基金

我们可以看到,其实定投出售,根本不需要经过基金经理进行代理,自己进行这个操作就行了,所以代码非常冗余,如果不经过基金经理又会被割韭菜。

那要怎么实现,当买基金的时候让基金经理代理,不需要买基金的时候,其他操作自己执行 ?
这时候,动态代理 的优势就体现出来了

动态代理

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

public class Main {
    public static void main(String[] args) {
        PersonProxy personProxy = new PersonProxy(new XiaoMing());
        Person fundManager = personProxy.createProxy();
        fundManager.buy();
        fundManager.sell();
        fundManager.autoInvestment();
    }
}
interface Person{
    boolean buy();
    boolean sell();
    boolean autoInvestment();
}
class XiaoMing implements Person{
    @Override
    public boolean buy() {
        System.out.println("我是小明,我要买基金");
        return false;
    }
    @Override
    public boolean sell() {
        System.out.println("我是小明,我要出售基金");
        return false;
    }
    @Override
    public boolean autoInvestment() {
        System.out.println("我是小明,我要定投基金");
        return false;
    }
}
class PersonProxy implements InvocationHandler {
    Object target;
    PersonProxy(Object target){
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        System.out.println("方法"+method.getName()+"已经被我代理");
        if("buy".equals(method.getName())){
            method.invoke(target, args);
            System.out.println("我是代理,我将帮你买基金");
        }
        return true;
    }
    public <T> T createProxy(){
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}

结果

方法buy已经被我代理
我是小明,我要买基金
我是代理,我将帮你买基金
方法sell已经被我代理
方法autoInvestment已经被我代理
  • target : 被代理的对象
  • InvocationHandler: jdk 动态代理类
  • invoke: 由jdk动态代理的方法,
    • proxy : jdk 代理类
    • method : 当前被代理类的方法
    • args 当前被代理类的方法参数
  • Proxy.newProxyInstance : 代理类的实例化方法
    • target.getClass().getClassLoader() : 目标类的 ClassLoader
    • target.getClass().getInterfaces() : 目标类的 interfaces
    • this : 代理类对象

动态代理-代理接口

想要实例化接口,但是又不创建实例类的骚操作,具体实现方法完全通过动态代理自由实现。

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

public class Main {

    public static void main(String[] args) {
        Person personProxy = PersonProxy.createProxy(Person.class);
        personProxy.say();
    }

}

interface Person{
    void say();
}

class PersonProxy implements InvocationHandler {
    Class target;
    PersonProxy(Class target){
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我就是"+method.getName()+"函数的方法体!");
        return null;
    }
    public static  <T> T createProxy(Class clazz){
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(),new Class[]{clazz}, new PersonProxy(clazz));
    }
}

结果

我就是say函数的方法体!

是不是非常 amazing !!!
根本没有任何的实例类!但是同样可以调用方法!可以调侃的说接口自己实现了自己 😂😂😂


  1. 这里要注意不能使用 method.invoke(target, args); 因为你根本没有任何实例类,和方法体,你调用这句话只会报错。
  2. Proxy.newProxyInstance 的参数完全不同,第二个参数是要传入 对象的 interfaces接口,而 new Class[]{clazz} 则是吧 clazz 当做接口参数传递。

总结:

代理的好处

1.代理类不影响原先代码执行,面向切面编程,典型的AOP。
2.代理类可以重新返回一个新的值,作为原先的函数的值。

动态代理的应用
  1. 更精确的日志系统,可以使用包扫描,将每个类每个属性,方法全部进行动态代理,这样,从程序开始到结束,所有函数调用等细节都能被打印出来。
  2. mybatis 的核心,注解开发,各种SQL语句注解,当调用的时候,通过动态代理,获取被代理方法上注解中的sql语句,然后执行。可以用动态代理做一个简易的 mybatis 试试。
  3. 当你遇到一个很复杂的需求,不得不修改别人的代码,但这往往会导致不可预计的bug的时候,通过动态代理,对返回值进行处理即可。这样既避免了修改原有代码,又完成了新的需求。

还有很多应用这里不一一列举了。

静态代理的缺点
  1. 当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式:只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大
    新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类
  2. 当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值