代理分两种技术,一种是jdk代理(机制就是反射,只对接口操作),一种就是字节码操作技术。前者不能算技术,后者算是新的技术。未来将有大的动作或者较为广泛的应用和变革,它可以实现代码自我的编码(人工智能,代码智能)。
先看看jvm class技术:
字节码改写:
(一)jdk 动态代理:
1.定义业务逻辑
public interface Service {
//目标方法
public abstract void add();
public class UserServiceImpl implements Service {
public void add() {
System.out.println("This is add service");
java.lang.reflect.Proxy
java.lang.reflect.InvocationHandler
接口定义代理类的实现。
class MyInvocatioHandler implements InvocationHandler {
private Object target;
public MyInvocatioHandler(Object target) {
this.target = target;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----before-----");
Object result = method.invoke(target, args);
System.out.println("-----end-----");
return result;
// 生成代理对象
public Object getProxy() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
return Proxy.newProxyInstance(loader, interfaces, this);
3.使用动态代理
public class ProxyTest {
public static void main(String[] args) {
Service service = new UserServiceImpl();
MyInvocatioHandler handler = new MyInvocatioHandler(service);
Service serviceProxy = (Service)handler.getProxy();
serviceProxy.add();
执行结果:
-----before-----
This is add service
-----end-----
代理对象的生成过程由Proxy类的newProxyInstance方法实现,分为3个步骤:
1、ProxyGenerator.generateProxyClass
方法负责生成代理类的字节码,生成逻辑比较复杂,了解原理继续分析源码 sun.misc.ProxyGenerator;
2、native方法Proxy.defineClass0
负责字节码加载的实现,并返回对应的Class对象。
Class clazz = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length)
3、利用clazz.newInstance
反射机制生成代理类的对象;
使用 反编译工具 jad jad com.sun.proxy.$Proxy.1
看看代理类如何实现,反编译出来的java代码如下:
public final class $proxy1 extends Proxy implements Service {
public $proxy1(InvocationHandler invocationhandler) {
super(invocationhandler);
public final boolean equals(Object obj) {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[] {
})).booleanValue();
catch(Error _ex) { }
catch(Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
public final String toString() {
try {
return (String)super.h.invoke(this, m2, null);
catch(Error _ex) { }
catch(Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
public final void add() {
try {
super.h.invoke(this, m3, null);
return;
catch(Error _ex) { }
catch(Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
public final int hashCode() {
try {
return ((Integer)super.h.invoke(this, m0, null)).intValue();
catch(Error _ex) { }
catch(Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("zzzzzz.Service").getMethod("add", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
catch(NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
catch(ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
从上述代码可以发现:
1、生成的$proxy1继承自Proxy类,并实现了Service接口。
2、执行代理对象的方法,其实就是执行InvocationHandle对象的invoke方法,传入的参数分别是当前代理对象,当前执行的方法和参数。
jdk动态代理使用的局限性
通过反射类Proxy
和InvocationHandler
回调接口实现的jdk动态代理,要求委托类必须实现一个接口,但事实上并不是所有类都有接口,对于没有实现接口的类,便无法使用该方方式实现动态代理。
(二)字节码修改技术
了解该技术必然先了解Java class文件格式 《读《深入jvm原理》之class文件》
目前字节码修改技术有ASM,javassist等。cglib就是基于封装的Asm. Spring 就是使用cglib代理库。
ASM 是一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
不过ASM在创建class字节码的过程中,操纵的级别是底层JVM的汇编指令级别,这要求ASM使用者要对class组织结构和JVM汇编指令有一定的了解。
Java字节码生成开源框架介绍--Javassist:
Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
注解、反射、
字节码操作
前言:本篇博客将介绍
Java中注解的定义、使用以及反射对
Java动态性的支持和
Java字节码操作,通过本篇内容,读者将对
Java知识有更加深刻的理解,同时为后面Android的高级框架学习打好基础。
Annotation是从
JDK5.0开始引入的,注解并不是程序本身,但可以被其他程序读取,如果没有注解信息处理流程,注解将毫无意义。注解可以在
Java很多地方使用,如类、属性、方法等等。
1-注解入门
2-内置注解
3-自定义注解、元注解
反射机制概述
reflection:
java是一门静态语言,但是因为有反射机制,成为了准
动态语言,反射机制允许程序在运行期间借助与Reflection API取得任何类的内部信息,并且能够直接操作任意对象内部属性及其方法。
在加载完类之后,在堆内的方法区就会产生一个
class类型的对象,这个对象就包含了完整的类结构信息,我们可以通过这个对象看到类的结构。这个对象就是一面镜子,通过这个镜子看到类的结构,所以形象的称为反射。
代码解释:
public
class ReflectionTest {
获取字节码的三种方法:
1)Class clazz1 = Class.forName("全限定类名"); //通过静态方法forName,获取字节码文件对象。此时该类还处于源文件java文件阶段,并没有变为字节码.class文件。
2)Class clazz2 = Person.class; //在类被编译成.class文件时启动,直接获取到自己编译成的.class文件。
3)Class c...
普通的new一个对象:
// 先拿到
Class对象
Class<?> a
Class =
Class.forName("org.chabug.entity.Reflection
Class");
// new这个
Class对应的对象
Object o = a
Class.newInstance();
普通的public方法可以直接调用:这里是调用set