静态代理和动态代理简单实现

静态代理:

静态代理的实现要求:真实角色,代理角色;真实角色和代理角色要实现同一个接口,代理角色要持有真实角色的引用。

  在Java中线程的设计就使用了静态代理设计模式,其中自定义线程类实现Runable接口,Thread类也实现了Runalbe接口,

  在创建子线程的时候,传入了自定义线程类的引用,再通过调用start()方法,调用自定义线程对象的run()方法。实现了线程的并发执行。

需求:在被代理类执行方法的时候,能够打印日志信息,比如当前的时间节点

1、业务方法,被代理类和代理类都要实现这个接口:

public interface LogService {
    void logTime();
}

2、被代理类

public class BeProxy implements LogService{
    public void logTime() {
        System.out.println("被代理类执行了~");
    }
}

3、代理类:代理角色实现被代理类需要的功能。

public class Proxy implements LogService {
    // 持有代理角色的引用
    private BeProxy beProxy;

    public Proxy() {
    }

    public Proxy(BeProxy beProxy) {
        this.beProxy = beProxy;
    }

    public void logTime() {
        System.out.println(new SimpleDateFormat("HH:mm:ss SSS").format(new Date(System.currentTimeMillis())) + " 代理对象开始执行");
        // 执行的是被代理角色的功能
        beProxy.logTime();
        System.out.println(new SimpleDateFormat("HH:mm:ss SSS").format(new Date(System.currentTimeMillis())) + " 代理对象结束执行");
    }
}

4、测试

public class Test {
    public static void main(String[] args) {
        // 被代理对象
        BeProxy beProxy = new BeProxy();

        // 代理者对象
        Proxy proxy = new Proxy(beProxy);

        proxy.logTime();
    }
}

5、结果:

00:48:21 119 代理对象开始执行
被代理类执行了~
00:48:21 121 代理对象结束执行

静态代理的问题:

上面的代码中,为了给被代理类类做日志增强,我们编写了代理类,而且准备了一个构造器接收目标对象。

代理对象构造器的参数类型是LogService,这意味着它只能接受LogService 的实现类对象,亦即我们写的代理类Proxy只能给LogService做代理,它们绑定死了!

如果现在我们系统需要全面改造,要给其他类也添加日志打印功能,就得为其他几百个接口都各自写一份代理类...

动态代理案例一:

动态代理和静态代理角色一样
态代理的代理类是动态生成的,不是我们直接写好的!
动态代理分为两大类:基于接口的动态代理,基于类的动态代理

  • 基于接口--- JDK动态代理 [我们在这里使用]
  • 基于类: cglib
  • java字节码实现 : javasist

需要了解两个类:

java.lang.reflect.Proxy; 代理,
    static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
          返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。 

java.lang.reflect.InvocationHandler: 调用处理程序
    Object invoke(Object proxy, Method method, Object[] args) 
              在代理实例上处理方法调用并返回结果。

动态代理具体步骤:

  1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
  2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

1、业务方法

public interface LogService {
    void logTime();
}

2、被代理类

public class BeProxy implements LogService{
    @Override
    public void logTime() {
        System.out.println("被代理类执行了~");
    }
}

3、处理程序类,可以自动生成代理类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 处理程序类,用这个类可以自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
    // 被代理的接口
    private LogService logService;

    public void setLogService(LogService logService) {
        this.logService = logService;
    }

    // 生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),logService.getClass().getInterfaces(),this);
    }

    @Override
    /**处理代理实例,并返回结果*/
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke(logService, args);
        return invoke;
    }
}

4、测试类

public class Test {
    public static void main(String[] args) {
        // 真实角色
        BeProxy proxy = new BeProxy();
        // 代理角色【不存在】
        ProxyInvocationHandler handler = new ProxyInvocationHandler();
        // 设置要代理的对象
        handler.setLogService(proxy);
        // 生成代理类对象
        LogService logService = (LogService) handler.getProxy();
        // 执行角色方法
        logService.logTime();
    }
}

5、结果

被代理类执行了~

动态代理案例二:

需求:

需求:
    有一个service接口,调用这个接口中的方法:
        调用的方法是doSome-->在方法开始前打印系统当前时间,以及在最后打印一句话
        调用的方法是doOther-->就正常输出

 

1、在开始和结束要输出的两句话(进行一个简单封装)

 1 import java.text.SimpleDateFormat;
 2 import java.util.Date;
 3 
 4 /**
 5  * @author zhangzhixi
 6  */
 7 public class Utils {
 8     public static void currentTime() {
 9         SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
10         String showTime = sdf.format(new Date());
11         System.out.println("当前系统时间为:" + showTime);
12     }
13 
14     public static void executeTransaction(){
15         System.out.println("事务执行结束");
16     }
17 }

 2、业务接口:

1 public interface UserService {
2     void doSome();
3     void doOther();
4 }

3、业务接口的实现类:

 1 public class UserServiceImpl implements UserService {
 2     @Override
 3     public void doSome() {
 4         System.out.println("doSome方法执行!~");
 5     }
 6 
 7     @Override
 8     public void doOther() {
 9         System.out.println("doOther方法执行!~");
10     }
11 }

4、创建调用处理程序类

 1 package com.zhixi.invaction;
 2 
 3 import com.zhixi.service.UserService;
 4 import com.zhixi.util.Utils;
 5 
 6 import java.lang.reflect.InvocationHandler;
 7 import java.lang.reflect.Method;
 8 import java.lang.reflect.Proxy;
 9 
10 /**
11  * @author zhangzhixi
12  */
13 public class MyInvocation implements InvocationHandler {
14 
15     /**
16      * 被代理的接口
17      */
18     UserService userService;
19 
20     public void setUserService(UserService userService) {
21         this.userService = userService;
22     }
23 
24     public Object getProxy() {
25         // 生成得到代理类
26         return Proxy.newProxyInstance(this.getClass().getClassLoader(), userService.getClass().getInterfaces(), this);
27     }
28 
29 
30     /**
31      * @param proxy 代理对象
32      * @param method 代理的方法对象
33      * @param args 方法调用时参数
34      */
35     @Override
36     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
37         Object invoke = null;
38 
39         // 调用了doSome就执行这段业务
40         if ("doSome".equals(method.getName())) {
41             // 增加的业务
42             Utils.currentTime();
43 
44             /**
45              * userService: 被代理的类
46              * args: 参数
47              */
48             invoke = method.invoke(userService, args);
49 
50             // 增加的业务
51             Utils.executeTransaction();
52         } else {
53             //说明调用了doOther
54             invoke = method.invoke(userService, args);
55         }
56         return invoke;
57     }
58 }

5、测试类:

 1 public class MyTest {
 2     public static void main(String[] args) {
 3         // 创建目标对象
 4         UserService userService= new UserServiceImpl();
 5         // 代理对象【不存在】
 6         MyInvocation invocation = new MyInvocation();
 7         // 设置要代理的对象
 8         invocation.setUserService(userService);
 9         // 生成代理
10         UserService service = (UserService) invocation.getProxy();
11         // 调用对象的业务方法
12         service.doSome();
13         System.out.println("===============");
14         service.doOther();
15     }
16 }

6、测试结果:

当前系统时间为:2021年01月07日 21:56:41
doSome方法执行!~
事务执行结束
===============
doOther方法执行!~
原文地址:https://www.cnblogs.com/zhangzhixi/p/14224602.html