欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

代理---静态代理--动态代理

程序员文章站 2022-03-04 12:33:33
...

首先,明确一点:代理不会改变之前写的所有代码,代理需要继承相同的接口。

那么问题来了,为什么要用到代理?

假设有一个接口 UserManager, 这个接口中有很多待实现的方法,此时,有一个实现类实现了这个接口 UserManagetImpl, 并且已经上线,客户已经在使用了,所以讲道理来说,不管是接口或者实现类,都必须做到对修改关闭,对扩展开放。

此时,有一个问题,如果我们需要给接口中每一个方法的实现类的具体实现语句中,加入别的逻辑,比如增加安全性检查,或者增加事务和日志,则按照最简单的写法是,修改实现类 UserManagerImpl 的每一个方法,加上相应的语句即可。但是,这种做法违背了上面说的 对修改关闭 原则。

 

于是,出现了代理,这里的代理指的是静态代理。

// 接口  UserManager.java
 
public interface UserManager {

    public boolean addUser(String username, String password);

    public void delUser(int userId);

    public String findUserById(int userId);
  
    public void modifyUser(int userId, String username, String password);

}
// 接口的实现类 UserManagerImpl.java

public class UserManagerImpl implements UserManager {

  @Override
    public boolean addUser(String username, String password) {

       System.out.println("------UserManagerImpl.addUser-----");
       return true;
    }

  @Override
    public void delUser(int userId) {

       System.out.println("------UserManagerImpl.delUser-----");
    }

  @Override
    public String findUserById(int userId) {

       System.out.println("------UserManagerImpl.findUserById-----");
       return "zhangsan";
    }

  @Override
    public void modifyUser(int userId,String username, String password) {

       System.out.println("------UserManagerImpl.modifyUser-----");
    
    }

  @Override
    public void checkSecurity() {

       System.out.println("------UserManagerImpl.checkSecurity-----");
     
    }

}
//静态代理,需要实现同样的接口
//代理不会改变之前的代码,对修改关闭
//将实际的实现通过构造器传递到代理中,通过代理调用实际实现类中的具体实现方法

public class UserManagerProxy implements UserManager {

    private UserNamager userManager;
    public UserManagerProxy(UserNamager userManager) {

       this.userManager = userManager;
   }

  @Override
    public boolean addUser(String username, String password) {
       checkSecurity();
       userManager.addUser(username,password);
       return true;
    }

  @Override
    public void delUser(int userId) {
       checkSecurity();
       userManager.delUser(userId);
    }

  @Override
    public String findUserById(int userId) {
       checkSecurity();
       userManager.findUserById(userId);
       return "zhangsan";
    }

  @Override
    public void modifyUser(int userId,String username, String password) {
       checkSecurity();
       userManager.modifyUser();
    
    }

  @Override
    public void checkSecurity() {
       System.out.println("------UserManagerImpl.checkSecurity-----");
     
    }

}
//测试类 ProxyTest.java

public class ProxyTest {
 
     public static void main(String[] args) {
 
       //在测试类中传入具体实现类 UserManagerImpl,传到代理的构造器中
       UserManagerProxy  userManagerProxy  = new UserManagerProxy(new UserManagerImpl());
       System.out.println(userManagerProxy.addUser("zhangsan","123456"));
}


}

以上,是一个简单的静态代理的例子,最需要注意的点如下:

(1) 代理类和具体的实现类继承的是同一个接口

(2) 代理的实现对修改关闭,对扩展开放,也只是对具体实现类的扩展

(3) 客户端通过代理去间接的调用到具体的实现类,在代理中会增加一部分控制逻辑

静态代理缺陷: 在具体的实现类中有多少个接口,就需要加多少次逻辑,并且一次性只能代理一个固定的接口,不灵活,代码不简洁,所以出现了动态代理.

动态代理:

// 接口  UserManager.java
 
public interface UserManager {

    public boolean addUser(String username, String password);

    public void delUser(int userId);

    public String findUserById(int userId);
  
    public void modifyUser(int userId, String username, String password);

}
// 接口的实现类 UserManagerImpl.java

public class UserManagerImpl implements UserManager {

  @Override
    public boolean addUser(String username, String password) {

       System.out.println("------UserManagerImpl.addUser-----");
       return true;
    }

  @Override
    public void delUser(int userId) {

       System.out.println("------UserManagerImpl.delUser-----");
    }

  @Override
    public String findUserById(int userId) {

       System.out.println("------UserManagerImpl.findUserById-----");
       return "zhangsan";
    }

  @Override
    public void modifyUser(int userId,String username, String password) {

       System.out.println("------UserManagerImpl.modifyUser-----");
    
    }

}
//动态代理的核心类 SecurityHandler.java
//需要实现InvocationHandler 接口

public class SecurityHandler implements InvocationHandler {

    private Object targetObject;


    //通过 createProxyInstance 传入具体的实现类
    public Object createProxyInstance(Object targetObject) {

        this.targetObject = targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                                      targetObject.getClass().getInterfaces(), this);
 
    }
 
@Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
    //在 invoke 方法中加逻辑
      checkSecurity();

    //真正调用目标的方法
      Object o1 = method.invoke(targetObject,objects);
      return o1;

    }

    private void checkSecurity() {
     System.out.println("------checkSecurity-----");
    }

}
//动态代理测试类 

public class Client {

  SecurityHandler handler = new SecurityHandler();

  //动态生成
  //传入真正的实现类 UserManagerImpl
  UserManager userManager = (UserManager )handler.createProxyInstance(new UserManagerImpl());
  System.out.println(userManager.addUser("zhangsan","123456"));

}

代理必须依赖真正的实现类存在,代理不能直接做具体的业务实现,只是一个中间件的作用,在这个中间件中加了一些逻辑控制,如加入日志,加入权限控制等,具体的业务实现还需要具体的实现类来完成。所以代理不能单独存在,必须搭配实现类,并且和实现类实现同样的接口。