jdk动态代理和cglib的区别

 我来答
就烦条0o
2018-07-28 · 知道合伙人软件行家
就烦条0o
知道合伙人软件行家
采纳数:33315 获赞数:46492
从事多年系统运维,喜欢编写各种小程序和脚本。

向TA提问 私信TA
展开全部

关于动态代理和静态代理

当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象。

按照代理对象的创建时期不同,可以分为两种:

静态代理:事先写好代理对象类,在程序发布前就已经存在了;

动态代理:应用程序发布后,通过动态创建代理对象。

静态代理其实就是一个典型的代理模式实现,在代理类中包装一个被代理对象,然后影响被代理对象的行为,比较简单,代码就不放了。

其中动态代理又可分为:JDK动态代理和CGLIB代理。

1.JDK动态代理

此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。

代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。

JDK动态代理只能针对实现了接口的类生成代理。

2.CGLIB代理

CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,

主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。

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

JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。

PS:final 所修饰的数据具有“终态”的特征,表示“最终的”意思:

  • final 修饰的类不能被继承。

  • final 修饰的方法不能被子类重写。

  • final 修饰的变量(成员变量或局部变量)即成为常量,只能赋值一次。

  • final 修饰的成员变量必须在声明的同时赋值,如果在声明的时候没有赋值,那么只有 一次赋值的机会,而且只能在构造方法中显式赋值,然后才能使用。

  • final 修饰的局部变量可以只声明不赋值,然后再进行一次性的赋值。

  • 参考代码

    CGLIB: 

    12345678
  •    
  • public Object createProxyObject(Object obj) {     this.targetObject = obj;     Enhancer enhancer = new Enhancer();     enhancer.setSuperclass(obj.getClass());     enhancer.setCallback(this);     Object proxyObj = enhancer.create();     return proxyObj;// 返回代理对象,返回的对象其实就是一个封装了“实现类”的代理类,是实现类的实例。 } 
  •    
  • JDK: 

    12345
  •    
  • public Object newProxy(Object targetObject) {// 将目标对象传入进行代理     this.targetObject = targetObject;  <br>    //注意这个方法的参数,后面是类实现的接口    return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),             targetObject.getClass().getInterfaces(), this);// 返回代理对象 }
  •    
  • 在代码中可以看到,在生成代理类时,传递的是实现类所实现的接口 targetObject.getClass().getInterfaces(),所以JDK只能对于接口进行做代理。如果换成类的话,则会抛java.lang.ClassCastException异常。 

    在Spring的源码中,可以看到很多生成代理类的代码。

    动态代理的应用

    AOP(Aspect-OrientedProgramming,面向切面编程),AOP包括切面(aspect)、通知(advice)、连接点(joinpoint),实现方式就是通过对目标对象的代理在连接点前后加入通知,完成统一的切面操作。

    实现AOP的技术,主要分为两大类:

    一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;

    二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

    Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。

    默认的策略是如果目标类是接口,则使用JDK动态代理技术,如果目标对象没有实现接口,则默认会采用CGLIB代理。

    如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。

Storm代理
2023-07-25 广告
StormProxies是一家可靠的代理服务提供商,提供原生IP(住宅原生IP)和高匿名代理服务。以下是关于StormProxies的原生IP服务的一些信息:1. 住宅原生IP:StormProxies提供的住宅原生IP是指从真实的家庭或企... 点击进入详情页
本回答由Storm代理提供
jiaxin8000xxsc
2017-07-22 · TA获得超过3.6万个赞
知道大有可为答主
回答量:4009
采纳率:88%
帮助的人:941万
展开全部

jdk动态代理举例如下:

public class JDKProxyimplements InvocationHandler{
private UserDao userDao;
 
public JDKProxy(UserDao userDao) {
    super();
    this.userDao = userDao;
}
 
public UserDao createProxy() {
        // 创建代理对象  
        // 1、定义代理类的类加载器  
        // 2、代理类要实现的接口列表  
        // 3、 指派方法调用的调用处理程序 
    UserDao proxy = (UserDao)Proxy.newProxyInstance(userDao.getClass()
            .getClassLoader(),userDao.getClass().getInterfaces(), this);
    return proxy;
}
 
// 调用目标对象的任何一个方法 都相当于调用invoke();
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
    if("add".equals(method.getName())){
        // 记录日志:
        System.out.println("日志记录=================");
        Object result = method.invoke(userDao, args);
        return result;
    }
    returnmethod.invoke(userDao, args);
}
}

CGLIB(Code GenerationLibrary)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate支持它来实现PO(Persistent Object 持久化对象)字节码的动态生成Hibernate生成持久化类的javassist.

CGLIB生成代理机制:其实生成了一个真实对象的子类.

 
public class CGLibProxyimplements MethodInterceptor{
private ProductDao productDao;
 
public CGLibProxy(ProductDao productDao) {
    super();
    this.productDao =productDao;
}

public ProductDao createProxy(){
    // 使用CGLIB生成代理:
    // 1.创建核心类:
    Enhancer enhancer = newEnhancer();
    // 2.为其设置父类:
    enhancer.setSuperclass(productDao.getClass());
    // 3.设置回调:
    enhancer.setCallback(this);
    // 4.创建代理:
    return (ProductDao)enhancer.create();
}
 

public Object intercept(Object proxy, Method method, Object[] args,
        MethodProxy methodProxy) throws Throwable {
    if("add".equals(method.getName())){
        System.out.println("日志记录==============");
        Object obj = methodProxy.invokeSuper(proxy, args);
        return obj;
    }
    returnmethodProxy.invokeSuper(proxy, args);
}
}

结论:在Spring框架中,如果类实现了接口,就使用JDK的动态代理生成代理对象,如果这个类没有实现任何接口,使用CGLIB生成代理对象.

本回答被提问者采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式