JAVA中的反射和动态代理

1.反射概念

在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

根据类的全限定名可以从JVM的方法区(类加载后存放在方法区中)获取类所有的信息(名称, 常量,属性,静态代码块,构造器,方法,接口,权限)

一个类的构成:名称, 常量,属性,静态代码块,构造器,方法,接口,权限,所以反射能够操作的东西也无非是这些内容

2.使用反射的方式

1.Class clazz = object.getClass //通过实例的getClass()方法获取类信息

2.Class clazz = Object.class      //直接获取

3.Class clazz = Class.forName("com.mysql.jdbc.Driver");//类加载器  

 本质调用public final native Class<?> getClass();直接调用本地方法去拿相关信息

3.世人都说反射慢

由于反射获取属性,方法,类加载等操作都是调用native接口和底层交互,所以导致了操作慢

但是JDK 其实对反射做了优化

1.优化一引入ReflectionData类,缓存类,对于读取Fields,Methods之类的操作方法返回的数据做了一次缓存,除了第一次读取,其他都是内存数据比较快

 private Field[] privateGetPublicFields(Set<Class<?>> traversedInterfaces) {
        checkInitted();
        Field[] res;
        ReflectionData<T> rd = reflectionData();
        if (rd != null) {
            //有缓存则返回
            res = rd.publicFields;
            if (res != null) return res;
        }

        // No cached value available; compute value recursively.
        // Traverse in correct order for getField().
        List<Field> fields = new ArrayList<>();
        if (traversedInterfaces == null) {
            traversedInterfaces = new HashSet<>();
        }

        // Local fields
        //没有则调本地方法获取
        Field[] tmp = privateGetDeclaredFields(true);
        addAll(fields, tmp);

        // Direct superinterfaces, recursively
        for (Class<?> c : getInterfaces()) {
            if (!traversedInterfaces.contains(c)) {
                traversedInterfaces.add(c);
                addAll(fields, c.privateGetPublicFields(traversedInterfaces));
            }
        }

        // Direct superclass, recursively
        if (!isInterface()) {
            Class<?> c = getSuperclass();
            if (c != null) {
                addAll(fields, c.privateGetPublicFields(traversedInterfaces));
            }
        }

        res = new Field[fields.size()];
        fields.toArray(res);
        //加入缓存
        if (rd != null) {
            rd.publicFields = res;
        }
        return res;
    }

2.优化二 对于Field,Method,Constructor的访问加入了代理类,在调用invoke(),或new Instance()等方法时当次数>15次时,创建代理类实现

 public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
            MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
            this.parent.setDelegate(var3);
        }

        return invoke0(this.method, var1, var2);
    }

1.动态代理概念

代理:为其他对象提供一种代理以控制对这个对象的访问

动态代理:程序运行过程中动态创建代理类

2.动态代理实现的两种方式

1). Java反射方式:实现java.lang.reflect.InvocationHandler接口,且实现invoke()方法

2). cglib方式:实现CGLIB提供的org.springframework.cglib.proxy.MethodInterceptor,且实现intercept()

举例:鹿晗是明星,找他工作先要找经纪人

/**
 * @author z
 * @date 2020-10-13 16:04
 **/
public class LuHan implements Star {

    @Override
    public void work() {
        System.out.println("鹿晗工作");
    }
}

Java反射方式案例:

public class ManagerProxy implements InvocationHandler {

    private Star star;
    //经纪人不一定只管一个人
    public ManagerProxy(Star star) {
        this.star = star;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("经过经纪人");
        Object o = method.invoke(star, args);
        return o;
    }

    public static void main(String[] args) {
        Star luhan = new LuHan();
        ManagerProxy proxy = new ManagerProxy(luhan);
        Star star = (Star) Proxy.newProxyInstance(
                luhan.getClass().getClassLoader(),
                luhan.getClass().getInterfaces(),
                proxy);
        star.work();
    }
}

Cglib方式案例: 

public class ManagerCglibProxy implements MethodInterceptor {

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("经过经纪人");
        Object o = methodProxy.invokeSuper(object, args);
        return o;
    }

    public static void main(String[] args) {
        ManagerCglibProxy cglibProxy = new ManagerCglibProxy();

        //cglib方式简洁很多,但是Enhancer不能代理final类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(LuHan.class);
        enhancer.setCallback(cglibProxy);
        Star star = (Star) enhancer.create();
        star.work();
    }

}
两次输出:
经过经纪人
鹿晗工作

cglib效率会比java反射方式高,但是cglib方式不能代理finl类 

 
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值