看mybatis日志模块时涉及的动态代理
动态代理的使用和个人理解(再看spring aop前的理解)
动态代理调用一个方法,并且对这个方法进行增强,代码如下
代码如下,
- //接口
1package com.enjoylearning.proxy.unknow;
2
3public interface UnknowToolsFactory {
4 void saleUnknowTools(float length);
5}
- 接口实现
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}
- 动态代理类
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}
- 测试类,普通的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);
- 附一个工具类,动态生成的二进制字节码保存到硬盘中
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}
需要注意的几个方法
- 代码结构,需要一个接口,实现类,实现invocationhandler的代理类
- 代理类中的public Object invoke(Object proxy, Method method, Object[] args) 的三个参数,
- 代理的真实对象(本文中的Ddfactory)
- 调用的真实方法 (saleUnknowTools)
- 调用的真实方法传入的参数 (licm2.saleUnknowTools(1.2f))
- 一般在invoke中,会对执行方法进行增强,比如method,invoke前后加入新的方法
- proxy 这个类深入说一下
- 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. 动态创建一个代理类对象
- 这个类最常用的是 public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
- 类加载器,由那个类加载器对象对生成的代理类进行加载,一般为出入的实现类的接口对象(UnknowToolsFactory,一般为factory.getclass.getclassloader)
- 接口的实现类 factory.getclass.getinterfaces()
- 为实现invacationhandler的类
不恋尘世浮华,不写红尘纷扰