java中动态代理的实现

 更新时间:2017年01月04日 15:08:50   作者:LSPZ  
本篇文章主要介绍了Java中两种动态代理的实现:jdk动态代理;cglib动态代理。具有一定的参考价值,下面跟着小编一起来看下吧

动态代理的实现

使用的模式:代理模式。

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。类似租房的中介。

两种动态代理:

(1)jdk动态代理,jdk动态代理是由Java内部的反射机制来实现的,目标类基于统一的接口(InvocationHandler)

(2)cglib动态代理,cglib动态代理底层则是借助asm来实现的,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。

主要应用的框架:

Spring中的AOP,Struts2中的拦截器

具体实现:

1、定义接口和实现类

package com.example.service;
public interface UserService {
  public String getName(int id);
  public Integer getAge(int id);
}
package com.example.service.impl;
import com.example.service.UserService;
public class UserServiceImpl implements UserService {
  public String getName(int id) {
    System.out.println("------getName------");
    return "cat";
  }
  public Integer getAge(int id) {
    System.out.println("------getAge------");
    return 10;
  }
}

2、jdk动态代理实现

package com.example.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler implements InvocationHandler {
  private Object target;
  /**
   * 绑定委托对象并返回一个代理类
   *
   * @param target
   * @return
   */
  public Object bind(Object target) {
    this.target = target;
    //取得代理对象
    return Proxy.newProxyInstance(target.getClass().getClassLoader(),
        target.getClass().getInterfaces(), this);  //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)
  }
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if ("getName".equals(method.getName())) {
      System.out.println("------before " + method.getName() + "------");
      Object result = method.invoke(target, args);
      System.out.println("------after " + method.getName() + "------");
      return result;
    } else {
      Object result = method.invoke(target, args);
      return result;
    }
  }
}
package com.example.jdk;

import com.example.service.UserService;
import com.example.service.impl.UserServiceImpl;

/**
 * 测试类
 */
public class RunJDK {
  public static void main(String[] args) {
    MyInvocationHandler proxy = new MyInvocationHandler();
    UserService userServiceProxy = (UserService) proxy.bind(new UserServiceImpl());
    System.out.println(userServiceProxy.getName(1));
    System.out.println(userServiceProxy.getAge(1));
  }
}

运行结果:

------before getName------
------getName------
------after getName------
cat
------getAge------
10

3、cglib动态代理实现:

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

CGLIB的核心类:

net.sf.cglib.proxy.Enhancer – 主要的增强类
net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用。

net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法
public Object intercept(Object object, java.lang.reflect.Method method,
Object[] args, MethodProxy proxy) throws Throwable;

第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。

package com.example.cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLIBProxy implements MethodInterceptor {
  private Object target;
  /**
   * 创建代理对象
   *
   * @param target
   * @return
   */
  public Object getInstance(Object target) {
    this.target = target;
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(this.target.getClass());
    // 回调方法
    enhancer.setCallback(this);
    // 创建代理对象
    return enhancer.create();
  }
  @Override
  public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    System.out.println("++++++before " + methodProxy.getSuperName() + "++++++");
    System.out.println(method.getName());
    Object result = methodProxy.invokeSuper(o, objects);
    System.out.println("++++++after " + methodProxy.getSuperName() + "++++++");
    return result;
  }
}
package com.example.cglib;
import com.example.service.UserService;
import com.example.service.impl.UserServiceImpl;
/**
 * 测试CGLIB
 */
public class RunCGLIB {
  public static void main(String[] args) {
    CGLIBProxy cglibProxy = new CGLIBProxy();
    UserService userService = (UserService) cglibProxy.getInstance(new UserServiceImpl());
    userService.getName(1);
    userService.getAge(1);
  }
}

运行结果:

++++++before CGLIB$getName$0++++++
getName
------getName------
++++++after CGLIB$getName$0++++++
++++++before CGLIB$getAge$1++++++
getAge
------getAge------
++++++after CGLIB$getAge$1++++++

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持脚本之家!

相关文章

  • 在SpringBoot中使用YourKit进行性能调优的教程详解

    在SpringBoot中使用YourKit进行性能调优的教程详解

    在应用程序的开发过程中,性能调优是一个重要的环节,在SpringBoot应用程序中,我们可以使用YourKit来进行性能调优,YourKit是一款非常强大的Java性能调优工具,在本文中,我们将介绍如何在 SpringBoot应用程序中使用YourKit进行性能调优
    2023-06-06
  • java程序运行时内存分配详解

    java程序运行时内存分配详解

    这篇文章主要介绍了java程序运行时内存分配详解 ,需要的朋友可以参考下
    2016-07-07
  • Java中Maven的依赖管理问题小结

    Java中Maven的依赖管理问题小结

    这篇文章主要介绍了Java中Maven的依赖管理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-05-05
  • Spring @Bean 修饰方法时注入参数的操作方法

    Spring @Bean 修饰方法时注入参数的操作方法

    对于 Spring 而言,IOC 容器中的 Bean 对象的创建和使用是一大重点,Spring 也为我们提供了注解方式创建 bean 对象:使用 @Bean,这篇文章主要介绍了Spring @Bean 修饰方法时如何注入参数,需要的朋友可以参考下
    2023-10-10
  • 关于Springboot+gateway整合依赖并处理依赖冲突问题

    关于Springboot+gateway整合依赖并处理依赖冲突问题

    这篇文章主要介绍了Springboot+gateway整合依赖并处理依赖冲突问题,给大家提到了spring boot版本和spring cloud版本,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-01-01
  • Java 生成随机单据号的实现示例

    Java 生成随机单据号的实现示例

    本文主要介绍了Java 生成随机单据号的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-09-09
  • IDEA 重新导入依赖maven 命令 reimport的方法

    IDEA 重新导入依赖maven 命令 reimport的方法

    这篇文章主要介绍了IDEA 重新导入依赖maven 命令 reimport的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • 详解使用IntelliJ IDEA 配置Maven(入门)

    详解使用IntelliJ IDEA 配置Maven(入门)

    本篇文章主要介绍了详解使用IntelliJ IDEA 配置Maven(入门),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • Java利用Phantomjs实现生成图片的功能

    Java利用Phantomjs实现生成图片的功能

    这篇文章主要介绍了Java利用Phantomjs实现生成图片的功能,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-08-08
  • MyBatis-plus数据库字段排序不准确的解决

    MyBatis-plus数据库字段排序不准确的解决

    这篇文章主要介绍了MyBatis-plus数据库字段排序不准确的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02

最新评论