代理模式

为什么要学习代理模式?

因为这就是SpringAOP的底层! 【SpringAOP和SpringMVC】

代理模式分类:静态代理,动态代理
image.png

一、静态代理

1. 角色分析

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
  • 客户:访问代理对象的人

    2. 设计思想

    1)租房接口

    ```java package cn.edu.jxust.demo01;

//租房接口 public interface Rent { public void rent(); }

  1. <a name="Wv7TR"></a>
  2. #### 2)真实角色
  3. <a name="ZnIq2"></a>
  4. ##### 房东出租房子
  5. ```java
  6. package cn.edu.jxust.demo01;
  7. //房东
  8. public class Host implements Rent{
  9. public void rent() {
  10. System.out.println("房东要出租房子");
  11. }
  12. }

中介代理
  1. package cn.edu.jxust.demo01;
  2. //代理人、中介
  3. public class Proxy implements Rent {
  4. private Host host;
  5. public Proxy(){
  6. }
  7. public Proxy(Host host){
  8. this.host = host;
  9. }
  10. public void rent() {
  11. host.rent();
  12. }
  13. public void seeHouse(){
  14. System.out.println("中介带你看房");
  15. }
  16. }

用户租房
  1. package cn.edu.jxust.demo01;
  2. public class Client {
  3. public static void main(String[] args) {
  4. //房东要租房子
  5. Host host = new Host();
  6. //代理,中介帮房东租房子,但是呢?代理一般会有一些附属操作!
  7. Proxy proxy = new Proxy(host);
  8. //你不用面对房东
  9. proxy.rent();
  10. proxy.seeHouse();
  11. }
  12. }

3. 代理模式的优缺点

好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
  • 公共也就交给代理角色!实现了业务的分工!
  • 公共业务发展扩展的时候,方便集中管理

缺点:

  • 一个真实角色就会产生一个代理角色;代码量会翻倍~开发效率会变低~

    加深理解【重点】

    代码:对应08-demo02
    image.png


    增加日志功能

    ```java package cn.edu.jxust.demo02;

public interface UserService { void add(); void delete(); void update(); void query(); }

  1. ```java
  2. package cn.edu.jxust.demo02;
  3. public class UserServiceImpl implements UserService {
  4. public void add() {
  5. System.out.println("增加一个用户");
  6. }
  7. public void delete() {
  8. System.out.println("删除一个用户");
  9. }
  10. public void update() {
  11. System.out.println("修改一个用户");
  12. }
  13. public void query() {
  14. System.out.println("查找一个用户");
  15. }
  16. }

改动原有的业务代码,在公司是大忌!

  1. package cn.edu.jxust.demo02;
  2. public class UserServiceProxy implements UserService {
  3. private UserService userService;
  4. public void setUserService(UserService userService) {
  5. this.userService = userService;
  6. }
  7. public void add() {
  8. log("add");
  9. userService.add();
  10. }
  11. public void delete() {
  12. log("delete");
  13. userService.add();
  14. }
  15. public void update() {
  16. log("update");
  17. userService.add();
  18. }
  19. public void query() {
  20. log("query");
  21. userService.add();
  22. }
  23. public void log(String msg){
  24. System.out.println("[debug]使用了"+msg+"log方法");
  25. }
  26. //改动原有的业务代码,在公司是大忌!
  27. }
  1. package cn.edu.jxust.demo02;
  2. public class Client {
  3. public static void main(String[] args) {
  4. UserService userService = new UserServiceImpl();
  5. UserServiceProxy proxy = new UserServiceProxy();
  6. proxy.setUserService(userService);
  7. proxy.delete();
  8. }
  9. }

image.png

二、动态代理

  • 动态代理和静态角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理、基于类的动态代理
    • 基于接口—-JDK动态代理
    • 基于类:cglib
    • Java字节码实现:javasist

需要了解两个类:Proxy:代理,InvocationHandler:调用处理程序

出租案例

  1. package cn.edu.jxust.demo03;
  2. //租房接口
  3. public interface Rent {
  4. public void rent();
  5. }
  1. package cn.edu.jxust.demo03;
  2. //房东
  3. public class Host implements Rent {
  4. public void rent() {
  5. System.out.println("房东要出租房子");
  6. }
  7. }
  1. package cn.edu.jxust.demo03;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. //使用这个类,自动生成代理类
  6. public class
  7. implements InvocationHandler {
  8. private Rent rent;
  9. public void setRent(Rent rent) {
  10. this.rent = rent;
  11. }
  12. /*
  13. Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader();
  14. new Class<?>[] { Foo.class },
  15. handler);
  16. */
  17. //生成得到代理类
  18. public Object getProxy(){
  19. return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
  20. }
  21. //处理代理实例,并返回结果
  22. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  23. seeHouse();
  24. //动态代理的本质,就是使用反射机制实现
  25. Object result = method.invoke(rent, args);
  26. fare();
  27. return result;
  28. }
  29. public void seeHouse(){
  30. System.out.println("中介带去看房");
  31. }
  32. public void fare(){
  33. System.out.println("中介收费");
  34. }
  35. }
  1. package cn.edu.jxust.demo03;
  2. public class Client {
  3. public static void main(String[] args) {
  4. //真实角色
  5. Host host = new Host();
  6. //代理角色:现在没有
  7. ProxyInvocationHandler pih = new ProxyInvocationHandler();
  8. //通过调用程序处理角色来处理我们要调用的接口对象!
  9. pih.setRent(host);
  10. //这里的Proxy就是动态生成的,我们并没有写
  11. Rent proxy = (Rent) pih.getProxy();
  12. proxy.rent();
  13. }
  14. }

增加用户案例

  1. package cn.edu.jxust.demo04;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. //使用这个类,自动生成代理类
  6. public class ProxyInvocationHandler implements InvocationHandler {
  7. private Object target;
  8. public void setTarget(Object target) {
  9. this.target = target;
  10. }
  11. //生成得到代理类
  12. public Object getProxy(){
  13. return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
  14. }
  15. //处理代理实例,并返回结果
  16. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  17. log(method.getName());
  18. Object result = method.invoke(target, args);
  19. return result;
  20. }
  21. public void log(String msg){
  22. System.out.println("执行了"+msg+ "方法");
  23. }
  24. }
  1. package cn.edu.jxust.demo04;
  2. import cn.edu.jxust.demo02.UserService;
  3. import cn.edu.jxust.demo02.UserServiceImpl;
  4. public class Client {
  5. public static void main(String[] args) {
  6. //真实角色
  7. UserServiceImpl userService = new UserServiceImpl();
  8. //代理角色,不存在
  9. ProxyInvocationHandler pih = new ProxyInvocationHandler();
  10. pih.setTarget(userService);//设置要代理的对象
  11. //动态生成代理类
  12. UserService proxy = (UserService) pih.getProxy();
  13. proxy.add();
  14. }
  15. }

动态代理的好处

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
  • 公共也就交给代理角色!实现了业务的分工!
  • 公共业务发展扩展的时候,方便集中管理!
  • 一个动态代理类代理的一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了问一个接口即可!