根据实例简单理解静态代理和动态代理

引入

代理模式的概念:

使用代理模式创建代理对象,让代理对象控制目标对象的访问,并且可以在不改变目标对象的情况下添加一些其他功能。

为了更好的实现 高内聚,低耦合,我们通常不愿意去修改已经写好的类或方法,而有时候需要加上一些通用的功能,比如 打印日志之类的。

简单案例
实现用户登录时,打印出用户登录的时间(日志)

静态代理

目标类UserServiceImpl

public class UserServiceImpl implements UserService{
   public boolean login(String userName,String password) {
      if(userName.equals("sky") && password.equals("123")) {
         System.out.println("sky登录成功");
         return true;
      }else {
         return false;
      }
   }
}

接口UserService

public interface UserService {
   public boolean login(String userName, String password);
}

代理类UserProxy

public class UserProxy implements UserService{
   
   private UserService userService;
   
   public UserService getUserService() {
      return userService;
   }

   public void setUserService(UserService userService) {
      this.userService = userService;
   }
   @Override
   public boolean login(String userName, String password) {
      // TODO Auto-generated method stub
      System.out.println("sky"+new Date().toLocaleString()+"登录");
      return this.userService.login(userName, password);
   }

}

测试类Test

public class Test {
   public static void main(String[] args) {
      // TODO Auto-generated method stub
      UserProxy userProxy = new UserProxy();
      //注入目标类
      userProxy.setUserService(new UserServiceImpl());
      userProxy.login("sky", "123");
   }
}

运行结果

sky2020-4-10 21:15:01登录
sky登录成功

可见我们并没有修改UserServiceImpl里的login方法,但仍然实现了日志的打印。


这里从测试类简单回溯一下:
首先我们new了一个代理对象userProxy,然后我们又new了一个目标对象并把它注入给了代理对象。
然后执行了代理对象的login方法。
再看代理类,他和目标类都实现了相同的接口,并且代理类在重写login方法的时候return了目标类的login方法
,这就好比同一个方法重写了两次,一次是目标方法的实现,一个则是代理方法的“锦上添花”。

这样既没有破坏原方法,也给其添加了一些新功能。

但静态代理也有很大的局限性,就是目标函数太多时,要给每一个目标类都配上代理类,显然是个大工程


此时动态代理就显得方便很多

动态代理

动态代理是根据目标对象动态的生成代理对象。

目标类(UserServiceImpl)和接口(UserService)都和上述一样

这里直接给出动态代理对象生成器类LoggerHandler

其实就是日志处理器,这样一来,所有想实现日志打印的都可以借助此类动态生成自己的代理对象,并实现功能。

public class LoggerHandler implements InvocationHandler{
   //可以接收对象(目标)
   private Object delegate;
   //代理对象的创建
   public Object bind(Object delegate) {//获得目标对象并给其创建对应的代理对象
      this.delegate = delegate;
      return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
      
   }
   /**
    * method 你要调用的方法
    * args 方法对应的参数
    * resul 该方法的返回值
    */
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      // TODO Auto-generated method stub
      Object result = null;
      System.out.println("方法名是:"+method.getName());
      result = method.invoke(delegate, args);
      //在代理类里增加功能,,此处增加的 日志 功能
      System.out.println("日志 : " + args[0] + " at " + new Date().toLocaleString() + "登录");
      
      return result;
   }
}

测试类Test

public class Test {
   public static void main(String[] args) {
      // TODO Auto-generated method stub
      LoggerHandler loggerHandler = new LoggerHandler();
      //传入目标对象,,要用共同的接口
      UserService userService = (UserService) loggerHandler.bind(new UserServicelmpl());
      userService.login("sky", "123");
   }
}

运行结果

方法名是:login
sky登录成功!
日志 : sky at 2020-4-10 21:33:49登录

同样简单回溯一下:
首先测试类(Test)还是先把日志生成器(LoggerHandler)new出来一个对象。


然后还是类似地将目标对象注入(bind方法,可以说是绑定),但对应的代理对象是用接口(User Service)接收的。

再看LoggerHandler
首先他实现了InvocationHandler接口

JDK1.3之后加入了实现动态代理的API
InvocationHandler接口
使用静态方法Proxy.newProxyInstance()建立一个代理对象
利用invoke()方法来操作代理方法

这里针对一下Proxy.newProxyInstance()方法

Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);

先说第二个参数:目标对象.获得类.接口加载器
看到这就不难理解为什么要用 接口 接收对应的代理对象了,我猜这里面可能利用了反射机制(瞎猜的)


再看第二个参数:目标对象.获得类.类加载器,,
接着看invoke方法里的第二个参数 Method,,

Method不是反射里常见的方法吗?这难道?

于是点进了InvocationHandler接口,然后又懵逼的出来了。

然后在newProxyInstance方法里找了一个间接的证据
里面有反射常用的方法

菜鸡(我):说实话,这真的没搞懂,希望有会的大佬能告诉我一下,感谢。
在这里插入图片描述

关于反射的一些简单理解可以参考一下这篇文章:结合实例理解反射


再看newProxyInstance的第三个参数,这里是把自身传过去了。
鉴于刚才点进了InvocationHandler接口,所以有了自己的一点理解。
接口里很空,很多注释,还有一个空方法!(invoke)
因为动态代理要服务于不同的目标对象,每个目标对象各有不同,也会出现不同的代理对象,

所以这里的this应该是帮助目标对象更好的找到自己的代理对象吧。(猜测)

最后总结一下动态代理和静态代理的优缺点:

动态代理解决了静态代理难以复用的缺点,但在性能上有所折扣。

That’s all,,.Thank you !!

原创文章 10 获赞 10 访问量 438

猜你喜欢

转载自blog.csdn.net/weixin_43415201/article/details/105442039
今日推荐