动态代理简介

在了解动态代理之前,我们首先要理解什么是代理模式,动态代理究竟要解决什么问题。因此,在介绍动态代理之前,先介绍下代理模式(静态代理)

静态代理

充分利用了Java的多态性,通过对接口的多个实现,另代理类与被代理类实现同一个接口,通过代理类调用接口方法,实现了调用被代理类(另一个实现类)的方法。

具体实现:在编写代理类时,在代理类中声明父类接口,构造方法入参即为父类接口。在主方法中创建被代理类对象时,会调用被代理类的构造器,此时通过java的多态性,将接口的实现类声明为父接口,并将其作为参数传入被代理类,这样就可以实现静态代理。

对上边的实现方式,我们举个栗子说明下,我们先简单的创建一个对象和接口:

//被代理类所需实现的接口
public interface DemoInterface {
    void doSomeThing();
}
//被代理类
public class Demo implements DemoInterface{
    @Override
    public void doSomeThing() {
        System.out.println("被代理对象方法执行!!");
    }
}

然后创建一个代理类:

public class DemoProxy {

    private DemoInterface demo;

    public DemoProxy(DemoInterface demo) {
        this.demo = demo;
    }

    public void doSomeThing(){
        System.out.println("静态代理前置操作。");
        demo.doSomeThing();
        System.out.println("静态代理后置操作。");
    }
}

这样,我们就可以通过代理对象的操作,在被代理对象方法执行之前或之后做一些我们自己的操作了。

//执行结果
静态代理前置操作。
被代理对象方法执行!!
静态代理后置操作。

当然,这种设计模式的简单使用,也会有一些弊端存在,比如:在父接口中如果声明了不需要实现的方法,无论实现类还是被实现类都需要强行实现该方法,代码累赘,实现困难,因此伟大的程序猿们研究了进阶的代理模式,动态代理。

动态代理

动态代理就是为了解决上述代理模式的弊端的,动态代理通过自己的方式创建出代理对象,实际操作时候直接操作代理对象即可,解决了代码冗余的弊端。比如说市面上常见的两种,jdk动态代理和cglib动态代理。

JDK动态代理

JDK动态代理是jdk自带的,是通过java.lang.reflect.Proxy创建的代理对象,它的创建方式是通过传入java.lang.reflect.InvocationHandler匿名内部类的方式,在通过反射创建代理对象时让代理对象同时实现被代理的接口和java.lang.reflect.InvocationHandler接口,从而达到一个动态代理的目的。因此,jdk动态代理需要被代理对象实现一个接口。
使用方式如下:

/**
 * JDK动态代理委托类(Demo)必须实现接口只有这样才能生成一个代理类,而且代理类也会默认是该接口的实现
 *
 */
public class JDKProxyFactory {
    //维护一个目标对象
    private Object target;

    public JDKProxyFactory(Object target) {
        this.target = target;
    }
    //给目标对象生成一个代理对象。
    public Object getProxyInstance(){

        /**
         * 说明:
         * 1:loader 制定当前目标对象使用的类加载器。获取加载器的方法固定。
         * 02; In
         * ClassLoader loader, :指定当前目标对象使用的类加载器。获取加载器的方法固定。
         * Class<?>[] interfaces, 目标对象实现的接口类型,使用泛型方法确认类型
         * InvocationHandler h) 事件处理,执行目标对象方法时,会触发事件处理器的方法。会把当前执行的目标对象方法作为参数传入
         */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                System.out.println("jdk代理开始。");
                Object invoke = method.invoke(target, args);
                System.out.println("jdk代理结束。");
                return invoke;
            }
        });
    }
}
//实际调用
DemoInterface jdkProxyInstance = (DemoInterface)new JDKProxyFactory(demo).getProxyInstance();
jdkProxyInstance.doSomeThing();

Cglib动态代理

Cglib并非sun公司官方的代理技术,所以需要Jar包支持。需要cglib、asm等Jar包支持。(Maven依赖如下)

 <dependency>
 	 <groupId>asm</groupId>
     <artifactId>asm</artifactId>
     <version>3.3.1</version>
 </dependency>
 <dependency>
     <groupId>asm</groupId>
     <artifactId>asm-commons</artifactId>
     <version>3.3.1</version>
 </dependency>
 <dependency>
     <groupId>asm</groupId>
     <artifactId>asm-tree</artifactId>
     <version>3.3.1</version>
 </dependency>
 <dependency>
     <groupId>cglib</groupId>
     <artifactId>cglib</artifactId>
     <version>3.3.0</version>
 </dependency>

cglib的创建方式完全与JDK不同,他是利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。由于是通过继承被代理类的方式进行的代理模式,因此,在使用cglib时被代理类一定不能被final修饰。
具体使用如下:

/**
 * Cglib动态代理并不需要实现一个接口,它生成的代理类默认继承委托类,所以,委托类不能被final修饰。
 *
 */
public class CglibProxyFactory implements MethodInterceptor {
    //维护一个目标对象
    private Object target;

    public CglibProxyFactory(Object target) {
        this.target = target;
    }
    //给目标对象生成一个代理对象。
    public Object getProxyInstance(){
        //创建一个工具类
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建子类对象,即代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib代理开始。");
        Object invoke = method.invoke(target, args);
        System.out.println("Cglib代理结束。");
        return invoke;
    }
}

总结

静态代理为代理模式的使用,需要代理类实现很多无用方法,编码上的硬伤让我们在实际应用时候很难会选择它。

JDK动态代理:JDK自带的动态代理,通过反射创建代理对象,会和被代理对象实现同一个接口,在使用aop等技术时是默认的动态代理技术,弊端是需要被代理对象实现一个接口

Cglib动态代理:非自带的动态代理模式,因此需要引入一些其他的依赖,而且,在使用其他技术(比如Aop)引入动态代理模式时,需要做一些额外的配置。而且,由于是创建子类的实现模式,要求被代理类不能被final修饰

性能对比:由于是直接修改class文件的方式,所以在jdk1.7及以前,cglib的效率是略高于jdk动态代理的。但是在jdk的逐版本优化下,在1.8及以后的版本,jdk的效率是略优于cglib的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摆烂的小趴菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值