Java-代理

前言

本文主要说代理的三种实现方式,不涉及概念性内容

1. 静态代理

案例

已知车站具有售票功能,同时网上售票软件也可以进行售票。既网上售票软件代理车站售票功能。

共同的接口

车票接口,定义售票方法,不提供实现,仅供外部调用

public interface Ticket {

    /**
     * 售票
     * @return void
     * 时间:2018年4月25日
     */
    public void sellTicket();
}

实现类

车站类,实现车票接口中的售票方法

public class Station implements Ticket{

    @Override
    public void sellTicket() {
        System.out.println("正在出售车票");
    }

}

代理类

网上售票代理类,注入被代理对象车站类,并实现车票接口的售票方法

public class NetworkProxy implements Ticket{

    private Station station = new Station();

    @Override
    public void sellTicket() {
        station.sellTicket();
        this.success();
    }

    public void success() {
        System.out.println("出票");
    }

}

客户类

测试网上售票代理执行

public class ProxyTest {
    public static void main(String[] args) {
        NetworkProxy networkProxy = new NetworkProxy();
        networkProxy.sellTicket();
    }
}

从上面的例子我们可以看出,在代理类中,我们注入了被代理对象,同时实现了功能接口,从而实现了代理。并且在被代理对象执行方法前后可以添加一些需要的功能。
而这就是静态代理,静态代理的弊端就是,倘若我们想实现其他类的代理类,则需要为其另建代理类,这会显得十分麻烦。由此引出了动态代理。

2. 动态代理

在静态代理中,我们需要在代理类中手动注入需要的被代理对象,而动态代理是在程序运行中动态生成我们需要的被代理对象。

案例

已知车站具有售票功能,同时网上售票软件也可以进行售票。既网上售票软件代理车站售票功能。

功能接口

public interface Ticket2 {

    /**
     * 售票
     * @return void
     * 时间:2018年4月25日
     */
    public void sellTicket();
}

被代理对象

public class Station2 implements Ticket2{

    @Override
    public void sellTicket() {
        System.out.println("正在出售车票");
    }

}

代理对象

实现java.lang.reflect包下的InvocationHandler接口,通过构造方法将被代理对象注入,并重写invoke()方法

public class DynamicProxy implements InvocationHandler{

    /**
     * 被代理的对象
     */
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = method.invoke(target, args);
        this.success();
        return object;
    }

    private void success() {
        System.out.println("出票中");
    }

}

测试类

public class DynamicProxyTest {

    public static void main(String[] args) {
        Ticket2 ticket = new Station2();

        DynamicProxy dynamicProxy = new DynamicProxy(ticket);

        //创建代理对象
        Ticket2 proxy = (Ticket2)Proxy.newProxyInstance(
            //功能接口实现类的类加载器
            ticket.getClass().getClassLoader(),
            //功能接口实现类的所有接口
            ticket.getClass().getInterfaces(), 
            //动态代理对象
            dynamicProxy
        );

        proxy.sellTicket();
    }
}

当然,我们可以对上面的动态代理进行一定的优化。

代理对象


public class DynamicProxy implements InvocationHandler{

    /**
     * 被代理的对象
     */
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = method.invoke(target, args);
        this.success();
        return object;
    }

    private void success() {
        System.out.println("出票中");
    }

     /**
     * 获取代理对象
     * @return T
     * 时间:2018年4月25日
     */
    @SuppressWarnings("unchecked")
    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(
            target.getClass().getClassLoader(), 
            target.getClass().getInterfaces(), 
            this
        );
    }
}

测试类

public class DynamicProxyTest {

    public static void main(String[] args) {
        Ticket2 ticket2 = new Station2();
        DynamicProxy dynamicProxy = new DynamicProxy(ticket2);
        Ticket2 proxy = dynamicProxy.getProxy();
        proxy.sellTicket();
    }
}

至此,java动态代理就结束了。但是,代理就这样结束了吗?并没有。
!!重点!!!

java动态代理,只能为接口创建代理,返回的代理对象也只能转换到某个接口类型。如果一个类没有接口,或者希望代理非接口中定义的方法,那就没办法了。
由此,又引出了cglib代理。

3. cglib代理

cglib动态的创建了一个类,但是这个类的父类是被代理的类,代理类重写了父类所有的public和非final方法,改为调用callback中的相关方法。 https://github.com/cglib/cglib

案例

已知车站具有售票功能,同时网上售票软件也可以进行售票。既网上售票软件代理车站售票功能。

功能接口

public interface Ticket3 {
    /**
     * 售票
     * @return void
     * 时间:2018年4月25日
     */
    public void sellTicket();
}

被代理对象

public class Station3 implements Ticket3{

    @Override
    public void sellTicket() {
        System.out.println("正在出售车票");
    }

}

代理对象

代理对象需实现MethodInterceptor接口,并重写intercept()方法

public class CGLibProxy implements MethodInterceptor {

    /**
     * 方法级别的代理
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 方法执行前
        before();

        Object object = proxy.invokeSuper(obj, args);

        // 方法执行后
        after();

        return object;
    }

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> cls) {
        return (T) Enhancer.create(cls, this);

    }

    private void after() {
        System.out.println("方法执行前");
    }

    private void before() {
        System.out.println("方法执行后");
    }

}

测试类

public class CGLibTest {

    public static void main(String[] args) {
        CGLibProxy cgLibProxy = new CGLibProxy();
        Ticket3 proxy = cgLibProxy.getProxy(Station3.class);
        proxy.sellTicket();
    }
}

动态代理与cglib代理区别

Java SDK代理:

面向的是一组接口, 它为这些接口动态创建了一个实现类,接口的具体实现逻辑是通过自定义的InvocationHandler实现的,这个实现是自定义的,也就是说,其背后都不一定有真正被代理的对象,也可能多个实际对象,根据情况动态选择。

jdk动态代理生成的代理类:

继承了Proxy类,实现了代理的接口,由于java只支持单继承,因此被代理类继承了Proxy类之后就无法再继承其他类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。生成的代理类格式如下:public HelloImpl extends Proxy implements Hello

cglib代理:

面向的是一个具体的类,它动态创建了一个新类,继承了该类,重写了其方法。
cglib是针对类来进行代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法增强,因为采用的是继承,所以不能对final修饰的类进行代理。cglib采用非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

以上内容参考

https://blog.csdn.net/noaman_wgs/article/details/72810255
https://blog.csdn.net/qq924862077/article/details/74625967

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值