欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java反射(JDK)与动态代理(CGLIB)详解

程序员文章站 2022-03-10 10:45:31
目录1、jdk代理2、cglib代理3、jdk代理与cglib代理对比一、反射概念:在运行状态中,对于任意的一个类,都能够知道这个类的所有字段和方法,对任意一个对象都能够通过反射机制调用一个类的任意方...

一、反射

概念:在运行状态中,对于任意的一个类,都能够知道这个类的所有字段和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法

实现方法:jvm在第一次加载某个类时会生成一个class对象,里面记录了这个类的信息

链接:类加载机制(留坑)

二、动态代理

动态代理的作用:在不改变原代码的基础上增加新的功能,如日志、权限检验等

反射在动态代理中的应用:由于知道原类的字段、方法等信息,才可以通过代理类执行被代理类的方法

动态代理的实现有两种

1、jdk代理

实现方法:通过创建一个代理类,这个代理类继承于一个proxy类,proxy类中有一个invocationhandler接口,这个接口持有被代理对象和一个invoke()方法。创建好代理类对象后,对该对象调用的方法都会交由invoke方法处理。invoke方法接受3个参数:代理对象、方法、参数列表。重写invoke方法便可以在原方法的基础上添加其他逻辑

一个jdk代理的简单实现:

import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
import java.lang.reflect.proxy;
// 定义一个接口
interface myinterface {
    void fun();
}
// 用一个类去实现这个接口
class person implements myinterface {
    @override
    public void fun() {
        system.out.println("person实现接口方法");
    }
}
// 用一个类实现invocationhandler接口
class myinvocationhandler<t> implements invocationhandler {
    //invocationhandler持有的被代理对象
    t target;
    public myinvocationhandler(t target) {
        this.target = target;
    }
    /**
     * proxy:代表动态代理对象
     * method:代表正在执行的方法
     * args:代表调用目标方法时传入的实参
     */
    @override
    public object invoke(object proxy, method method, object[] args) throws throwable {
        system.out.println("代理执行" + method.getname() + "方法"); // 在原方法的基础上添加其他逻辑
        object result = method.invoke(target, args); // 通过invoke方法调用原方法
        return result;
    }
}
public class main {
    public static void main(string[] args) {
        person person = new person();
        invocationhandler invocationhandler = new myinvocationhandler<>(person);
        myinterface proxy = (myinterface) proxy.newproxyinstance(person.class.getclassloader(),
                person.class.getinterfaces(), invocationhandler);
        proxy.fun();
    }
}

输出结果:

代理执行fun方法
person实现接口方法

缺陷:只能代理接口方法,因为jdk代理需要继承一个proxy类,又由于java的单继承机制,导致代理类无法继承父类的函数,只能实现接口

2、cglib代理

原理与jdk代理类似,区别在于cglib代理创建的代理类直接继承于被代理类,所以可以实现被代理类的方法而非仅仅接口方法

一个简单的cglib代理实现:

public class main {
    public static void main(string[] args) {
        enhancer enhancer = new enhancer();
        enhancer.setsuperclass(car.class);
        enhancer.setcallback(new methodinterceptor() {
            @override
            public object intercept(object obj, method method, object[] args, methodproxy methodproxy)
                    throws throwable {
                system.out.println("before");
                object res = methodproxy.invokesuper(obj, args);
                system.out.println("after");
                return res;
            }
        });
        car car = (car) enhancer.create();
        car.print();
    }
}
class car {
    void print() {
        system.out.println("执行原方法");
    }
}

由于cglib并非jdk自带,所以需要通过maven引入一个依赖

<dependency>
    <groupid>org.sonatype.sisu.inject</groupid>
    <artifactid>cglib</artifactid>
    <version>3.1.1</version>
</dependency>

输出结果:

before
执行原方法
after

3、jdk代理与cglib代理对比

1、jdk代理只能实现接口方法,而cglib代理既可以实现接口方法也可以实现类中自带的方法

2、性能上,在jdk1.8,cglib3.1.1的环境上,每次创建一个代理类并执行同样的方法

当执行10000次,jdk代理用时85ms,而cglib代理用时190ms,明显jdk代理性能更佳;

当执行1000000(一百万)次时,两种代理耗时几乎相等;

当执行10000000次时,cglib代理已经优于jdk代理。

所以在执行次数少时,jdk代理性能更好;反之cglib代理性能更好(但是重复执行多于1000000次的任务几乎没有吧

总结

本片文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!