spring-4设计模式-代理动态,代理源码分析,实现自己的动态代理
什么事代理?
就是对一个对象功能的增强,例如网上售票,代理的就是各个售票点的代理
java实现的代理两种办法
名词:代理对象、 目标对象 。代理和目标不是绝对的,例如:故宫售票、网上售票、黄牛售票。故宫售票对于网上售票来说,前者属于目标对象,后者属于代理对象,网上售票和黄牛售票也是同理,所以代理对象与目标对象不是绝对的,会随着代码的改变而改变。
静态代理:
继承:代理对象继承目标对象,重写需要增强的方法
缺点:对象太多,复杂。
下面代码模拟静态继承代理
1、父类dao
package dao; public class IndexDao implements Dao { public void query() { System.out.println("IndexDao_Query"); } }
2、子类(继承静态代理)
package dao; public class LogDao extends IndexDao { @Override public void query() { System.out.println("插入日志_LogDao"); super.query(); } }
3、测试
package test; import dao.Dao; import dao.LogDao; import dao.TimeDao; public class ProxyStaticTest { public static void main(String args[]){ Dao dao = new LogDao(); dao.query(); Dao dao1 = new TimeDao(); dao1.query(); } }
4、截图
聚合:目标对象和代理对象实现同一接口,代理对象当中要包含目标对象(通过构造或者set),再次重新调用目标对象的方法并增强此方法
缺点:也会产生过多的类(内存溢出)
下面代码模拟静态聚合代理
1、日志dao
package dao;
public class LogDao {
Dao dao;
public LogDao(Dao dao) {
this.dao = dao;
}
public void query() {
System.out.println("日志管理——LogDao");
dao.query();
}
}
2、测试
package test; import dao.Dao; import dao.LogDao; import dao.TimeDao; public class ProxyStaticTest { public static void main(String args[]){ Dao dao1 = new TimeDao(); LogDao LogDao = new LogDao(dao1); LogDao.query(); } }
3、截图
总结:静态代理只适合确定类的数量的情况下才能使用,否则就会出现类爆炸(类过多的问题)
扩展:聚合静态代理很类似装饰者设计模式,只不过装饰者设计模式是用set方法将对象赋值。而聚合代理是用构造方法将对象赋值(IO中的类是用的就是装饰者设计模式)
相关博客:https://www.cnblogs.com/ChrisRIM/archive/2012/08/21/2648372.html
动态代理
1、接口
package com.dao; public interface ObjectDao { public void query(); }
2、实现类
package com.dao; public class User_Defined_Dao implements ObjectDao { public User_Defined_Dao() { } public void query() { System.out.println("自定义Dao中的query方法"); } }
3、代理类
package com.proxy; /* * 对象是如何生成的? * java * class * new * **/ import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.io.File; import java.io.FileWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; public class ProxyUtil { public static Object getInstance(Object target) { Object proxy = null; Class targetInfo = target.getClass().getInterfaces()[0]; String tab = "\t"; String line = "\n"; String implName = targetInfo.getSimpleName(); //创建java内容 String javaContent = ""; //package String packageContent = "package com.proxy;" + line; //importClass String impPackageContent = "import " + targetInfo.getName() + ";" + line; //创建类体 String classContent = "public class $Proxy implements " + implName + " {" + line; //创建私有变量 String privateObject = tab + "private " + implName + " target;" + line; //创建构造 String constructorContent = tab + "public $Proxy (" + implName + " target ){" + line; constructorContent = constructorContent + tab + tab + "this.target = target;" + line; constructorContent = constructorContent + tab + "}" + line; //创建方法 String methedContent = ""; Method[] methods = targetInfo.getDeclaredMethods(); for (Method method : methods) { //获取方法的返回类型 String methodTypeName = method.getReturnType().getSimpleName(); //获取方法的名字 String methodName = method.getName(); methedContent = tab + "public " + methodTypeName + " " + methodName + " ("; //创建参数 Object[] args = method.getParameterTypes(); String argContent = ""; for (int i = 0; i < args.length - 1; i++) { //获取参数的类型 String argsTypeName = args[i].getClass().getSimpleName(); //获取参数名称 i1 i2 argContent = argsTypeName + " i" + i; if (i != args.length - 1) { //多个参数的情况下需要使用','但是最后一个不需要 argContent += ","; } } //组装方法内容,方法体中的逻辑先写死 methedContent += argContent + "){" + line + tab + tab + "System.out.println(\"自定义Dao方法\");" + line + tab; methedContent += tab + tab + "target." + methodName + "(" + argContent + ");"; methedContent += line + tab + "}"; } javaContent = packageContent + impPackageContent + classContent + privateObject + constructorContent + methedContent + line + "}"; //1、使用IO字符流将创建好String 放到D盘中,用于查看是否存在问题。 String filePath = "D:\\com\\proxy\\"; String classFileName = "com.proxy.$Proxy"; File fileDir = new File("D:\\com\\proxy\\"); try { if (!fileDir.isDirectory()) { fileDir.mkdirs(); } File file = new File("D:\\com\\proxy\\$Proxy.java"); if (!file.exists()) { file.createNewFile(); } FileWriter fileWriter = new FileWriter(file); fileWriter.write(javaContent); fileWriter.flush(); fileWriter.close(); //创建java编译器 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); //第三方管理器 StandardJavaFileManager fileMgr = javaCompiler.getStandardFileManager(null, null, null); //将java文件放到管理器中 Iterable units = fileMgr.getJavaFileObjects(file); //创建编译任务 JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileMgr, null, null, null, units); //开始启动任务 task.call(); fileMgr.close(); //使用反射获取编译后的$Proxy对象 URL [] urls = new URL[]{new URL("file:D:\\\\")}; URLClassLoader ucl = new URLClassLoader(urls); Class clazz = ucl.loadClass(classFileName); Constructor constructor = clazz.getConstructor(targetInfo); proxy = constructor.newInstance(target); System.out.println("成功!"); } catch (Exception e) { System.out.println("失败!"); e.printStackTrace(); } return proxy; } }
4、测试
public static void main(String args[]){ ObjectDao objectDao = (ObjectDao) ProxyUtil.getInstance(new User_Defined_Dao()); objectDao.query(); }
5测试结果