JAVA中的代理模式

一、概述

代理模式(Proxy Pattern),简单来说就是一个类代表另一个类的功能,属于结构型设计模式。主要意图是是为一个对象提供一种代理来控制对这个对象的访问。

这样做有一个好处就是:原对象可以只保留核心业务,其他的功能实现,可以放到代理对象中去,确保原对象不会被污染。

举个简单的例子:如果一位明星开演唱会,原对象就是唱歌的这位明星,但是他的经纪人(代理对象)来安排这场演唱会的所有工作,只是其中唱歌环节由这位明星来做而已。那么想邀请明星开演唱会,那么只需要联系他的经纪人即可。这就是一个简单代理。

二、三种代理模式

静态代理

静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类

接口

public interface Sport {
    void run();
}

实现类

public class DoSport implements Sport {
    @Override
    public void run() {
        System.out.println("跑步中。。。。。。。。");
    }
}

代理对象

public class DoSportProxy implements Sport {
    private Sport sport;

    public DoSportProxy(Sport sport) {
        this.sport = sport;
    }

    @Override
    public void run() {
        System.out.println("啦啦啦,我是跑步的小行家");
        sport.run();
    }
}

调用

System.out.println("===========静态代理============");
DoSport doSport = new DoSport();
DoSportProxy sportProxy = new DoSportProxy(doSport);
sportProxy.run();

结果

总结

优点是可以在不修改目标原对象的情况下,对原对象的功能进行拓展。

缺点是接口添加方法,代理对象和原对象都要进行修改。

动态代理

特点:

  • 1.代理对象不需要实现接口,原对象要实现接口
  • 2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象
  • 3.动态代理也叫做:JDK代理,接口代理。

接口和接口的实现对象还采用静态代理中的即可,我们只需对代理对象进行修改

代理对象

public class DynamicProxy implements InvocationHandler {
    private Object object;

    public DynamicProxy(Object object) {
        this.object = object;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("跑步准备,系鞋带");
        Object result = method.invoke(object, args);
        System.out.println("跑步完成,拨打120");
        return result;
    }
}

测试

// 动态代理
System.out.println("===========动态代理============");
Sport sport = new DoSport();
Sport proxySport = (Sport) Proxy.newProxyInstance(Sport.class.getClassLoader(),
        new Class[]{Sport.class},new DynamicProxy(sport));
proxySport.run();

结果

总结
与静态代理相比,省去代理对象实现接口,但是原对象还需实现接口。

CGLIB代理

Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。

Cglib子类代理实现方法:

  • 1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入Spring-core.jar即可.
  • 2.引入功能包后,就可以在内存中动态构建子类
  • 3.代理的类不能为final,否则报错
  • 4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.

原对象

public class Eat {
    public void eatFoot() {
        System.out.println("别吃辣么快。。。。");
    }
}

CGLIB代理对象

第一种

public class CglibProxy implements MethodInterceptor {

    private Object target;

    public CglibProxy() {
    }

    public CglibProxy(Object target) {
        this.target = target;
    }

    public Object getInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) {
        try {
            long beginTime = System.currentTimeMillis();
            System.out.println("方法的名称:" + method.getName());
            Object object = method.invoke(target, objects);
            long endTime = System.currentTimeMillis();
            System.out.println(endTime - beginTime);
            return object;
        } catch (Exception e) {
            System.out.println("噎死的原因: " + e.getMessage());
        }
        return null;
    }
}

第二种

public class CglibEat implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("开饭啦,同志萌。。。。");
        return methodProxy.invokeSuper(o, objects);
    }
}

调用

System.out.println("===========Cglib代理============");
Eat eat = new Eat();
Eat eatProxy = (Eat) new CglibProxy(eat).getInstance();
eatProxy.eatFoot();
System.out.println("===========Cglib代理2============");
Eat cglibEat = (Eat) Enhancer.create(Eat.class, new CglibEat());
cglibEat.eatFoot();

结果

总结

与动态代理相比,原对象和代理对象都不需要实现接口,但是需要导入额外的架包。

常用代理模式是jdk动态代理和CGLIB代理,二者根据自己的喜爱进行选择使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值