xmtrock
发布于 2022-05-30 / 1,120 阅读
0

JDK代理与CGLIB代理

原始静态代理

public interface Singer {
    void sing();
}
public class Star implements Singer {
    @Override
    public void sing() {
        System.out.println("now singing~~");
    }
}
public class StarAgent implements Singer {
    Star s;

    public StarAgent(Star s) {
        this.s = s;
    }

    @Override
    public void sing() {
        System.out.println("this is for vip");
        s.sing();
    }
}
public class StaticProxy {
    public static void main(String[] args) {
        Singer singer = new StarAgent(new Star());
        singer.sing();
    }
}
this is for vip
now singing~~

JDK代理

interface JdkProxyInterface {
    void gotoSchool();
    void gotoWork();
    void oneDay();
    void oneDayFinal();
}
public class JdkConcreteClass implements JdkProxyInterface{
    @Override
    public void gotoSchool() {
        System.out.println("gotoSchool..");
    }
    @Override
    public void gotoWork() {
        System.out.println("gotoWork..");
    }
    @Override
    public void oneDay() {
        gotoSchool();
        gotoWork();
    }
    @Override
    public void oneDayFinal() {
        gotoSchool();
        gotoWork();
    }
}
/**
 * InvocationHandler 的一个实现,实际上处理代理的逻辑在这里
 */
public class JdkMyInvocationHandler implements InvocationHandler {
    JdkProxyInterface jdkProxyInterface;

    public JdkMyInvocationHandler(JdkProxyInterface jdkProxyInterface) {
        this.jdkProxyInterface = jdkProxyInterface;
    }

    private void aopMethod() {
        System.out.println("before AOP...");
    }

    //继承方法,代理时实际执行的犯法,如果要实现原方法,则需要调用method.invoke(javaProxy, args),
    // 这里还调用了一个aopMethod(),可以类比于Spring中的切面before注解。
    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        this.aopMethod();
        return method.invoke(jdkProxyInterface, args);
    }
}
public class JdkJavaProxyTest {
    public static void main(String[] args) {
        JdkConcreteClass jdkConcreteClass = new JdkConcreteClass();
        JdkProxyInterface newProxyInstanceClass =
                (JdkProxyInterface) Proxy.newProxyInstance(
                        JdkJavaProxyTest.class.getClassLoader(),
                        new Class[]{JdkProxyInterface.class},
                        new JdkMyInvocationHandler(jdkConcreteClass)
                );
        newProxyInstanceClass.oneDay();
        // newProxyInstanceClass.oneDayFinal();
    }
}
before AOP...
gotoSchool..
gotoWork..

CGLIB代理

public class CglibTestSon {
    public CglibTestSon() {
    }

    public void gotoHome() {
        System.out.println("gotoHome..");
    }

    public void gotoSchool() {
        System.out.println("gotoSchool..");
    }

    public void oneday() {
        gotoHome();
        gotoSchool();
    }

    public final void onedayFinal() {
        gotoHome();
        gotoSchool();
    }
}
/**
 * 可以类比于jdk动态代理中的InvocationHandler,
 * 实际上被代理后重要的类,实际上后续执行的就是intercept里的方法,
 * 如果需要执行原来的方法,则调用 method.invoke(s, args);
 * 这里也加了一个aopMethod();
 */
public class CglibInvoker implements MethodInterceptor {
    CglibTestSon cglibTestSon;

    public CglibInvoker(CglibTestSon cglibTestSon) {
        this.cglibTestSon = cglibTestSon;
    }

    private void aopMethod() {
        System.out.println("before AOP...");
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        aopMethod();
        Object invoke = method.invoke(cglibTestSon, args);
        return invoke;
    }
}
public class CglibProxyTest {
    public static void main(String[] args) {
        CglibTestSon CglibTestSon = new CglibTestSon();
        Enhancer enhancer = new Enhancer();
        Callback s = new CglibInvoker(CglibTestSon);
        enhancer.setSuperclass(CglibTestSon.class);
        Callback callbacks[] = new Callback[] { s };
        enhancer.setCallbacks(callbacks);
        CglibTestSon CglibTestSon2 = (CglibTestSon) enhancer.create();
        // CglibTestSon2.gotoHome();
        // CglibTestSon2.gotoSchool();
        // 这里可以看到这个类以及被代理,在执行方法前会执行aopMethod()。这里需要注意的是oneDay()方法和onedayFinal()的区别。
        // onedayFinal的方法aopMethod执行2次,oneDay的aopMethod执行1次 ,注意这里和jdk的代理的区别
        CglibTestSon2.oneday();
        CglibTestSon2.onedayFinal();
    }
}
before AOP...
gotoHome..
gotoSchool..
before AOP...
gotoHome..
before AOP...
gotoSchool..
名称 备注
静态代理 简单,代理模式,是动态代理的理论基础。常见使用在代理模式
jdk动态代理 需要有顶层接口才能使用,但是在只有顶层接口的时候也可以使用,常见是mybatis的mapper文件是代理。使用反射完成。使用了动态生成字节码技术。
cglib动态代理 可以直接代理类,使用字节码技术,不能对 final类进行继承。使用了动态生成字节码技术。

jdk底层实现

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces); // proxyName 为类名,interfaces为顶层接口Class
//如果需要看,可以将字节码写入文件进行观察
File file = new File("D:/testProxy/Ddd.class");
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(bs);
fileOutputStream.flush();
fileOutputStream.close();

自己观察可以从Proxy.newProxyInstance( ClassLoader paramClassLoader, Class<?>[] paramArrayOfClass, InvocationHandler paramInvocationHandler)进行观察,简单来看就是先生成新的class文件,然后加载到jvm中,然后使用反射,先用class取得他的构造方法,然后使用构造方法反射得到他的一个实例。
标红的是最复杂的。然后cglib的实现原理基本一致,唯一的区别在于生成新的class文件方式和结果不一样。

cglib 底层实现
直接上最终生成字节码的代码。需要注意的是这里要想执行这句话,必须在实现cglib动态代理的代码之后,否则取不到DefaultGeneratorStrategy的实例。

byte[] bs = DefaultGeneratorStrategy.INSTANCE.generate(enhancer);
FileOutputStream fileOutputStream = new FileOutputStream("D:/testProxy/Cc.class");
fileOutputStream.write(bs);
fileOutputStream.flush();
fileOutputStream.close();

跟踪enhancer.create(); 这个代码可以看具体怎么生成字节码,怎么将字节码转化为类。过程基本雷同于jdk,主要区别在于生成字节码的区别。