温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java 动态代理的理解与Cglib动态代理实现

发布时间:2020-06-12 12:22:57 来源:网络 阅读:520 作者:nineteens 栏目:编程语言

  什么是动态代理?

  先说下静态代理:

  也即是说,在程序运行前,已经有了编译好的类,这个就是静态代理,

  动态代理:

  也即,在程序运行前, 代理类并不存在,而是在程序运行时,动态生成的类是动态代理类。

  可能会有如下思考

  代理模式是怎样的?用什么技术实现?

  为什么要使用代理模式呢?有什么好处?

  动态代理的应用场景有哪些?

  先说说动态代理的实现吧:

  动态代理主要使用的是Java 反射技术:

  JavaAPI 中关于InvocationHandler有大致这么一段描述,每个代理类都要实现InvocationHandler这个接口,每个代理类都会关联到一个handle,

  当一个代理类调用方法时,会转到InvocationHandler的Invoke方法进行调用。

  以下代码有引用以为牛人代码

  看下InvocationHandler源码,我这就不再写一遍了。

  public interface InvocationHandler

  {

  public abstract Object invoke(Object obj, Method method, Object aobj[])

  throws Throwable;

  }

  这个invoke方法中有几个参数 :

  obj:表示我们要调用的真实对象

  method:表示我们要调用的真实对象的某个方法。

  aobj[] :表示真实对象某个方法接受的参数。

  怎么用这个InvocationHandler 这个接口,主要看proxy这个类:

  Proxy是创建一个代理对象的类

  Proxy这个类有这个一个方法:是用的最多的方法

  public static Object newProxyInstance(ClassLoader classloader, Class aclass[], InvocationHandler invocationhandler)

  throws IllegalArgumentException

  参数:

  classloader: 定义了由那个ClassLoader对对象进行加载

  aclass[]: 是为代理对象提供了哪些接口,表示代理对象实现了这些接口,

  invocationhandler: 表示代理对象调用方法时会关联到那个invocationhandler

  主要通过类Proxy与接口invocationhandler实现动态代理:

  看下具体动态代理实现加深理解:

  1.首先肯定是需要一个接口的:

  public interface UserService {

  public String getName(int id);

  public Integer getAge(int id);

  }

  还需要这个接口的实现,也就是代理对象:

  public class UserServiceImpl implements UserService {

  @Override

  public String getName(int id) {

  System.out.println("------getName------");

  return "Tom";

  }

  @Override

  public Integer getAge(int id) {

  System.out.println("------getAge------");

  return 10;

  }

  }

  还需要自定义一个invocationhandler ,自己实现invoke方法:

  import java.lang.reflect.InvocationHandler;

  import java.lang.reflect.Method;

  public class MyInvocationHandler implements InvocationHandler {

  private Object target;

  MyInvocationHandler() {

  super();

  }

  MyInvocationHandler(Object target) {

  super();

  this.target = target;

  }

  @Override

  public Object invoke(Object o, 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;

  }

  }

  }

  最后再看下proxy是怎样的使用这个接口,还有invocationhandler的

  import java.lang.reflect.InvocationHandler;

  import java.lang.reflect.Proxy;

  public class TestProxy {

  public static void main(String[] args) {

  UserService userService = new UserServiceImpl();

  InvocationHandler invocationHandler = new MyInvocationHandler(userService);

  UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),

  userService.getClass().getInterfaces(), invocationHandler);

  System.out.println(userServiceProxy.getName(1));

  System.out.println(userServiceProxy.getAge(1));

  }

  }

  以上可以看到可以清晰理解proxy的newproxyInstance是用来生成代理对象的, userService是指向具体 的实现

  UserServiceImpl

  给newproxyInstance方法传入实际的classLoader,实际类对应的接口,与调用类方法的invocationhandler即可实现:

  System.out.println("++++++before " + method.getName() + "++++++");

  其实上面这个一行代码就有***性质,aop时再详细讨论.

  上面可以看到 使用这个反射技术实现动态代理,需要定义一个接口,但是有时候其实不想定义接口,只希望定义好实现类,然后你再在方法运行前,运行后加些内容即可。

  这个就考虑了一个CGLIB这个可是不错的使用CGLIB实现动态代理很方便。

  Cglib 采用的是ASM字节码技术,利用字节码生成代理类。效率比反射要高,但是不能代理final修身的类,clglib元素是集成被代理的类。final类不能被继承。

  下面看下cglib具体实现:

  下载 cglib包和asm包,你的工程需要依赖这两个包:

  首先需要一个非final类,不再和反射一样需要一个接口了

  public class StudentService {

  public String getName(){

  System.out.println("------getName------");

  return "Tom";

  }

  public Integer getID(){

  System.out.println("------getID------");

  return 10;

  }

  }

  接下来就看怎么代理上面的类了,需要定义一个拦截器:

  import net.sf.cglib.proxy.MethodInterceptor;

  import net.sf.cglib.proxy.MethodProxy;

  import java.lang.reflect.Method;

  public class CglibProxy implements MethodInterceptor {

  @Override

  public Object intercept(Object o, Method method, Object[] args,

  MethodProxy methodProxy) throws Throwable {

  System.out.println("++++++before " + methodProxy.getSuperName()

  + "++++++");

  System.out.println(method.getName());

  Object o1 = methodProxy.invokeSuper(o, args);

  System.out.println("++++++before " + methodProxy.getSuperName()

  + "++++++");

  return o1;

  }

  }

  上面的interceptf方法和invocationhandler中的invoke方法类似,通过interceptf来真正调用方法invokeSuper:

  最后看下Cglb具体怎么代理StudentService这个类吧:

  import net.sf.cglib.proxy.Enhancer;

  public class TestCglib {

  public static void main(String[] args) {

  CglibProxy cglibProxy = new CglibProxy();

  Enhancer enhancer = new Enhancer();

  enhancer.setSuperclass(StudentService.class);

  enhancer.setCallback(cglibProxy);

  StudentService o = (StudentService)enhancer.create();

  System.out.println(o.getName());

  // System.out.println(o.getID());

  }

  }

  上面的o即是 代理类,该类可以访问真实的Studentservice方法:

  运行结果:无锡妇科检查多少钱 http://www.120csfkyy.com/

  ++++++before CGLIB$getName$1++++++

  getName

  ------getName------

  ++++++before CGLIB$getName$1++++++

  Tom

  使用Cglib 有啥好处?

  看下面代码:

  public class TestCglib {

  public static void main(String[] args) {

  CglibProxy cglibProxy = new CglibProxy();

  Enhancer enhancer = new Enhancer();

  enhancer.setSuperclass(StudentService.class);

  enhancer.setCallback(cglibProxy);

  StudentService o = (StudentService)enhancer.create();

  System.out.println(o.getName());

  // System.out.println(o.getID());

  Enhancer enhancer1 = new Enhancer();

  enhancer1.setSuperclass(UserServiceImpl.class);

  enhancer1.setCallback(cglibProxy);

  UserServiceImpl obj = (UserServiceImpl)enhancer1.create();

  System.out.println(obj.getName(1));

  // System.out.println(o.getID());

  }

  }

  只要写一个

  cglibProxy

  就可以是实现

  对UserServiceImpl 与 StudentService进行代理

  减少了代码的繁琐,只有有这么一个代理就够了,其次方便维护,解耦合,要是有问题,只要去找 原始类就可以了


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI