暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Java动态代理

程序员升级之路 2021-02-23
111

一、什么是动态代理

       打个比方,如果系统中有2个类,A和B,以前是A依赖B,即A直接调用B的某个方法,表示为A->B;


       现在调用链路变成A->B->C,即A先调用B,B再调用C,不过B在调用C前后会加些逻辑,这时候B相当于一个代理人的角色,并且B的拦截是在程序运行过程中动态产生的,这种情况我们叫动态代理。


二、为什么需要动态代理

       动态代理主要有以下几个作用:

       1、提高系统的扩展性

       像上面的情况,以前的调用链是A->B,现在要在B的基础上加些逻辑,如B是一个订单服务,这个B是的代码我们拿不到,只有Jar包,我们想在保存订单后发个邮件,当然我们可以在调用方去做,不过每个调用方都做这个事情,相同的逻辑就会分散在不同的地方,不便于后续的维护,这个时候就可以通过动态代理来增强系统的功能,并且不用修改B的代码。


       2、精简代码,将逻辑收拢

       这个什么意思呢,通过动态代理我们可以让使用者非常简单的使用,不用关注一些实现的细节,如Mybatis中只要写个接口,然后在Xml中写Sql语句,不用写如何读取Sql,怎么与JDBC打交道的代码,就可以轻松的访问数据库了。

        其它还有Fein,也只要定义接口就可以了,如何执行Url请求,怎么解析响应的代码都不用我们写,让访问Rest服务变得非常简单。


三、Java中动态代理使用

主要有2种方式:

1、JDK代理

     其代理对象必须实现接口InvocationHandler,它的实现方式是在运行期间创建一个接口的实现类来完成目标对象的代理。


     使用步骤如下:

     1)、实现InvocationHandler接口;

     2)、调用Proxy.newProxyInstance生成代理对象


先实现接口InvocationHandler

    public class JDKProxy implements InvocationHandler{
        Object target;  //被代理的对象


    public JDKProxy(Object target) {
    this.target = target;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("JDKProxy before");
            Object result = method.invoke(target, args); 
            System.out.println("JDKProxy after");


            return result;
    }
     }


    编写测试代码:

      public void testJDKProxy(){
      UserServiceImpl userServiceImpl = new UserServiceImpl();
      ClassLoader classLoader = userServiceImpl.getClass().getClassLoader();
      Class[] interfaces = userServiceImpl.getClass().getInterfaces();
      InvocationHandler logHandler = new JDKProxy(userServiceImpl);
      UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, logHandler);


      proxy.select();
      }


      UserServiceImpl代码如下:

        public class UserServiceImpl implements UserService {
            public void select() {
                System.out.println("select被调用");
        }


        UserSerivice接口定义如下:

          public interface UserService {
          void select();
          }


          2、CGLIB代理

               它的实现是通过ASM(开源的Java字节码编辑类库)操作字节码,性能比JDK代理的强。


           使用步骤如下:

           1)、实现接口MethodInterceptor

           2)、生成Enhancer类实例,调用setCallback方法绑定代理对象


           先实现接口MethodInterceptor

            public class CglibProxy implements MethodInterceptor{


            @Override
            public Object intercept(Object object, Method method, Object[] objects, net.sf.cglib.proxy.MethodProxy methodProxy){
            Object result=null;


                    System.out.println("CglibProxy before");


            try {
                        result = methodProxy.invokeSuper(object, objects);
            }catch (java.lang.Throwable ex){
            System.out.println(ex.getMessage());
            }
                    System.out.println("CglibProxy after");


            return result;
                }
            }

            编写测试代码

              public void testCglibProxy(){
              CglibProxy proxy = new CglibProxy();
              Enhancer enhancer = new Enhancer();
                      //设置超类,注意是接口不是实现类
                      enhancer.setSuperclass(UserService.class);
                      //绑定代理对象
              enhancer.setCallback(proxy);


                      UserService dao = (UserService)enhancer.create();
              dao.update();
              dao.select();
              }


              Spring Cloud系列二:Ribbon

              MyBatis源码分析三:Sql执行

              Codis  Proxy是如何处理一个请求的

              文章转载自程序员升级之路,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论