动态代理:
  1.动态编译 JavaCompiler.CompilationTask 动态编译想理解自己查API文档
  2.反射被代理类 主要使用Method.invoke(Object o,Object... args);对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
  3.类的加载 URLClassLoader可以加载硬盘任意位置的.java文件。class.getClassLoader只能加载classPath目录下的类。
动态代理可以理解为 动态生成发射代理的类。这其中可以动态增加逻辑操作。比如日志的打印,事物的处理等。spring的AOP操作也是动态代理的。

假设我们有一个接口GrowAble可成长的。

package com.cn;

public interface GrowAble {
void growUp();
}

一棵小树苗实现了这个接口

package com.cn;
public class Tree implements GrowAble {
@Override
public void growUp() {
System.out.println("I am a tree , I'm grow up!");
} }

这时我们想不在不改变源码的情况下想知道树长了多少这个操作?
我们需要一个转换接口。

package com.cn;
import java.lang.reflect.Method; public interface InvactionHandle {
void invoke(Object o,Method m);
}

一个实现接口类。

package com.cn;
import java.lang.reflect.Method;
import java.util.Random; public class HeightInvactionHandle implements InvactionHandle {
@Override
public void invoke(Object c, Method m) {
try {
m.invoke(this.o);
System.out.println("这棵树长了" + new Random().nextInt(9527)+"米!!!" );
} catch (Exception e) {
e.printStackTrace();
}
}
private Object o;
public HeightInvactionHandle(Object o) {
super();
this.o = o;
}
}

现在最重要的Proxy类了。把上述两个接口接口起来。

package com.cn;
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;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
/**
* 动态代理
* @author 灵台方寸小道士
*/
public class Proxy {
public static Object getNewInstance(Class<?> c,Object object) throws Exception {
String path = System.getProperty("user.dir") + File.separator + "mybin"
+ File.separator + "com" + File.separator + "cn"
+ File.separator;
String fileName = "$Proxy.java";
String nextLine = System.getProperty("line.separator");
// create java File
String fileValue = "package com.cn;"+nextLine+
"import com.cn.*;"+nextLine+
"import java.lang.reflect.Method;"+nextLine+
"public class $Proxy implements "+ c.getName() +"{"+nextLine+
" private InvactionHandle h;"+nextLine+
" public $Proxy(InvactionHandle hin)"+ nextLine+
" {"+nextLine+
" this.h = hin;"+nextLine+
" }"+nextLine;
Method[] methods = c.getDeclaredMethods();
for (Method m:methods) {
fileValue += " public "+ m.getReturnType()+" "+m.getName()+"()"+nextLine+
" {"+nextLine+
" try{ "+nextLine+
//测试方法不带参数 所以new Class<?>[]{}空参数传入
" Method me = "+c.getName()+".class.getDeclaredMethod(\""+m.getName()+"\", new Class<?>[]{});"+nextLine+
" h.invoke(this,me);"+nextLine+
" }catch(Exception e){ "+nextLine+
" e.printStackTrace(); }"+nextLine+
" }"+nextLine;
}
fileValue +="}"+nextLine;
File f = new File(path);//是否存在此目录
if (!f.exists())
f.mkdirs();
FileWriter writer = new FileWriter(new File(f,fileName));
writer.write(fileValue);
writer.flush();
writer.close();
System.out.println("*************** create java file over ******************");
// compiler 生成 class文件 调取javac编译
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = compiler.getStandardFileManager(null,null, null);
Iterable<? extends JavaFileObject> in = manager.getJavaFileObjects(path+ fileName);
CompilationTask task = compiler.getTask(null, manager, null, null,null, in);
task.call();
System.out.println("*************** complier class file over ******************"); // loader 加载class文件 的第一种方法 URLClassLoader可以load任意目录下的类!
URL[] urls = new URL[] { new URL("file:/" + System.getProperty("user.dir") + File.separator + "mybin"+ File.separator) };
URLClassLoader loader = new URLClassLoader(urls);
Class<?> d = loader.loadClass("com.cn.$Proxy");
System.out.println("*************** loader class file over ******************"); // newInstance class JVM
Constructor<?> con = d.getConstructor(InvactionHandle.class);
Object o = con.newInstance(object);
// newInstance...
/**
加载class文件 的第二种方法 ClassLoader只能load位于classpath(src目录)下的类
Class<?> second = Proxy.class.getClassLoader().loadClass("com.cn.$Proxy");
System.out.println(second.getSimpleName());
*/
return o;
}
}

JavaCompiler 是用于编译生成的java代码。在用URLClassLoader将class文件加载进内存。在实例化。

下面一个测试类 Client

package com.cn;
public class Client { public static void main(String[] args) throws Exception {
Tree tree = new Tree();
InvactionHandle handle = new HeightInvactionHandle(tree);
GrowAble gro = (GrowAble)Proxy.getNewInstance(GrowAble.class, handle);
gro.growUp();
System.out.println("测试结束");
}
}

运行结果

***************     create java file over      ******************
*************** complier class file over ******************
*************** loader class file over ******************
I am a tree , I'm grow up!
这棵树长了2174米!!!
测试结束

现在我们在用JDK来做做

package com.cn;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Random; public class JDKInvocationHandle implements InvocationHandler { private Object o;
public JDKInvocationHandle(Object o)
{
super();
this.o = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
try {
result = method.invoke(o,args);
System.out.println("这棵树长了" + new Random().nextInt(9527)+"米!!!" );
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}

测试类

package com.cn;
public class Client2 { public static void main(String[] args) {
java.lang.reflect.InvocationHandler h = new JDKInvocationHandle(new Tree());
GrowAble gro = (GrowAble) java.lang.reflect.Proxy.newProxyInstance(
GrowAble.class.getClassLoader(),
new Class[] { GrowAble.class },
h);
gro.growUp();
System.out.println("测试结束");
}
}

运行结果

I am a tree , I'm grow up!
这棵树长了726米!!!
测试结束

文章目标 学习java动态代理原理。仅当抛砖引玉作用。

文章原创。转载请注明http://www.cnblogs.com/stay-9527/p/3689266.html

动态代理 原理简析(java. 动态编译,动态代理)的更多相关文章

  1. [转载] Thrift原理简析(JAVA)

    转载自http://shift-alt-ctrl.iteye.com/blog/1987416 Apache Thrift是一个跨语言的服务框架,本质上为RPC,同时具有序列化.发序列化机制:当我们开 ...

  2. Java Annotation 及几个常用开源项目注解原理简析

    PDF 版: Java Annotation.pdf, PPT 版:Java Annotation.pptx, Keynote 版:Java Annotation.key 一.Annotation 示 ...

  3. Java Android 注解(Annotation) 及几个常用开源项目注解原理简析

    不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...

  4. JDK框架简析--java.lang包中的基础类库、基础数据类型

    题记 JDK.Java Development Kit. 我们必须先认识到,JDK不过,不过一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含 ...

  5. PHP的错误报错级别设置原理简析

    原理简析 摘录php.ini文件的默认配置(php5.4): ; Common Values: ; E_ALL (Show all errors, warnings and notices inclu ...

  6. Spring系列.@EnableRedisHttpSession原理简析

    在集群系统中,经常会需要将Session进行共享.不然会出现这样一个问题:用户在系统A上登陆以后,假如后续的一些操作被负载均衡到系统B上面,系统B发现本机上没有这个用户的Session,会强制让用户重 ...

  7. .Net CLR R2R编译的原理简析

    前言 躺平了好一段时间了,都懒得动了.本文均为个人理解所述,如有疏漏,请指正. 楔子 金庸武侠天龙八部里面,少林寺至高无上的镇寺之宝,武林人士梦寐以求的内功秘笈易筋经被阿朱偷了,但是少林寺也没有大张旗 ...

  8. Spring系列.AOP原理简析

    Spring AOP使用简介 Spring的两大核心功能是IOC和AOP.当我们使用Spring的AOP功能时是很方便的.只需要进行下面的配置即可. @Component @Aspect public ...

  9. SIFT特征原理简析(HELU版)

    SIFT(Scale-Invariant Feature Transform)是一种具有尺度不变性和光照不变性的特征描述子,也同时是一套特征提取的理论,首次由D. G. Lowe于2004年以< ...

随机推荐

  1. 手游client思考框架

    手游新公司新项目client我不太同意框架.虽然我也终于让步,当他居然问老板,使这个幼稚的行为而悔恨. 然而,就在最近我写了一些代码视图,我更坚定了自己的想法和思想.和思路不一定适合其它人,所以我并不 ...

  2. MLAPP——概率机器学习知识汇总

    <机器学习>课程使用Kevin P. Murphy图书<Machine Learning A Probabilistic Perspective>本英语教材,本书从一个独特的数 ...

  3. Caused by: java.lang.ClassNotFoundException: javax.transaction.TransactionManager

    1.错误叙述性说明 usage: java org.apache.catalina.startup.Catalina [ -config {pathname} ] [ -nonaming ] { -h ...

  4. hdu2844 &amp; poj1742 Coin ---多重背包--两种方法

    意甲冠军:你有N种硬币,每个价格值A[i],每个号码C[i],要求. 在不超过M如果是,我们用这些硬币,有多少种付款的情况下,.那是,:1,2,3,4,5,....,M这么多的情况下,,你可以用你的硬 ...

  5. js中不同的height, top的对比

    每次看到js中的clientHeight(clientTop), offsetHeight(offsetTop),scrollHeight(scrollTop)就头大,根本分不清这几种的区别,然而碰到 ...

  6. Effective C++学习笔记(Part One:Item 1-4)

    最近的最终effectvie C++仔细阅读侧,我很惊讶C++动力和魅力.最近的" LL最近记得阅读体验和读书笔记其.必要查找使用,是什么假设总结不合适.欢迎批评: 如今仅仅列出框架,近期会 ...

  7. Web采矿技术

      一.数据挖掘 数据挖掘是运用计算机及信息技术,从大量的.不全然的数据集中获取隐含在当中的实用知识的高级过程.Web 数据挖掘是从数据挖掘发展而来,是数据挖掘技术在Web 技术中的应用.Web 数据 ...

  8. 大数据系列修炼-Scala课程06

    关于Scala中的正则表达式与模式匹配结合的正则表达式Reg 正则表达式的实现:正则表达式的定义与其它语言差不多,只需在表达式后加一个.r,并且可以遍历相应的表达式进行匹配 //定义的正则表达式 va ...

  9. IOS SDK相机的详细解释/画廊(默认+他们的高清摄像头接口)

    原版的blog,转载请注明出处 blog.csdn.net/hello_hwc 前言: 新NSURLSession的UploadTask的,结果写那个Demo的时候想要写成拍照上传.然后就想到先写一个 ...

  10. JDBC加载过程

    jdbc载入的过程如图所看到的. 桥接模式请參照:设计模式:桥接模式 blog目的:与图说话 版权声明:本文博客原创文章,博客,未经同意,不得转载.