一、动态代理和Class字节码的关系
动态代理有什么作用及应用场景?
1.日志集中打印
2.事务
3.权限管理
4.AOP
在Spring Aop当中可以哪些方式实现,及区别?
l.java Proxy(动态构建字节码)(动态构建全新字节码bean初始化的时候)
2.cglib(动态构建字节码)(动态构建全新字节码bean初始化的时候)
3.Aspecti(修改目标类的字节,织入代理的字节,在程序编译(编译的时候插入动态代理的字节码,不会生成全新的Class)
4.instrumentation(修改目标类的字节码、类装载的时候动态拦截去修改,基于iavaagent)-javaagent:spring-instrument-4.3.8.RELEASE.jar(类装载的时候插入动态代理的字节码,不会生成全新的Class)
关于实现动态代理的技术:
1.动态代理可以由java proxy、cglib、instrumentation(javaagent)、Aspectj、等多种方式实现
2.动态代理本质是对class字节码进行动态构建或修改。
3.修改的工具有ASM、javavssist
4.多种实现方式的区别在于对字节码切入方式不一样。可选方式的有:
java proxy、Cglib是基于动态构建接口实现类字节
AspectJ是借助Eclipse工具在编译时织入代理字节
instrumentation是基于javaagent在类装载时修改Class织入代理字节
使用字定义ClassLoader在装载时织入代理字节JAVA Proxy实现过程
动态代理技术栈图:
一个简单实现的例子:
public interface User {
String getName(String name);
}
```java
public class Userimpl implements User{
@Override
public String getName(String name) {
System.out.println("实现类");
return name;
}
}
```java
public class UserProxy {
public static void main(String[] args) {
final Userimpl userimpl = new Userimpl();
User targetproxy = (User) Proxy.newProxyInstance(UserProxy.class.getClassLoader(), new Class[]{User.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] myargs) throws Throwable {
System.out.println("q我是前置");
try {
return method.invoke(userimpl,myargs);
} finally {
System.out.println("后置");
}
}
});
targetproxy.getName("hzy");
}
}
public static void buildProxy() throws IOException {
byte[] bytes = ProxyGenerator.generateProxyClass("User$proxy",new Class[]{User.class});
String fileName = System.getProperty("user.dir")+"\\target\\UserService$proxy.class";
File file = new File(fileName);
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(bytes);
fileOutputStream.flush();
fileOutputStream.close();
}
在上面的main函数中加上 buildProxy()方法,执行后查看文件目录:
可以看到生成的class文件
把文件拖到idea里面,可以看到反编译后的文件:
首先是newProxyInstance方法:
可以看到进入了这句 Class> cl = getProxyClass0(loader, intfs);//寻找或者生成目标代理类
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
这个注释的意思:如果由实现给定接口的给定加载器定义的代理类存在,这将简单地返回缓存副本;否则,它将通过 ProxyClassFactory 创建代理类,即判断这个接口是不是已经装载class,如果有则直接返回
之后还有apply方法、proxyfactory中的方法等等,比较复杂,以后再仔细学。