JDK动态代理原理解析
一、例子:
1、定义基础接口
public interface HttpApi {
String get(String url);
}
2、实现类
public class RealModule implements HttpApi {
@Override
public String get(String url) {
return "result";
}
}3、动态代理
public class ProxyFactory {
public static HttpApi getProxy(HttpApi target) {
return (HttpApi) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new LogHandler(target));
}
// 增强类
private static class LogHandler implements InvocationHandler {
private HttpApi target;
LogHandler(HttpApi target) {
this.target = target;
}
// method底层的方法无参数时,args为空或者长度为0
@Override
public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 扩展的功能
Log.i("http-statistic", (String) args[0]);
// 访问基础对象
return method.invoke(target, args);
}
}
}上面例子中出现的核心方法有:
- Proxy.newProxyInstance( target.getClass().getClassLoader(),target.getClass().getInterfaces(),new LogHandler(target));
- 参数说明:1.类加载器。2.指定newProxyInstance()方法返回的对象要实现哪些接口,可以指定多个接口。3.调用处理器,实现了InvocationHandler接口的实现类,重写invoke方法来增强被代理类的方法。
- 方法返回:实现了指定接口的实现类对象,即被代理类。
- invoke(Object proxy, Method method, @Nullable Object[] args) ;
- 参数说明:1.代理对象,也就是Proxy.newProxyInstance()方法返回的对象。2.被代理对象的方法如例子中的get()方法。3.表示当前被调用方法的参数。
- 方法返回:前被调用的方法的返回值,没有返回值则返回null。
二、反编译代理类源码
public final class $proxy0 extends Proxy implements HttpApi {
//反射的元数据Method存储起来,避免重复创建
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $proxy0(InvocationHandler var1) throws {
super(var1);
}
/**
* Object#hashCode()
* Object#equals(Object)
* Object#toString()
*/
// 实现了HttpApi接口
public final String get() throws {
try {
//转发到Invocation#invoke()
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
//Object#hashCode()
//Object#equals(Object)
//Object#toString()
m3 = Class.forName("HttpApi").getMethod("get");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}通过反编译的源码我们可以得到以下结论:
- JDK动态代理生成了代理类(继承Proxy)的字节码文件(Class)。
- 代理类继承自 java.lang.reflect.Proxy,实现了HttpApi接口。
- 代理类中的所有方法都是final 的。
- 代理类所有的方法功能的实现都统一调用了InvocationHandler的invoke()方法。
- 通过(String)super.h.invoke(this, m3, (Object[])null)方法进入增强类以实现对被代理方法的增强。
- JDK动态代理只能对实现了接口的类进行代理,不能对普通类进行代理,这是因为JDK动态代理生成的新的代理类其父类是Proxy,java不支持类的多继承,所以只能实现接口。
三、核心类Proxy源码解析
1.JDK动态代理核心类:Proxy。
2.Proxy主要API
| 方法 | 描述 |
| getProxyClass(ClassLoader, Class<?>...) : Class<?> | 获取实现目标接口的代理类 Class 对象 |
| newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h): Object | 获取实现目标接口的代理对象 |
| isProxyClass(Class<?>) : boolean | 判断一个 Class 对象是否属于代理类 |
| getInvocationHandler(Object) : InvocationHandler | 获取代理对象内部的 InvocationHandler |
3.核心源码:
3.1 Proxy.java
1、获取代理类 Class 对象
public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces){
final Class<?>[] intfs = interfaces.clone();
...
1.1 获得代理类 Class 对象
return getProxyClass0(loader, intfs);
}
2、实例化代理类对象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h){
...
final Class<?>[] intfs = interfaces.clone();
2.1 获得代理类 Class对象
Class<?> cl = getProxyClass0(loader, intfs);
...
2.2 获得代理类构造器 (接收一个 InvocationHandler 参数)
// private static final Class<?>[] constructorParams = { InvocationHandler.class };
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
...
2.3 反射创建实例
return newInstance(cons, ih);
}可以看到,实例化代理对象也需要先通过 getProxyClass0(...) 获取代理类 Class 对象,而 newProxyInstance(...) 随后会获取参数为 InvocationHandler 的构造函数实例化一个代理类对象。
3.2获取代理类的Class对象
-> 1.1、2.1 获得代理类 Class对象
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {
...
从缓存中获取代理类,如果缓存未命中,则通过ProxyClassFactory生成代理类
return proxyClassCache.get(loader, interfaces);
}
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>>{
3.1 代理类命名前缀
private static final String proxyClassNamePrefix = "$Proxy";
3.2 代理类命名后缀,从 0 递增(原子 Long)
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
3.3 参数校验
for (Class<?> intf : interfaces) {
// 验证参数 interfaces 和 ClassLoder 中加载的是同一个类
// 验证参数 interfaces 是接口类型
// 验证参数 interfaces 中没有重复项
// 否则抛出 IllegalArgumentException
}
// 验证所有non-public接口来自同一个包
3.4(一般地)代理类包名
// public static final String PROXY_PACKAGE = "com.sun.proxy";
String proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
3.5 代理类的全限定名
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
3.6 生成字节码数据
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
3.7 从字节码生成 Class 对象
return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
}
}
-> 3.6 生成字节码数据
public static byte[] generateProxyClass(final String var0, Class[] var1) {
ProxyGenerator var2 = new ProxyGenerator(var0, var1);
...
final byte[] var3 = var2.generateClassFile();
return var3;
}3.3ProxyGenerator.java
生成class文件字节码
private byte[] generateClassFile() {
3.6.1 只代理Object的hashCode、equals和toString
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
3.6.2 代理接口的每个方法
...
for(var1 = 0; var1 < this.interfaces.length; ++var1) {
...
}
3.6.3 添加带有 InvocationHandler 参数的构造器
this.methods.add(this.generateConstructor());
var7 = this.proxyMethods.values().iterator();
while(var7.hasNext()) {
...
3.6.4 在每个代理的方法中调用InvocationHandler#invoke()
}
3.6.5 输出字节流
ByteArrayOutputStream var9 = new ByteArrayOutputStream();
DataOutputStream var10 = new DataOutputStream(var9);
...
return var9.toByteArray();
}核心流程:JDK 动态代理生成的代理类命名为 com.sun.proxy$Proxy[从0开始的数字](例如:com.sun.proxy$Proxy0),这个类继承自 java.lang.reflect.Proxy。其内部还有一个参数为 InvocationHandler 的构造器,对于代理接口的方法调用都会分发到 InvocationHandler#invoke()。
CGLIB动态代理原理解析
一、例子
// 被代理类
public class PersonService {
public PersonService() {
System.out.println("PersonService构造");
}
// 该方法不能被子类覆盖
// Cglib是无法代理final修饰的方法的,具体原因我们一会通过源码来分析
final public Person getPerson(String code) {
System.out.println("PersonService:getPerson>>"+code);
return null;
}
public void setPerson() {
System.out.println("PersonService:setPerson");
}
}// 增强类
public class CglibProxyIntercepter implements MethodInterceptor {
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("执行前...");
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("执行后...");
return object;
}
}// 测试类
public class Test {
public static void main(String[] args) {
//代理类class文件存入本地磁盘
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(PersonService.class);
enhancer.setCallback(new CglibProxyIntercepter());
PersonService proxy= (PersonService) enhancer.create();
proxy.setPerson();
proxy.getPerson("1");
}
}上面例子中出现的核心方法有:
- intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy)
- 参数说明:1.cglib生成的代理对象。2.被代理对象方法。3.方法参数。4.代理方法
- enhancer.setSuperclass(PersonService.class);
- enhancer.setCallback(new CglibProxyIntercepter());
- enhancer.create();
- 参数说明:1.setSuperclass(PersonService.class);设置被代理类。2.设置增强类。3.创建
二、反编译代理类源码
通过CGLIB会生成三个Class文件,分别是代理类的FastClass,代理类,被代理类的FastClass

2.1
就是cglib生成的代理类,它继承了PersonService类,并实现了Factory接口。
public class PersonService$$EnhancerByCGLIB$$eaaaed75extends PersonService
implements Factory
{
private boolean CGLIB$BOUND;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;//拦截器
private static final Method CGLIB$setPerson$0$Method;//被代理方法
private static final MethodProxy CGLIB$setPerson$0$Proxy;//代理方法
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$finalize$1$Method;
private static final MethodProxy CGLIB$finalize$1$Proxy;
private static final Method CGLIB$equals$2$Method;
private static final MethodProxy CGLIB$equals$2$Proxy;
private static final Method CGLIB$toString$3$Method;
private static final MethodProxy CGLIB$toString$3$Proxy;
private static final Method CGLIB$hashCode$4$Method;
private static final MethodProxy CGLIB$hashCode$4$Proxy;
private static final Method CGLIB$clone$5$Method;
private static final MethodProxy CGLIB$clone$5$Proxy;
static void CGLIB$STATICHOOK1()
{
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class localClass1 = Class.forName("com.demo.proxy.cglib.PersonService$$EnhancerByCGLIB$$eaaaed75");//代理类
Class localClass2;//被代理类PersionService
Method[] tmp95_92 = ReflectUtils.findMethods(new String[] { "finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (localClass2 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$finalize$1$Method = tmp95_92[0];
CGLIB$finalize$1$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "finalize", "CGLIB$finalize$1");
Method[] tmp115_95 = tmp95_92;
CGLIB$equals$2$Method = tmp115_95[1];
CGLIB$equals$2$Proxy = MethodProxy.create(localClass2, localClass1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
Method[] tmp135_115 = tmp115_95;
CGLIB$toString$3$Method = tmp135_115[2];
CGLIB$toString$3$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
Method[] tmp155_135 = tmp135_115;
CGLIB$hashCode$4$Method = tmp155_135[3];
CGLIB$hashCode$4$Proxy = MethodProxy.create(localClass2, localClass1, "()I", "hashCode", "CGLIB$hashCode$4");
Method[] tmp175_155 = tmp155_135;
CGLIB$clone$5$Method = tmp175_155[4];
CGLIB$clone$5$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
tmp175_155;
Method[] tmp223_220 = ReflectUtils.findMethods(new String[] { "setPerson", "()V" }, (localClass2 = Class.forName("com.demo.proxy.cglib.PersonService")).getDeclaredMethods());
CGLIB$setPerson$0$Method = tmp223_220[0];
CGLIB$setPerson$0$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "setPerson", "CGLIB$setPerson$0");
tmp223_220;
return;
}通过代理类的源码可以看到,代理类会获得所有在父类继承来的方法,并且会有MethodProxy与之对应,比如 Method:CGLIB$setPerson$0$Method,MethodProxy:CGLIB$setPerson$0$Proxy。
2.2方法调用
//代理方法(methodProxy.invokeSuper会调用)
final void CGLIB$setPerson$0() {
super.setPerson();
}
//被代理方法(methodProxy.invoke会调用,这就是为什么在拦截器中调用methodProxy.invoke会死循环,一直在调用拦截器)
public final void setPerson() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if(var10000 != null) {
//调用拦截器
var10000.intercept(this, CGLIB$setPerson$0$Method, CGLIB$emptyArgs, CGLIB$setPerson$0$Proxy);
} else {
// 如果找不到callback实例则直接调用被代理的方法
super.setPerson();
}
}调用过程:代理对象调用this.setPerson()方法 -> 调用拦截器 -> var10000.intercept() -> methodProxy.invokeSuper() -> CGLIB$setPerson$0() -> 被代理对象setPerson()方法。
如果增强类中增强方法写成
// 增强类
public class CglibProxyIntercepter implements MethodInterceptor {
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("执行前...");
Object object = methodProxy.invoke(sub, objects);
System.out.println("执行后...");
return object;
}
}则调用过程:代理对象调用this.setPerson()方法 -> 调用拦截器 -> var10000.intercept() -> methodProxy.invoke() -> 代理对象调用this.setPerson()方法 -> 进入死循环。
2.3MethodProxy
在拦截器MethodInterceptor中intercept()方法就是调用methodProxy.invokeSuper(),进而调用代理方法CGLIB$setPerson$0(),MethodProxy非常关键,我们分析一下它具体做了什么。
2.3.1MethodProxy.create(localClass2, localClass1, "()V", "setPerson", "CGLIB$setPerson$0");
public class MethodProxy {
private Signature sig1;
private Signature sig2;
private MethodProxy.CreateInfo createInfo;
private final Object initLock = new Object();
private volatile MethodProxy.FastClassInfo fastClassInfo;
//c1:被代理对象Class
//c2:代理对象Class
//desc:入参类型
//name1:被代理方法名
//name2:代理方法名
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc);//被代理方法签名
proxy.sig2 = new Signature(name2, desc);//代理方法签名
proxy.createInfo = new MethodProxy.CreateInfo(c1, c2);
return proxy;
}
// 给CreateInfo赋值
private static class CreateInfo {
//c1:被代理对象Class
//c2:代理对象Class
Class c1;
Class c2;
NamingPolicy namingPolicy;
GeneratorStrategy strategy;
boolean attemptLoad;
public CreateInfo(Class c1, Class c2) {
this.c1 = c1;
this.c2 = c2;
AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
if (fromEnhancer != null) {
this.namingPolicy = fromEnhancer.getNamingPolicy();
this.strategy = fromEnhancer.getStrategy();
this.attemptLoad = fromEnhancer.getAttemptLoad();
}
}
}2.3.2通过CreateInfo初始化FastClassInfo
private void init() {
if (this.fastClassInfo == null) {
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
CreateInfo ci = this.createInfo;
FastClassInfo fci = new FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
private static FastClass helper(CreateInfo ci, Class type) {
FastClass.Generator g = new FastClass.Generator();
g.setType(type);
g.setClassLoader(ci.c2.getClassLoader());
g.setNamingPolicy(ci.namingPolicy);
g.setStrategy(ci.strategy);
g.setAttemptLoad(ci.attemptLoad);
return g.create();
}
private static class FastClassInfo {
FastClass f1;// 被代理类FastClass
FastClass f2;// 代理类FastClass
int i1;
int i2;
private FastClassInfo() {
}
}2.3.3methodProxy.invoke()与methodProxy.invokeSuper()方法调用
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
this.init();
FastClassInfo fci = this.fastClassInfo;
// f1被代理类FastClass,被代理类调用invoke方法即调用setPerson()
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
} catch (IllegalArgumentException var5) {
if (this.fastClassInfo.i1 < 0) {
throw new IllegalArgumentException("Protected method: " + this.sig1);
} else {
throw var5;
}
}
}
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
this.init();
FastClassInfo fci = this.fastClassInfo;
// f2代理类FastClass,代理类调用invoke方法即调用CGLIB$setPerson$0()代理方法
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}上面代码调用过程就是获取到代理类对应的FastClass,并执行了代理方法。还记得之前生成三个class文件吗?PersonService$EnhancerByCGLIB$eaaaed75$FastClassByCGLIB$$355cb7ea.class就是代理类的FastClass,
PersonService$FastClassByCGLIB$a076b035.class就是被代理类的FastClass。

2.4FastClass机制
Cglib动态代理执行代理方法效率之所以比JDK的高是因为Cglib采用了FastClass机制,它的原理简单来说就是:为代理类和被代理类各生成一个Class,这个Class会为代理类或被代理类的方法分配一个index(int类型)。
这个index当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比JDK动态代理通过反射调用高。下面我们反编译一个FastClass看看:
//根据方法签名获取index
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -2077043409:
if(var10000.equals("getPerson(Ljava/lang/String;)Lcom/demo/pojo/Person;")) {
return 21;
}
break;
case -2055565910:
if(var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 12;
}
break;
case -1902447170:
if(var10000.equals("setPerson()V")) {
return 7;
}
break;
//省略部分代码.....
//根据index直接定位执行方法
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
eaaaed75 var10000 = (eaaaed75)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
return new Boolean(var10000.equals(var3[0]));
case 1:
return var10000.toString();
case 2:
return new Integer(var10000.hashCode());
case 3:
return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 4:
return var10000.newInstance((Callback)var3[0]);
case 5:
return var10000.newInstance((Callback[])var3[0]);
case 6:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
case 7:
var10000.setPerson();
return null;
case 8:
var10000.setCallbacks((Callback[])var3[0]);
return null;
case 9:
return var10000.getCallback(((Number)var3[0]).intValue());
case 10:
return var10000.getCallbacks();
case 11:
eaaaed75.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
return null;
case 12:
eaaaed75.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
return null;
case 13:
return eaaaed75.CGLIB$findMethodProxy((Signature)var3[0]);
case 14:
return var10000.CGLIB$toString$3();
case 15:
return new Boolean(var10000.CGLIB$equals$2(var3[0]));
case 16:
return var10000.CGLIB$clone$5();
case 17:
return new Integer(var10000.CGLIB$hashCode$4());
case 18:
var10000.CGLIB$finalize$1();
return null;
case 19:
var10000.CGLIB$setPerson$0();
return null;
//省略部分代码....
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}可以看到,该类中大部分都是 switch-case 块,该类通过为方法的调用添加基于整数数字的索引,来减少反射调用的时间,从而将反射调用转化为直接调用
invoke() 方法的使用流程如下:
- 通过 MethodProxy#init() 方法,用当前方法的 Signature 签名构建两个 FastClass 实例和当前方法对应的 index,并存放在 FastClassInfo 中。
- 通过 FastClassInfo 中的 FastClass 实例和 index,在 FastClass 中找到对应的方法(在基于整数索引 index 的 switch-case 中查找)进行直接调用。
FastClass并不是跟代理类一块生成的,而是在第一次执行MethodProxy invoke/invokeSuper时生成的并放在了缓存中。
//MethodProxy invoke/invokeSuper都调用了init()
private void init() {
if(this.fastClassInfo == null) {
Object var1 = this.initLock;
synchronized(this.initLock) {
if(this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
fci.f1 = helper(ci, ci.c1);//如果缓存中就取出,没有就生成新的FastClass
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);//获取方法的index
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}CGLIB与JDK动态代理之间的区别
1.JDK动态代理只能对实现了接口的类进行代理,不能对普通类进行代理,这是因为JDK动态代理生成的新的代理类其父类是Proxy,java不支持类的多继承,所以只能实现接口。
2.CGLIB能够代理接口和普通类,但是被代理的类不能被final修饰,且接口中的方法不能使用final修饰
3.JDK动态代理使用Java反射技术进行操作,在生成类上效率更高
4.CGLIB使用ASM框架直接对字节码进行修改,使用了FastClass的特性。在某些情况下,类的方法执行会比较高效。
参考:Cglib动态代理实现原理 - 两条闲鱼 - 博客园,https://www.jianshu.com/p/5b123443c114,CGLIB 动态代理及其原理分析_wadreamer的博客-CSDN博客_cglib动态代理实现原理