aop在java中有几种实现方式?
- java proxy
基于接口的实现,构建目标类的实现类(全新的类),初始化的时候 - cglib
基于继承实现,构建目标类的子类(全新的类),初始化的时候 - Aspectj
aspectJ的使用是在编译期,通过特殊的编译器可以在不改变代码的前提下织入代码
修改目标类的字节,织入代理的字节,在程序编译的时候,不会生成全新的class, - java agent
修改目标类的字节码,在类装载的时候,插入动态代理的字节码,不会生成全新的class
是通过java.lang.instrument实现,用来在 ClassLoader 加载字节码之前完成对操作字节码的目的
java -javaagent:G:\myagent.jar=Hello1 -jar myapp.jar
字节码 bytecode: .java => .class(16进制) => jvm指令码(数字)=>机器码 idea view show bytecode
共同点
都是对jvm class字节码进行操作
不同点
操作方式不一样,第一个和第二个是基于对字节码的新增(新增一个完整的字节码,但是要等到需要被操作的类被加载之后才会在系统运行期动态生成代理类,新增类必须用到代理(对性能有一定的影响),第三种和第四种是基于对字节码的修改(修改现有的类的字节码)也就是说被代理的类的class字节码 在装载入jvm的时候,已经被修改了所以性能会很高
修改不需要用到代理
- 反射
是java代码层面的概念,字节码是jvm层面的概念
jdk 动态代理实现
- 会生成一个字节数组(一个全新的类),继承了实现了service接口并且继承了Proxy,如下图在运行期动态生成出类的字节码,并且加载,这也就是为什么Proxy.newProxyInstance需要传入classLoader的原因
注意:在Proxy生成动态代理类的时候,会验证接口类能否被指定classloader加载,不能会报 is not visible from class loader异常
Class.forName(String className)使用装载当前类的类装载器来装载制定的类
public interface ServiceGetName {
String getName(String name);
}
public class ServiceGetNameImpl implements ServiceGetName {
@Override
public String getName(String name) {
return name;
}
}
public static void main(String[] args) throws Exception{
//java proxy 接口动态代理
ServiceGetNameImpl serviceGetNameImpl = new ServiceGetNameImpl();
ServiceGetName serviceGetName;
/**
* 1. 在内存里面生成一个class字节码,得到class类的字节码数组
* a. 生成一个代理类数组
* 2. class 在jvm的装载,这也是为什么要传一个classloader的原因
* 3. 通过反射来new一个代理实例
*/
Object proxy = Proxy.newProxyInstance(ProxyDemo.class.getClassLoader(),new Class[]{ServiceGetName.class}
, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置逻辑");
try {
return method.invoke(serviceGetNameImpl,args);
} finally {
System.out.println("后置逻辑");
}
}
});
serviceGetName = (ServiceGetName)proxy;
String r = serviceGetName.getName("zhangsan");
System.out.println(r);
buildProxyClass();
}
public static void buildProxyClass() throws Exception{
//代理的proxy 源码
//生成一个代理字节码数组
byte[] bytes= ProxyGenerator.generateProxyClass("ServiceGetName$proxy",new Class[]{ServiceGetName.class});
String fileName = System.getProperty("user.dir")+"/target/ServiceGetName$proxy.class";
File f = new File(fileName);
FileOutputStream out = new FileOutputStream(f);
out.write(bytes);
out.flush();
out.close();
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import com.xcar.designpattern.bytecode.ServiceGetName;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class ServiceGetName$proxy extends Proxy implements ServiceGetName {
private static Method m1;
private static Method m2;
private static Method m0;
private static Method m3;
public ServiceGetName$proxy(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String getName(String var1) throws {
try {
return (String)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m3 = Class.forName("com.xcar.designpattern.bytecode.ServiceGetName").getMethod("getName", Class.forName("java.lang.String"));
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
参考
https://www.cnblogs.com/aspirant/p/8796974.html
https://blog.csdn.net/ljz2016/article/details/83309599
https://www.cnblogs.com/lilei94/p/9744331.html
网友评论