`

JDK动态代理为什么必须针对接口?其与CGLIB的对比01

阅读更多

 

http://www.cnblogs.com/frankliiu-java/articles/1896443.html

示例代码:

 

public interface AopService {
public void doService();
}
public class AopServiceImpl implements AopService {
private String singal;
public String getSingal() {
return singal;
}

public AopServiceImpl(){}
public AopServiceImpl(String singal){
this.singal = singal;
}

@Override
public void doService() {

System.out.println("do service method is being invoked now!!!");
}
}
public class ProxyFactory implements InvocationHandler {
private Object targetObject;
public Object createTargetObject(Object targetObject){
this.targetObject = targetObject;
return Proxy.newProxyInstance(this.targetObject.getClass()
.getClassLoader(),
this.targetObject.getClass().getInterfaces(), this);
}

@Override
public Object invoke(Object arg0, Method method, Object[] args)
throws Throwable {
        AopServiceImpl aopservice = (AopServiceImpl)this.targetObject;
        Object result = null;
        if(aopservice.getSingal()!=null){
        result = method.invoke(targetObject, args);
        }
return result;
}
}

 

 

测试代码:

 

public class AopTests {

@Test
public void Tests(){
ProxyFactory pf = new ProxyFactory();
//AopService as = (AopService)pf.createTargetObject(new AopServiceImpl());
AopService as = (AopService)pf.createTargetObject(new AopServiceImpl("Frank"));
        as.doService();
}
}

 

 

JDK动态代理为什么必须用接口以及与CGLIB的对比 


这两天对AOP原理感兴趣了,试验了JDK动态代理与CGLIB动态代理。从Spring的AOP框架介绍中得知对于使用接口的类,Spring使用JDK动态代理(原来做项目中试图从Bean强制转换为实现类,结果报错,原来是这么回事),没有接口的就使用别的AOP框架aspectj,但这些都是依赖于Java字节码工具ASM生成一个原类的新类,调用Callback

但是JDK动态代理为什么必须使用接口一直很疑惑,难道原理不是像ASM一样修改字节码吗?带着这个疑问,开始看JDK的Proxy代码。使用JDK动态代理的代码代码

ITestBean tb = (ITestBean) Proxy.newProxyInstance(tb.getClass().getClassLoader(), tb.getClass().getInterfaces(), new TestBeanHander(tb));

于是从创建代理函数看起,即public static Object newProxyInstance(ClassLoader loader,
   Class<?>[] interfaces, InvocationHandler h)
   throws IllegalArgumentException , 

通过源码可以看到,这个类第一步生成一个代理类(注意,这里的参数就是接口列表),

Class cl = getProxyClass(loader, interfaces);

然后通过代理类找到构造参数为InvocationHandler的构造函数并生成一个新类。

Constructor cons = cl.getConstructor(constructorParams);//这个有用,在后面细说
return (Object) cons.newInstance(new Object[] { h });  

接口起什么作用呢,于是又看getProxyClass方法的代码,这个源码很长,就不细说了。大致分为三段:

第一:验证

第二:缓存创建新类的结构,如果创建过,则直接返回。(注意:这里的KEY就是接口列表)

第三:如果没有创建过,则创建新类

创建代码如下

    long num;

   //获得代理类数字标识 
   synchronized (nextUniqueNumberLock) {
     num = nextUniqueNumber++;
    }

 

    //获得创建新类的类名$Proxy,包名为接口包名,但需要注意的是,如果有两个接口而且不在同一个包下,也会报错

   String proxyName = proxyPkg + proxyClassNamePrefix + num;

    //调用class处理文件生成类的字节码,根据接口列表创建一个新类,这个类为代理类,
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
      proxyName, interfaces);
    //通过JNI接口,将Class字节码文件定义一个新类
     proxyClass = defineClass0(loader, proxyName,
       proxyClassFile, 0, proxyClassFile.length);

 

根据前面的代码Constructor cons = cl.getConstructor(constructorParams);

可以猜测到接口创建的新类proxyClassFile 不管采用什么接口,都是以下结构

public class $Proxy1 extends Proxy implements 传入的接口{

    

}
生成新类的看不到源代码,不过猜测它的执行原理很有可能是如果类是Proxy的子类,则调用InvocationHandler进行方法的Invoke

到现在大家都应该明白了吧,JDK动态代理的原理是根据定义好的规则,用传入的接口创建一个新类,这就是为什么采用动态代理时为什么只能用接口引用指向代理,而不能用传入的类引用执行动态类。

cglib采用的是用创建一个继承实现类的子类,用asm库动态修改子类的代码来实现的,所以可以用传入的类引用执行代理类

JDK动态代理与CGLIB对比如下:

//JDK动态代理测试代码


补充说明,如果在实现类中,接口定义的方法互相调用不会在调用InvocationHandler的invoke方法,JDK动态代理应该不是嵌入到Java的反射机制中,而是在反射机制上的一个调用。 

 

分享到:
评论

相关推荐

    浅谈JDK动态代理与CGLIB代理去区别

    JDK动态代理的局限性在于,它只能为实现了至少一个接口的类创建代理,因为代理对象必须继承自这些接口。这种方式适用于那些基于接口进行编程的设计,比如Spring AOP中的Advisor和Advice。 相反,CGLIB(Code ...

    Spring框架中JDK动态代理和cglib动态代理

    JDK 动态代理为什么必须使用接口?这主要是因为 JDK 动态代理是基于接口的代理,它需要一个接口来生成代理类。如果我们想使用 JDK 动态代理,必须提供一个接口,并且将其实现类交给 JDK 动态代理来生成代理类。这样...

    java代理机制 JDK动态代理和cglib代理 详解

    JDK动态代理基于接口实现,它要求被代理的类必须实现至少一个接口。在运行时,Java会动态地创建一个新的类,这个类实现了与原始类相同的接口,并且在调用接口方法时,可以插入自定义的逻辑。这样,我们就可以在不...

    JDK动态代理和CGLIB代理

    相比于JDK动态代理,CGLIB可以在没有接口的情况下进行代理,因此对于未实现接口的类,CGLIB是更好的选择。CGLIB使用ASM库来生成和加载代理类的字节码。 使用CGLIB代理通常需要引入cglib库,然后通过`...

    Jdk动态代理和cglib动态代理原理

    与JDK动态代理不同,CGLIB不依赖于接口,而是通过继承目标类来创建代理对象。 1. **CGLIB核心组件**:主要包括`Enhancer`、`Callback`和`MethodInterceptor`。`Enhancer`是增强对象的主要工具,`Callback`是一系列...

    AOP之JDK动态代理和CGLib动态代理

    综上所述,AOP为软件设计带来了模块化和解耦的优势,Spring通过JDK动态代理和CGLib动态代理提供了灵活的实现。理解并掌握这两种代理方式,对于深入理解和有效利用Spring AOP至关重要。在实际开发中,根据业务需求和...

    CGLIB 和 JDK生成动态代理类的区别

    与JDK动态代理不同,CGLIB并不依赖于接口,而是直接对类进行增强。它使用ASM库在内存中构建新的字节码,生成的目标类会继承自原始类。因此,对于没有实现接口的类,CGLIB可以提供动态代理功能。 性能方面,CGLIB...

    jdk与cglib动态代理与底层实现

    与JDK动态代理不同,CGLIB并不依赖接口,而是通过字节码技术生成一个被代理类的子类来实现。这使得CGLIB能够代理没有实现接口的类。CGLIB的核心是ASM库,它能直接操作字节码生成新的类。在Spring中,如果目标类没有...

    jdk动态代理和CGlib动态代理

    JDK动态代理适用于目标类已经实现了接口的情况,而CGlib则可以处理未实现接口的类。两者都可以在运行时增加额外的行为,但实现方式和性能特性有所不同。JDK动态代理通常更简洁,因为不需要生成子类,但对目标类的...

    jdk 的动态代理和CGLIB代理

    jdk 的动态代理和CGLIB代理

    JDK代理和Cglib代理

    与JDK代理不同,Cglib不需要目标对象实现任何接口,而是通过继承的方式创建代理。这使得Cglib在处理未实现接口的类时更为灵活。 1. **Cglib Enhancer**:Enhancer是Cglib的核心类,它负责生成子类并进行增强。我们...

    java 动态代理实例(JDK代理与CGLIB代理)

    动态代理主要分为两种:JDK代理和CGLIB代理。 **JDK代理**是基于接口的代理,它通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口实现。当我们的目标对象实现了特定的接口时,我们可以...

    jdk动态代理 cglib3.0动态代理

    JDK和CGLIB是两种常用的实现Java动态代理的方式。本文将深入探讨这两个库以及它们的工作原理。 **JDK动态代理** JDK动态代理基于Java反射API实现,它提供了`java.lang.reflect.Proxy`类和`java.lang.reflect....

    java动态代理实例(jdk动态代理和cglib)

    总结来说,JDK动态代理适用于需要代理接口的情况,而CGLIB则可以处理没有接口的类。两者都是为了在运行时增强对象的功能,提供了灵活的代码扩展机制。在实际开发中,可以根据具体需求选择适合的动态代理方式。

    jdk与cglib动态度代理的区别原理

    主要存在两种常见的动态代理技术:JDK动态代理和CGLIB(Code Generation Library)动态代理。本文将深入探讨这两种技术的区别和原理。 **JDK动态代理**: JDK动态代理是Java标准库提供的一种代理机制,位于`java....

    Jdk动态代理,cglib动态代理,反射和拦截器(链)示例

    当JDK动态代理无法满足需求,例如代理的目标类没有实现接口时,CGLIB就能派上用场。CGLIB是一个强大的高性能的代码生成库,它可以在运行期扩展Java类与实现Java接口。CGLIB通过生成子类并在子类的方法上织入增强代码...

    JAVA动态代理实现Demo(JDK动态代理和CGLIB动态代理)

    JDK动态代理基于接口实现,也就是说,被代理的对象必须实现至少一个接口。代理机制的核心是`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。以下是一些关键知识点: 1. **Proxy类**:...

    代理模式-静态动态代理-jdk动态代理-cglib动态代理

    Spring支持JDK动态代理和CGLIB动态代理,根据目标类是否实现了接口来选择合适的代理方式。 总结来说,代理模式是软件设计中的一个重要工具,它提供了在不修改原始对象的前提下扩展功能的能力。Java中的静态代理、...

    JDK动态代理_JDK动态代理

    本文将详细介绍JDK动态代理的原理与应用,帮助读者深入理解其工作方式以及如何在实际项目中运用。 #### 二、JDK动态代理简介 JDK动态代理是Java平台提供的一个工具包,用于在运行时创建代理对象。它主要适用于实现...

    JDK动态代理和Cglib动态代理实例源码

    相比JDK动态代理,Cglib不需要目标类实现接口,因此适用于无法修改源码或不希望实现接口的情况。 2. **Cglib动态代理实现过程**: - 引入Cglib库,如cglib-nodep-3.3.0.jar。 - 创建一个实现了`MethodInterceptor...

Global site tag (gtag.js) - Google Analytics