spring源码(二)- 代理
ajc增强
通过插件,修改字节码文件
agent
通过插件,在类加载是修改
jdk代理:
普通类的过程:
先编写java 源代码 ,由源代码编译为字节码,最后经过类加载可以使用。
代理类:
没有源码,在运行期间直接生成代理类的字节码,生成的字节码需要类加载器加载才能使用
package com.tlj.app.parta;
import java.lang.reflect.Proxy;
/**
* @Author: login
* @Date: 2022/9/9
* @Description: 只能针对接口进行代理
*/
public class JdkProxy {
interface Foo {
void foo() ;
}
static class Target implements Foo {
@Override
public void foo() {
System.out.println(" target");
}
}
public static void main(String[] args) {
// 用来加载运行期间动态生成的字节码文件
ClassLoader classLoader = JdkProxy.class.getClassLoader();
Target target = new Target();
Foo foo = (Foo) Proxy.newProxyInstance(classLoader, new Class[] { Foo.class }, (proxy, method, args1) -> {
System.out.println("before");
// 代理返回目标方法执行的结果
return method.invoke(target, args1);
});
foo.foo();
}
}
jdk 代理是重新生成了接口的子类来实现代理,被代理类可以使final, jdk代理只能代理接口
Cglib动态代理
代理类是目标类的子类,不能对final类进行代理
package com.tlj.app.parta;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @Author: login
* @Date: 2022/9/9
* @Description:
*/
public class CglibProxy {
static class Target {
public void foo() {
System.out.println( "hhhhhhh");
}
}
public static void main(String[] args) {
Target target = new Target();
Target proxyTarget = (Target) Enhancer
.create(Target.class, (MethodInterceptor) (proxy, method, arg, methodProxy) -> {
System.out.println("before");
// 方式一 使用反射区调用
Object result = method.invoke(target, arg);
// 方式二 内部没有用反射,需要目标 spring用的就是这种机制
methodProxy.invoke(target, arg);
// 方式三
methodProxy.invokeSuper(proxy, arg);
System.out.println("after");
return result;
});
proxyTarget.foo();
}
}
spring 选择代理的方式就是cglib