全家福

image.png

被代理类准备

image.png
ImServiceImpl

  1. package com.xiang.service.impl;
  2. import com.xiang.service.ImService;
  3. public class ImServiceImpl implements ImService {
  4. @Override
  5. public void sendSms() {
  6. System.out.println("我在发送消息");
  7. }
  8. }

ImService

  1. package com.xiang.service;
  2. public interface ImService {
  3. void sendSms();
  4. }

思路分析

参考静态代理,sendSms()方法里面的内容需要程序员自己定义,所以封装成接口(MyInvocationHandler),让程序员自己实现,People是目标对象,也需要程序员自己实现,所以此处删掉。

  1. public class ImProxy implements ImService{
  2. private ImService imService;
  3. StudentsProxy(ImService imService){
  4. this.imService = imService;
  5. }
  6. @Override
  7. public void sendSms(){
  8. System.out.println("===> 方法增强前");
  9. people.tuition();
  10. System.out.println("===> 方法增强后");
  11. }
  12. }

封装后

  1. package com.xiang.proxy;
  2. import com.xiang.proxy.handler.MyInvocationHandler;
  3. import com.xiang.service.ImService;
  4. import java.lang.reflect.Method;
  5. /**
  6. * 动态代理生成的执行方法,本来是动态生成的,此处为了学习暂时手动自定义
  7. */
  8. public class $Proxy0 implements ImService {
  9. private MyInvocationHandler h;
  10. public $Proxy0(MyInvocationHandler h){
  11. this.h = h;
  12. }
  13. @Override
  14. public void sendSms() {
  15. try {
  16. Method sendSms = ImService.class.getMethod("sendSms", new Class[]{});
  17. h.invoke(h, sendSms, null);
  18. } catch (Throwable throwable) {
  19. throwable.printStackTrace();
  20. }
  21. }
  22. }

提出的公共接口
MyInvocationHandler

  1. public interface MyInvocationHandler {
  2. /**
  3. * 要实现的方法
  4. * @param proxy 代理类
  5. * @param method 被代理类
  6. * @param args 被代理类的入参。
  7. * @return
  8. * @throws Throwable
  9. */
  10. Object invoke(Object proxy, Method method, Object[] args)
  11. throws Throwable;
  12. }

动态代理类
ImProxy

  1. public class ImProxy implements MyInvocationHandler {
  2. public Object objFactory;
  3. public ImProxy(Object objFactory){
  4. this.objFactory = objFactory;
  5. }
  6. @Override
  7. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  8. System.out.println("===> 方法增强前");
  9. Object invoke = method.invoke(objFactory, args);
  10. System.out.println("===> 方法增强后");
  11. return invoke;
  12. }
  13. }

结论

我们只需要动态生成$Proxy0即可。

原理思路

  1. 使用java语言组装$Proxy0.java源代码 获取实现的接口,使用java的反射技术获取该接口下面的所有方法。
  2. 将 $Proxy0.java 编异成 $Proxy0.class文件(JavaCompiler 类似于我们在命令行输入的javac)
  3. 通过classLoader加载到内存中。

MyProxy

  1. package com.xiang.proxy;
  2. import com.xiang.proxy.handler.MyInvocationHandler;
  3. import com.xiang.proxy.handler.impl.ImProxy;
  4. import com.xiang.service.ImService;
  5. import com.xiang.service.impl.ImServiceImpl;
  6. import javax.tools.JavaCompiler;
  7. import javax.tools.JavaFileObject;
  8. import javax.tools.StandardJavaFileManager;
  9. import javax.tools.ToolProvider;
  10. import java.io.File;
  11. import java.io.FileWriter;
  12. import java.io.IOException;
  13. import java.lang.reflect.Constructor;
  14. import java.lang.reflect.Method;
  15. public class MyProxy{
  16. private final static String PATH = "d:/code/"; //保存文件路径
  17. private final static String CLASS_NAME = "$Proxy1"; //类名
  18. public static Object newProxyInstance(MyClassLoader loader,
  19. Class<?> interfaces,
  20. MyInvocationHandler h){
  21. //1. 获取要生成的代码String对象
  22. String proxyClass = getProxyClass(interfaces);
  23. //2.写入本地文件
  24. String filename = PATH+CLASS_NAME+".java";//文件写入地址
  25. whiteFile(proxyClass,filename);
  26. //3. 将 $Proxy0.java 编异成 $Proxy0.class文件(JavaCompiler 类似于我们在命令行输入的javac)
  27. compiler(filename);
  28. //3. 通过classLoader加载到内存中。
  29. try {
  30. Class<?> clazz = loader.findClass(CLASS_NAME);
  31. //构造函数入参对象。
  32. Constructor<?> constructor = clazz.getConstructor(MyInvocationHandler.class);
  33. return constructor.newInstance(h);
  34. } catch (Exception e) {
  35. e.printStackTrace();
  36. return null;
  37. }
  38. }
  39. /**
  40. * 获取拼接代理对象
  41. * @return
  42. */
  43. public static String getProxyClass(Class<?> interfaces){
  44. Method[] methods = interfaces.getMethods();
  45. StringBuilder stringBuilder = new StringBuilder();
  46. stringBuilder.append("package com.xiang.proxy;");
  47. stringBuilder.append("import com.xiang.proxy.handler.MyInvocationHandler;");
  48. stringBuilder.append("import java.lang.reflect.Method;");
  49. stringBuilder.append("public class "+CLASS_NAME+" implements "+interfaces.getName()+" {\n" );
  50. stringBuilder.append(" private MyInvocationHandler h;\n" );
  51. stringBuilder.append(" public "+CLASS_NAME+"(MyInvocationHandler h){\n" );
  52. stringBuilder.append(" this.h = h;\n" );
  53. stringBuilder.append(" }\n" );
  54. stringBuilder.append(mothods(methods,interfaces));
  55. stringBuilder.append("}");
  56. return stringBuilder.toString();
  57. }
  58. /**
  59. * 拼接方法
  60. * @param methods
  61. * @param interfaces
  62. * @return
  63. */
  64. public static String mothods(Method[] methods,Class<?> interfaces){
  65. StringBuilder stringBuilder = new StringBuilder();
  66. for (Method method : methods) {
  67. stringBuilder.append("@Override\n");
  68. //此处偷懒,都没有返回值
  69. stringBuilder.append("public void "+method.getName()+"() {\n" );
  70. stringBuilder.append("try {\n" );
  71. stringBuilder.append(" Method mothodName = "+interfaces.getName()+".class.getMethod(\""+method.getName()+"\", new Class[]{});\n" );
  72. stringBuilder.append(" h.invoke(h, mothodName, null);\n" );
  73. stringBuilder.append(" } catch (Throwable throwable) {\n" );
  74. stringBuilder.append(" throwable.printStackTrace();\n" );
  75. stringBuilder.append(" }\n" );
  76. stringBuilder.append("}" );
  77. stringBuilder.append(" " );
  78. }
  79. return stringBuilder.toString();
  80. }
  81. /**
  82. * 文件写入本地
  83. */
  84. public static void whiteFile(String fileStirng,String filename){
  85. File file = new File(filename);
  86. try {
  87. FileWriter fw = new FileWriter(file);
  88. fw.write(fileStirng);
  89. fw.flush();
  90. fw.close();
  91. } catch (IOException e) {
  92. e.printStackTrace();
  93. }
  94. }
  95. public static void compiler(String filename){
  96. JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
  97. StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, null);
  98. Iterable<? extends JavaFileObject> iterable = fileManager.getJavaFileObjects(filename);
  99. JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, null, null, null, iterable);
  100. task.call();
  101. try {
  102. fileManager.close();
  103. } catch (IOException e) {
  104. e.printStackTrace();
  105. }
  106. }
  107. }
  1. package com.xiang.proxy;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.IOException;
  6. public class MyClassLoader extends ClassLoader{
  7. private File classPathFile;
  8. public MyClassLoader(){
  9. this.classPathFile = new File("D:\\code");
  10. }
  11. @Override
  12. public Class<?> findClass(String name) throws ClassNotFoundException {
  13. String className = MyClassLoader.class.getPackage().getName() + "." + name;
  14. if(classPathFile != null){
  15. File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class");
  16. if(classFile.exists()){
  17. FileInputStream in = null;
  18. ByteArrayOutputStream out = null;
  19. try{
  20. in = new FileInputStream(classFile);
  21. out = new ByteArrayOutputStream();
  22. byte [] buff = new byte[1024];
  23. int len;
  24. while ((len = in.read(buff)) != -1){
  25. out.write(buff,0,len);
  26. }
  27. return defineClass(className,out.toByteArray(),0,out.size());
  28. }catch (Exception e){
  29. e.printStackTrace();
  30. }finally {
  31. if(null != in){
  32. try {
  33. in.close();
  34. } catch (IOException e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. if(out != null){
  39. try {
  40. out.close();
  41. } catch (IOException e) {
  42. e.printStackTrace();
  43. }
  44. }
  45. }
  46. }
  47. }
  48. return null;
  49. }
  50. }

代码测试

  1. public static void main(String[] args) {
  2. ImService imService = (ImService) newProxyInstance(new MyClassLoader(), ImService.class, new ImProxy(new ImServiceImpl()));
  3. imService.sendSms();
  4. }