Quarkus中的静态代理
#java #quarkus #bytecode #cdi

在以前的post中,描述了Quarkus构建过程以及在构建时间中如何帮助进行DI。在这篇文章中,我们讨论了代理创建的标准方法以及Quarkus是如何做到的。

CDI和拦截器

所有Quarkus应用程序都使用CDI - Contexts and Dependency Injection。它具有声明性创建拦截器的注释。结果,目标类创建具有Interceptor逻辑的代理。但是如何创建代理取决于实现。

如何创建代理

首先,让我们看拦截器的示例。 GreeterInterceptor -Interceptor和WorkServiceServiceImplFinalService-将被代理的bean类。

GreeterInterceptor拦截器 - 拦截豆的打印问候

@Greeter
@Interceptor
public class GreeterInterceptor {

    @AroundInvoke
    public Object greet(InvocationContext ctx) throws Exception {
        System.out.println("Hello from " + ctx.getTarget());
        return ctx.proceed();
    }

}

WorkService bean-未实现任何接口

@Singleton
public class WorkService {

    @Greeter
    public void serve() {
        System.out.println("I'm doing work");
    }

}

ServiceImpl bean-实现接口Service

@Singleton
public class ServiceImpl implements Service {

    @Greeter
    @Override
    public void serve() {
        System.out.println("I'm doing work");
    }

}

FinalService bean-不实现界面,具有 final 修饰符

@Singleton
public final class FinalService {

    @Greeter
    public void serve() {
        System.out.println("I'm doing work");
    }

}

动态代理

动态代理是在运行时创建的代理。有两种方法可以做到这一点:bytecode Estrenation and Java Dynamic Proxy Class API

Java动态代理类API

使用此API,您可以像这样的代码创建代理

InvocationHandler handler = new MyInvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // proxy logic
    }
}
Service f = (Service) Proxy.newProxyInstance(
                        Service.class.getClassLoader(),
                        new Class<?>[] { Service.class },
                        handler);

此API的主要限制,您只能为接口创建代理,因此在我们的示例中只能用于ServiceImpl bean。

运行时字节代码生成

可以使用诸如cglib(但它们不支持JDK17+)或ByteBuddy的字节码生成LIB实现此方法。使用ByteCode Generation,您可以从我们的示例中为WorkServiceServiceImpl创建代理。但是,如果目标类是最终的FinalService,则字节码的生成可能会有所帮助。

Quarkus的代理创建

与上面描述的情况不同,Quarkus知道在构建时间哪个类需要代理。因此,可以在构建时间生成而不会在运行时浪费资源,因此可以 static代理

Quarkus也可以使用final修饰符修改类的字节码,因此可以代理。结果,Quarkus可以为我们所有示例创建代理-WorkService(普通类),ServiceImpl(实现接口)和FinalService(与final修饰符类)。

概括

在此主题中,我们讨论了创建代理的主要方法 - 字节码生成和Java Dynamic代理类API。 Quarkus结合了字节码的生成,字节码转换和有关所有类的知识,以在构建时间生成代理。从而在运行时提供更好的表现,并为最终课程创建代理的可能性。