aop在java中有幾種實(shí)現(xiàn)方式?
- java proxy
基于接口的實(shí)現(xiàn),構(gòu)建目標(biāo)類(lèi)的實(shí)現(xiàn)類(lèi)(全新的類(lèi)),初始化的時(shí)候 - cglib
基于繼承實(shí)現(xiàn),構(gòu)建目標(biāo)類(lèi)的子類(lèi)(全新的類(lèi)),初始化的時(shí)候 - Aspectj
aspectJ的使用是在編譯期,通過(guò)特殊的編譯器可以在不改變代碼的前提下織入代碼
修改目標(biāo)類(lèi)的字節(jié),織入代理的字節(jié),在程序編譯的時(shí)候,不會(huì)生成全新的class, - java agent
修改目標(biāo)類(lèi)的字節(jié)碼,在類(lèi)裝載的時(shí)候,插入動(dòng)態(tài)代理的字節(jié)碼,不會(huì)生成全新的class
是通過(guò)java.lang.instrument實(shí)現(xiàn),用來(lái)在 ClassLoader 加載字節(jié)碼之前完成對(duì)操作字節(jié)碼的目的
java -javaagent:G:\myagent.jar=Hello1 -jar myapp.jar
字節(jié)碼 bytecode: .java => .class(16進(jìn)制) => jvm指令碼(數(shù)字)=>機(jī)器碼 idea view show bytecode
共同點(diǎn)
都是對(duì)jvm class字節(jié)碼進(jìn)行操作
不同點(diǎn)
操作方式不一樣,第一個(gè)和第二個(gè)是基于對(duì)字節(jié)碼的新增(新增一個(gè)完整的字節(jié)碼,但是要等到需要被操作的類(lèi)被加載之后才會(huì)在系統(tǒng)運(yùn)行期動(dòng)態(tài)生成代理類(lèi),新增類(lèi)必須用到代理(對(duì)性能有一定的影響),第三種和第四種是基于對(duì)字節(jié)碼的修改(修改現(xiàn)有的類(lèi)的字節(jié)碼)也就是說(shuō)被代理的類(lèi)的class字節(jié)碼 在裝載入jvm的時(shí)候,已經(jīng)被修改了所以性能會(huì)很高
修改不需要用到代理
- 反射
是java代碼層面的概念,字節(jié)碼是jvm層面的概念
jdk 動(dòng)態(tài)代理實(shí)現(xiàn)
- 會(huì)生成一個(gè)字節(jié)數(shù)組(一個(gè)全新的類(lèi)),繼承了實(shí)現(xiàn)了service接口并且繼承了Proxy,如下圖在運(yùn)行期動(dòng)態(tài)生成出類(lèi)的字節(jié)碼,并且加載,這也就是為什么Proxy.newProxyInstance需要傳入classLoader的原因
注意:在Proxy生成動(dòng)態(tài)代理類(lèi)的時(shí)候,會(huì)驗(yàn)證接口類(lèi)能否被指定classloader加載,不能會(huì)報(bào) is not visible from class loader異常
Class.forName(String className)使用裝載當(dāng)前類(lèi)的類(lèi)裝載器來(lái)裝載制定的類(lèi)
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 接口動(dòng)態(tài)代理
ServiceGetNameImpl serviceGetNameImpl = new ServiceGetNameImpl();
ServiceGetName serviceGetName;
/**
* 1. 在內(nèi)存里面生成一個(gè)class字節(jié)碼,得到class類(lèi)的字節(jié)碼數(shù)組
* a. 生成一個(gè)代理類(lèi)數(shù)組
* 2. class 在jvm的裝載,這也是為什么要傳一個(gè)classloader的原因
* 3. 通過(guò)反射來(lái)new一個(gè)代理實(shí)例
*/
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 源碼
//生成一個(gè)代理字節(jié)碼數(shù)組
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