JDK动态代理

JDK动态代理,第1张

JDK动态代理是基于接口使用,通过Proxy.newProxyInstance方法使用。

传入参数:当前类加载器、目标接口、带目标类的InvocationHandle实现类

1、Proxy#newProxyInstance

2、Constructor#newInstance

4、sun.reflect.NativeConstructorAccessorImpl#newInstance

4、sun.reflect.NativeConstructorAccessorImpl#newInstance

ReflectionFactory.inflationThreshold 默认值是15

5、native的newInstance0

3、sun.reflect.DelegatingConstructorAccessorImpl#newInstance

4、执行GeneratedConstructorAccessor3代理类方法

第16次调用generate方法生成代理类GeneratesConstructorAccessor,第17次执行GeneratesConstructorAccessor代理类方法

反射类加载器会导致Perm溢出

ConstructorAccessor 有下面实现类

1、NativeConstructorAccessorImpl

JNI(java本地接口)

2、DelegatingConstructorAccessorImpl

注入ConstructorAccessorImpl属性(值是1或3),实现newInstance

3、GeneratedConstructorAccessorX

通过代理类

MethodAccessor 有下面实现类

1、NativeMethodAccessorImpl

NativeMethodAccessorImpl是通过JNI(java本地接口)存取器获取反射类字节码信息

2、DelegatingMethodAccessorImpl

DelegatingMethodAccessorImpl注入MethodAccessorImpl属性(值是1或3),实现invoke调用

3、GeneratedMethodAccessorX

通过代理类加载反射类字节码

NativeConstructorAccessorImpl或NativeMethodAccessorImpl都有一个字段numInvocations。用来计算调用JNI次数

当大于15就会生成GeneratedConstructorAccessorX或GeneratedConstructorAccessorX的字节码类文件,该字节码通过DelegatingClassLoader类加载。

为什么设计这种机制:为了提高效率

MethodAccessorGenerator类

generate方法实现了

1、asm生成字节码数组

2、defineClass生成DelegatingClassLoader代理类加载器

3、generateName方法生成字节码文件GeneratedXXXAccessorX

Inflation机制提高了反射的性能,但是对于重度使用有两个问题

1、初次加载性能较低

2、动态加载的字节码导致PermGen持续增长

JDK是基于接口实现

Inflation机制

关键是生成代理类和调用inovke方法的实现方式

1、JNI

2、asm字节码

1.jdk动态代理目标类必须实现一个或多个接口 如果没有实现接口则无法实现jdk动态代理,如果想实现没有接口的类,就可以使用cglib 代理(子类代理)

2.实现jdk动态代理需要实现类的接口类型

public interface IUserDao {

public void a()

    public void b()

}

public class UserDaoimplements IUserDao{

@Override

    public void a() {

System.out.println("aaa")

    }

@Override

    public void b() {

System.out.println("bbb")

    }

}

/**

* 代理工厂

* 创建动态代理

* 动态代理不需要实现接口,但需要制定接口类型

*/

/**

* jdk 动态代理有一个限制,就是代理对象必须实现一个或多个接口 也叫 接口代理

* 如果想实现没有接口的类,就可以使用cglib 代理(子类代理)

*/

public class ProxyFactory {

private Objecttarget

    public ProxyFactory(Object target){

this.target = target

    }

/**

* 给目标对象生成代理对象

    * @return

    */

    public ObjectgetProxyInstance(){

return Proxy.newProxyInstance(

//类加载器

                target.getClass().getClassLoader(),

                //目标对象接口类型,使用泛型方式确认

                target.getClass().getInterfaces(),

                //触发事件处理器的方法,会把当前执行目标的对象的方法作为参数传入

                new InvocationHandler() {

@Override

                    public Objectinvoke(Object proxy, Method method, Object[] args)throws Throwable {

System.out.println("开始事务")

                        Object returnValue = method.invoke(target,args)

                        System.out.println("提交事务")

                        return returnValue

                    }

}

)

    }

}

public class TestProxy {

public static void main(String[] args) {

UserDao target =new UserDao()

        //原始的类型

        System.out.println(target.getClass())

        ProxyFactory proxyFactory =new ProxyFactory(target)

        //必须指定接口类型,否则

//Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.hbj.Test.proxy.UserDao

// at com.hbj.Test.proxy.TestProxy.main(TestProxy.java:11)

        IUserDao proxyInstance = (IUserDao) proxyFactory.getProxyInstance()

        System.out.println(proxyFactory.getClass())

        proxyInstance.a()

    }

}


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/11709218.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-18
下一篇2023-05-18

发表评论

登录后才能评论

评论列表(0条)

    保存