java动态代理原理(Java代理的作用和实现)

:暂无数据 2026-08-18 14:00:01 :0

java动态代理原理(Java代理的作用和实现)

大家好,关于java动态代理原理很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于Java代理的作用和实现的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!

本文目录

Java代理的作用和实现

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

JDK动态代理

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字节码

Java 几种动态代理实现及其性能比较

1. 动态代理是指在运行时,动态生成代理类。代理类的字节码将在运行时生成并载入当前的ClassLoader.
生成动态代理类的方法很多,如JDK自带的动态代理、CGLIB、Javassist或者ASM库。
JDK动态代理使用简单,它内置在JDK中,因此不需要引入第三方Jar包,但相对功能比较弱。CGLIB和Javassist都是高级的字节码生成库,总体性能比JDK自带的动态代理好,而且功能十分强大。ASM是低级的字节码生成工具,使用ASM已经近乎在于使用Javabytecode编程,对开发人员要求较高,也是性能最好的一种动态代理生辰工具。但ASM的使用是在过于繁琐,而且性能也没有数量级的提升,与CGLIB等高级字节码生成工具相比,ASM程序的可维护性也较差。
JDK实现
1、步骤
1)通过实现InvocationHandler接口创建自己的调用处理器
2)通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理类
3)通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型
4)通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入
2、创建代理
//InvocationHandlerImpl 实现了InvocationHandler接口,并能实现方法调用从代理类到委托类的分派转发
//其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
InvocationHandler handler = new InvocaitonHandlerImpl(..);
//通过Proxy为包括Interface接口在内的一组接口动态创建代理类的对象
Class clazz = Proxy.getProxyClass(classLoader,new Class{Interface.class,...});
//通过反射从生成的类对象获得构造函数对象
Constructor constructor = clazz.getConstructor(new Class{InvocationHandler.class});
//通过构造函数对象创建动态代理类实例
Interface Proxy = (Interface)constructor.newInstance(new Object{handler});
//Proxy类的静态方法newProxyInstance对上面具体步骤的后三步做了封装,简化了动态代理对象的获取过程。
//InvocationHandlerImpl实现了InvocaitonHandler接口,并能实现方法调用从代理类到委托类的分派转发
InvocaitonHandler handler = new InvocationHandlerImpl(..);
//通过Proxy直接创建动态代理类实例
nterface proxy = (Interface)Proxy.newProxyInstance(classLoader,new Class{Interface.class},handler);
3、代码
/**
* 接口
*
*/
public interface IDBQuery {
String request();
}
/**
* 真实的实现类,具体的目标对象
*
*/
public class DBQuery implements IDBQuery {
public DBQuery(){
try {
Thread.sleep(1000); //可能包含数据库连接等耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String request() {
return "request string";
}
}
/**
* JDK动态代理的实现类
*
*/
public class JdkDbQueryHandler implements InvocationHandler{
IDBQuery real = null; //主题接口
/**
* 生成Handler
*/
@Override
public Object invoke(Object proxy, Method method, Object args)
throws Throwable {
if(real == null)
real = new DBQuery(); //如果是第一次调用,则生成真实对象
return real.request(); //使用真实主题完成实际的操作
}
/**
* 利用Handler生成动态代理对象
*/
public static IDBQuery createJdkProxy(){
//根据指定的类加载器和接口以及截获器,返回代理类的一个实例对象
//ClassLoader loader :指定被代理对象的类加载器
//Class Interfaces :指定被代理对象所以事项的接口
//InvocationHandler h :指定需要调用的InvocationHandler对象
IDBQuery jdkProxy = (IDBQuery) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class{IDBQuery.class}, new JdkDbQueryHandler());
return jdkProxy;
}
}

JAVA动态代理解析


众所周知,JDK的动态代理模式必须实现接口。
以下面的源码为例:
接口一:
public interface ActionInterface {
void doSelf(String str);
String getType();
}
接口二:
public interface InterruupIntf {
void interrup();
}
实现类:
public class MyselfImpl implements ActionInterface, InterruupIntf {
public String getType() {
String type = "公用部门";
System.out.println(type);
return type;
}
public void doSelf(String str) {
System.out.println("业务实现类: " + str + " !");
}
public void interrup() {
System.out.println("发呆三分钟!");
}
}
动态代理需要反射,
* 必须要实现InvocationHandler接口
* 能够对所有的方法进行代理
public class MyInvocationHandler implements InvocationHandler {
private Object obj;
/**
* 通过构造方法来设置被代理的对象
* @param obj
*/
public MyInvocationHandler(Object obj) {
this.obj = obj;
}
/**
* 动态代理需要反射
*
*/
public Object invoke(Object proxy, Method method, Object args)
throws Throwable {
System.out.println("+++++++++++调用业务方法之前做其他事情");
Object returnObject = method.invoke(obj, args);
System.out.println("+++++++++++调用业务方法之前做其他事情");
return returnObject;
}
/**
* 测试函数
* 动态代理对所有的代理类都进行了拦截
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws SecurityException
* @throws IllegalArgumentException
*/
public static void main(String args) throws InterruptedException,
IllegalArgumentException, SecurityException,
InstantiationException, IllegalAccessException,
InvocationTargetException, NoSuchMethodException {
//实现业务逻辑的类
MyselfImpl muSelf = new MyselfImpl();
//JDK创建的动态逻辑类,调用上面的构造函数注入
MyInvocationHandler myInvocation = new MyInvocationHandler(muSelf);
/*
Class? proxyClass = Proxy.getProxyClass(MyselfImpl.class.getClassLoader(), MyselfImpl.class.getInterfaces());
//建业务逻辑类的动态代理类
Object proxy = proxyClass.getConstructor(new Class { InvocationHandler.class }).newInstance(new MyInvocationHandler(new MyselfImpl())); */
//建业务逻辑类的动态代理类
Object proxy = Proxy.newProxyInstance(MyselfImpl.class.getClassLoader(), MyselfImpl.class.getInterfaces(), myInvocation);
//业务类自己调用运行代理对象
ActionInterface testIntf = (ActionInterface) proxy;
testIntf.doSelf("我要做业务了!");
testIntf.getType();
InterruupIntf intIntf = (InterruupIntf) proxy;
intIntf.interrup();
}
}
运行最后一个类的MAIN函数,控制台输出结果如下:
+++++++++++调用业务方法之前做其他事情
业务实现类: 我要做业务了! !
+++++++++++调用业务方法之前做其他事情
+++++++++++调用业务方法之前做其他事情
公用部门
+++++++++++调用业务方法之前做其他事情
+++++++++++调用业务方法之前做其他事情
发呆三分钟!
+++++++++++调用业务方法之前做其他事情
看到结果了。
JDK的动态代理,对MyselfImpl所有方法都进行了拦截,在调用真正的业务类方法之前之后都插入了代码,这就是JDK的动态代理。其实SPRING的AOP思想的基本原理也是这个,但是它写的比较负责,而且比较优秀。

Spring的两种代理JDK和CGLIB的区别

原理区别:\x0d\x0ajava动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。\x0d\x0a1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP \x0d\x0a2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP \x0d\x0a3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

java反射和动态代理有什么关系

1.JAVA主要作用是获取程序在运行时刻的内部结构,包括其中的构造方法、声明的域和定义的方法等
2JAVA自带的动态代理是基于java.lang.reflect.Proxy、java.lang.reflect.InvocationHandler两个类来完成的,使用了JAVA反射机制,通常使用下面方法创建代理对象: Object proxy = Proxy.newProxyInstance(定义代理对象的类加载器,要代理的目标对象的归属接口数组,回调接口InvocationHandler)
***隐藏网址***

Java怎么实现多层动态代理

java动态代理主要是通过Proxy类的newProxyInstance()方法,该方法需要三个参(ClassLoader loader, Class《?》 interfaces, InvocationHandler h),其中分别为:
①:该对象的类加载器classloader
②:被代理类的类对象
③:一个InvocationHandler 处理器接口
InvocationHandler中有一个方法:invoke(Object proxy, Method method, Object args) ,通过显式调用可以实现对代理对象的类方法进行操作,这里主要是采用反射的原理,SrpingAop就是利用这一点进行实现的。

java静态代理与动态代理的区别

JAVA的静态代理与动态代理比较
1.静态代理类:
由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。动态代理类:在程序运行时,运用反射机制动态创建而成。
由此可见,代理类可以为委托类预处理消息、把消息转发给委托类和事后处理消息等。
例程1 HelloService.java
package proxy;
import java.util.Date;
public interface HelloService{
public String echo(String msg);
public Date getTime();
}
2.动态代理类
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
Proxy类提供了创建动态代理类及其实例的静态方法。
(1)getProxyClass()静态方法负责创建动态代理类,它的完整定义如下:
public static Class《?》 getProxyClass(ClassLoader loader, Class《?》 interfaces) throws IllegalArgumentException
参数loader 指定动态代理类的类加载器,参数interfaces 指定动态代理类需要实现的所有接口。
(2)newProxyInstance()静态方法负责创建动态代理类的实例,它的完整定义如下:
public static Object newProxyInstance(ClassLoader loader, Class《?》 interfaces, InvocationHandler handler) throws
IllegalArgumentException
参数loader 指定动态代理类的类加载器,参数interfaces 指定动态代理类需要实现的所有接口,参数handler 指定与动态代理类关联的 InvocationHandler 对象。
以下两种方式都创建了实现Foo接口的动态代理类的实例:
/**** 方式一 ****/
//创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(...);
//创建动态代理类
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class { Foo.class });
//创建动态代理类的实例
Foo foo = (Foo) proxyClass.getConstructor(new Class { InvocationHandler.class }).
newInstance(new Object { handler });
/**** 方式二 ****/
//创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(...);
//直接创建动态代理类的实例
Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class { Foo.class }, handler);
由Proxy类的静态方法创建的动态代理类具有以下特点:
动态代理类是public、final和非抽象类型的;
动态代理类继承了java.lang.reflect.Proxy类;
动态代理类的名字以“$Proxy”开头;
动态代理类实现getProxyClass()和newProxyInstance()方法中参数interfaces指定的所有接口;

java动态代理是什么

import java.lang.reflect.Proxy;
A.创建一个实现接口InvocationHandler的类,他必须实现invoke方法
B.创建被代理的类以及接口。
C.通过Proxy的静态方法newProxyInstance(ClassLoader loader,Class【】interfaces,InvocationHandler handler)创建一个代理
D.通过代理调用方法。
java动态代理:是在运行是生成的class对象,在生成时必须提供一组或一个interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当做这些interface中的任何一个来用,当然,这个DynamicProxy其实就是一个Proxy,他不会替你做实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。因此,DynamicProxy必须实现InvocationHandler接口。
5)一个动态代理了和一个InvocationHandler 实现关联的。每一个动态代理实例的调用都要通过InvocationHandler接口的handler(调用处理器)来调用,动态代理不做任何执行操作,只是在创建动态代理时,把要实现的接口和handler关联,动态代理要帮助被代理执行的任务,要转交给handler来执行。其实就是调用invoke方法。

关于java动态代理原理到此分享完毕,希望能帮助到您。

java动态代理原理(Java代理的作用和实现)

本文编辑:admin

更多文章:


mariadb忘记密码(mysql用户密码忘记了怎么办)

mariadb忘记密码(mysql用户密码忘记了怎么办)

大家好,mariadb忘记密码相信很多的网友都不是很明白,包括mysql用户密码忘记了怎么办也是一样,不过没有关系,接下来就来为大家分享关于mariadb忘记密码和mysql用户密码忘记了怎么办的一些知识点,大家可以关注收藏,免得下次来找不

2026年10月15日 07:50

mysql端口号(如何查看自己数据库的端口号)

mysql端口号(如何查看自己数据库的端口号)

“mysql端口号”相关信息最新大全有哪些,这是大家都非常关心的,接下来就一起看看mysql端口号(如何查看自己数据库的端口号)!

2026年10月15日 06:30

printf打印16进制(C语言 十六进制怎么输出)

printf打印16进制(C语言 十六进制怎么输出)

大家好,今天小编来为大家解答以下的问题,关于printf打印16进制,C语言 十六进制怎么输出这个很多人还不知道,现在让我们一起来看看吧!

2026年10月15日 06:00

avantage怎么设置为中文(Avantage安装丢失GIT)

avantage怎么设置为中文(Avantage安装丢失GIT)

大家好,如果您还对avantage怎么设置为中文不太了解,没有关系,今天就由本站为大家分享avantage怎么设置为中文的知识,包括Avantage安装丢失GIT的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!

2026年10月15日 03:00

ospf协议的作用是什么(OSPF路由协议的作用是什么)

ospf协议的作用是什么(OSPF路由协议的作用是什么)

“ospf协议的作用是什么”相关信息最新大全有哪些,这是大家都非常关心的,接下来就一起看看ospf协议的作用是什么(OSPF路由协议的作用是什么)!

2026年10月15日 02:40

方案对比特效js(在一个网页中如何实现两个JS特效)

方案对比特效js(在一个网页中如何实现两个JS特效)

各位老铁们好,相信很多人对方案对比特效js都不是特别的了解,因此呢,今天就来为大家分享下关于方案对比特效js以及在一个网页中如何实现两个JS特效的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!

2026年10月15日 02:10

activex控件未注册怎么办(登陆视频监控网页时提示activex控件未注册,怎么解决)

activex控件未注册怎么办(登陆视频监控网页时提示activex控件未注册,怎么解决)

今天给各位分享登陆视频监控网页时提示activex控件未注册,怎么解决的知识,其中也会对登陆视频监控网页时提示activex控件未注册,怎么解决进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

2026年10月14日 20:30

学生信息管理系统c语言(用C语言编程学生信息管理系统!)

学生信息管理系统c语言(用C语言编程学生信息管理系统!)

今天给各位分享用C语言编程学生信息管理系统!的知识,其中也会对用C语言编程学生信息管理系统!进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

2026年10月14日 20:20

excel连接sql数据库教程(excel怎么连接sql数据库)

excel连接sql数据库教程(excel怎么连接sql数据库)

本篇文章给大家谈谈excel连接sql数据库教程,以及excel怎么连接sql数据库对应的知识点,文章可能有点长,但是希望大家可以阅读完,增长自己的知识,最重要的是希望对各位有所帮助,可以解决了您的问题,不要忘了收藏本站喔。

2026年10月14日 19:40

null s brawl(null和空字符有区别吗)

null s brawl(null和空字符有区别吗)

今天给各位分享null和空字符有区别吗的知识,其中也会对null和空字符有区别吗进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

2026年10月14日 19:00

最近更新

热刺vs马赛比赛(热刺赛程比分)
2026-10-15 09:10:01 浏览:0
热门文章

标签列表