Java代理设计模式

Java代理设计模式

定义

Java代理模式(Proxy Pattern)是一种常用的设计模式,它为其他对象提供一种代理以控制对这个对象的访问。简单来说,我们使用代理对象来代替对真实对象的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

对应角色

  • Subject(抽象主题角色):它声明了真实主题和代理主题的共同接口,这样一来在任何使用真实主题的地方都可以使用代理主题。
  • Proxy(代理主题角色):它包含了对真实主题的引用,从而可以在任何时候操作真实主题对象;在代理主题角色中提供一个与真实主题角色相同的接口,以便在任何时候都可以替代真实主题;代理主题角色还可以控制对真实主题的使用,负责在需要的时候创建和删除真实主题对象,并对真实主题对象的使用加以约束。
  • RealSubject(真实主题角色):它定义了代理角色所代表的真实对象,在真实主题角色中实现了真实的业务操作,客户端可以通过代理主题角色间接调用真实主题角色中定义的操作。

优缺点

优点

  • 职责清晰:真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰。
  • 高扩展性:具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。

缺点

  • 类个数增加:代理模式会造成系统中类的个数增加,比不使用代理模式增加了代理类,系统的复杂度增加。
  • 性能降低:在客户端和目标对象之间,增加了一个代理对象,造成请求处理速度变慢。

应用场景

  • 需要为一个对象在不同的地址空间提供局部代表的时候,可以使用远程代理。
  • 需要按需创建开销很大的对象的时候,可以使用虚拟代理。
  • 需要控制对象访问权限的时候,可以使用保护代理。

实例

// 抽象主题角色
interface Subject {
    void request();
}

// 真实主题角色
class RealSubject implements Subject {
    public void request() {
        System.out.println("RealSubject request");
    }
}

// 代理主题角色
class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    public void request() {
        System.out.println("ProxySubject preRequest");
        realSubject.request();
        System.out.println("ProxySubject postRequest");
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.request();
    }
}

JDK动态代理(Springboot实现)

首先,我们定义一个接口UserService,它有一个方法getUserById用于根据用户ID获取用户信息。

public interface UserService {
    String getUserById(Integer id);
}

然后,我们创建一个实现了UserService接口的类UserServiceImpl,并在其中实现getUserById方法。

@Service
public class UserServiceImpl implements UserService {
    @Override
    public String getUserById(Integer id) {
        return "User with id: " + id;
    }
}

接下来,我们创建一个类UserServiceInvocationHandler,它实现了InvocationHandler接口。在这个类中,我们重写了invoke方法,在其中添加了日志记录功能。

public class UserServiceInvocationHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("After method: " + method.getName());
        return result;
    }
}

最后,在我们的主类中,我们使用Proxy.newProxyInstance方法来创建一个代理对象,并使用这个代理对象来调用getUserById方法。

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
    @Autowired
    private UserService userService;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        UserService proxy = (UserService) Proxy.newProxyInstance(
                userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                new UserServiceInvocationHandler(userService)
        );
        System.out.println(proxy.getUserById(1));
    }
}

当我们运行这个程序时,会看到控制台输出以下内容:

Before method: getUserById
After method: getUserById
User with id: 1

Cglib动态代理(SpringBoot实现)

首先,我们定义一个类UserService,它有一个方法getUserById用于根据用户ID获取用户信息。

public class UserService {
    public String getUserById(Integer id) {
        return "User with id: " + id;
    }
}

接下来,我们创建一个类UserServiceInterceptor,它继承了MethodInterceptor接口。在这个类中,我们重写了intercept方法,在其中添加了日志记录功能。

public class UserServiceInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("After method: " + method.getName());
        return result;
    }
}

最后,在我们的主类中,我们使用Enhancer类来创建一个代理对象,并使用这个代理对象来调用getUserById方法。

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new UserServiceInterceptor());
        UserService proxy = (UserService) enhancer.create();
        System.out.println(proxy.getUserById(1));
    }
}

当我们运行这个程序时,会看到控制台输出以下内容:


Before method: getUserById
After method: getUserById
User with id: 1

你可能感兴趣的:(设计模式系列,java,设计模式)