看mybatis日志模块时涉及的动态代理

动态代理的使用和个人理解(再看spring aop前的理解)

动态代理调用一个方法,并且对这个方法进行增强,代码如下

代码如下,
  1. //接口
1package com.enjoylearning.proxy.unknow;
2
3public interface UnknowToolsFactory {
4    void saleUnknowTools(float length);
5}
  1. 接口实现
1package com.enjoylearning.proxy.unknow;
2
3public class DdFactory implements UnknowToolsFactory{
4    @Override
5    public void saleUnknowTools(float length) {
6        System.out.println("根据您的需求,为您定制了一个高度为:"+length+"的Unknow模特");
7    }
8}
  1. 动态代理类
 1package com.enjoylearning.proxy.unknow;
2
3import javax.annotation.Resource;
4import java.lang.reflect.InvocationHandler;
5import java.lang.reflect.Method;
6import java.lang.reflect.Proxy;
7
8public class LicmCompany implements InvocationHandler {
9
10    @Resource
11    private Object factory;
12
13    public Object getFactory() {
14        return factory;
15    }
16
17    public void setFactory(Object factory) {
18        this.factory = factory;
19    }
20
21    public Object getProxyInstance(){
22        return Proxy.newProxyInstance(factory.getClass().getClassLoader(),factory.getClass().getInterfaces(),this);
23    }
24
25
26    @Override
27    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
28        dosomeThingBefore();
29        Object obj = method.invoke(factory,args);
30        dosomeThingEnd();
31        return obj;
32    }
33
34    //售前服务
35    private void dosomeThingEnd() {
36        System.out.println("精美包装,快递一条龙服务!");
37    }
38
39    //售后服务
40    private void dosomeThingBefore() {
41        System.out.println("根据您的需求,进行市场调研和产品分析!");
42    }
43}
  1. 测试类,普通的main方法
1    UnknowToolsFactory unknowToolsFactory = new DdFactory();
2        LicmCompany licmCompany = new LicmCompany();
3        licmCompany.setFactory(unknowToolsFactory);
4        UnknowToolsFactory licm2 =  (UnknowToolsFactory)licmCompany.getProxyInstance();
5        licm2.saleUnknowTools(1.2f);
  1. 附一个工具类,动态生成的二进制字节码保存到硬盘中
 1package com.enjoylearning.proxy.utils;
2
3import java.io.FileOutputStream;
4import java.io.IOException;
5import java.lang.reflect.Proxy;
6import sun.misc.ProxyGenerator;
7
8public class ProxyUtils {
9
10    /*
11     * 将根据类信息 动态生成的二进制字节码保存到硬盘中, 默认的是clazz目录下 params :clazz 需要生成动态代理类的类
12     * proxyName : 为动态生成的代理类的名称
13     */

14    public static void generateClassFile(Class clazz, String proxyName{
15
16
17        // 根据类信息和提供的代理类名称,生成字节码
18        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName,
19                new Class[]{clazz});
20
21        String paths = clazz.getResource(".").getPath();
22        System.out.println(paths);
23        FileOutputStream out = null;
24
25        try {
26            // 保留到硬盘中
27            out = new FileOutputStream(paths + proxyName + ".class");
28//            out = new FileOutputStream("C:/a.class");
29            out.write(classFile);
30            out.flush();
31        } catch (Exception e) {
32            e.printStackTrace();
33        } finally {
34            try {
35                out.close();
36            } catch (IOException e) {
37                e.printStackTrace();
38            }
39        }
40    }
41
42}
需要注意的几个方法
  1. 代码结构,需要一个接口,实现类,实现invocationhandler的代理类
  2. 代理类中的public Object invoke(Object proxy, Method method, Object[] args) 的三个参数,
  1. 代理的真实对象(本文中的Ddfactory)
  2. 调用的真实方法 (saleUnknowTools)
  3. 调用的真实方法传入的参数 (licm2.saleUnknowTools(1.2f))
  4. 一般在invoke中,会对执行方法进行增强,比如method,invoke前后加入新的方法
  1. proxy 这个类深入说一下
  1. Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. 动态创建一个代理类对象
  2. 这个类最常用的是 public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
  1. 类加载器,由那个类加载器对象对生成的代理类进行加载,一般为出入的实现类的接口对象(UnknowToolsFactory,一般为factory.getclass.getclassloader)
  2. 接口的实现类 factory.getclass.getinterfaces()
  3. 为实现invacationhandler的类
原文地址:https://www.cnblogs.com/xiaoshahai/p/14263174.html