What is ArC
ArC is build time oriented implementation of CDI 2.0 - Contexts and Dependency Injection specification. ArC created by Quarkus team and used for DI in Quarkus. In this topic we will try use it not in Quarkus application.
How to use it
Bean definition
Because ArC based on CDI, for defining beans we will use standard annotations @ApplicationScoped
for defining bean and @Inject
for injecting beans into each other. It will look something like this:
import javax.inject.Inject;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class ServiceImpl implements Service {
@Inject
Service2 service2;
@Override
public void serve() {
}
}
Bean processing
Entry point for processing beans is BeanProcessor
. It can be created via builder. And then we can use method process
, which will resolve beans and generate resources for fast application startup.
Implementation
Maven plugin
We will be using ArC in Maven application. To modify build process we need to create plugin. We need to have access to application .class
files and all compile and runtime dependencies. It looks something like this:
package com.nutrymaco.arc.maven.plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
@Mojo(name = "build", defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, threadSafe = true)
public class BuildMojo extends AbstractMojo {
@Parameter(defaultValue = "${project}", readonly = true, required = true)
private MavenProject project;
@Override
public void execute() {
// build logic
}
}
Bean processing
BeanProcessor
need index for all classes that needed our application. So we use Jandex for creating index of all classes.
Indexer indexer = new Indexer();
// add all .class files to index
indexJar(project.getArtifact().getFile(), indexer);
for (Artifact artifact : project.getArtifacts()) {
indexJar(artifact.getFile(), indexer);
}
Index index = indexer.complete();
Then we can create BeanProcessor
BeanProcessor.builder()
.setApplicationIndex(index)
.setComputingBeanArchiveIndex(index)
.setImmutableBeanArchiveIndex(index)
.setGenerateSources(true)
.setOutput(new JarResourceOutput(generatedJarCreator))
.setTransformUnproxyableClasses(true)
.build();
JarResourceOutput
writes generated by ArC classes and service provider files into JAR
switch (resource.getType()) {
case JAVA_CLASS:
jar.addFile(
target.resolve(resource.getName()) + ".class",
resource.getData());
break;
case SERVICE_PROVIDER:
jar.addFile(
target.resolve("META-INF")
.resolve("services")
.resolve(resource.getName()).toString(),
resource.getData());
break;
case JAVA_SOURCE:
break;
}
Runtime
In main class we should initialize container and then we can request for beans.
public class AppMain {
public static void main(String[] args) {
var container = Arc.initialize();
var service = container.select(Service.class);
service.serve();
}
}
Summary
As the result we add build time DI for our application. For that we created maven plugin in which we useBeanProcessor
for processing bean definitions. Then in runtime we initialize container using Arc.initialize()
. You can use it like this or use Quarkus to get more performance optimizations and features without extra actions like creating plugins.
Top comments (0)