代理---静态代理--动态代理
程序员文章站
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"));
}
代理必须依赖真正的实现类存在,代理不能直接做具体的业务实现,只是一个中间件的作用,在这个中间件中加了一些逻辑控制,如加入日志,加入权限控制等,具体的业务实现还需要具体的实现类来完成。所以代理不能单独存在,必须搭配实现类,并且和实现类实现同样的接口。
下一篇: 【C#】判断list集合中是否存在相同项