Spring Dependency Injection
While you are encouraged to use CDI annotations for injection, Quarkus provides a compatibility layer for Spring dependency injection in the form of the spring-di extension.
This step explains how your Quarkus application can leverage the well known Dependency Injection annotations included in the Spring Framework.
Let’s proceed to create some beans using various Spring annotations.
Creating the Functional Interface
First you'll create a StringFunction
interface that some of your beans will implement and which will be injected into another bean later on. This functional interface provides target types for lambda expressions and method references you'll define.
Note: Functional Interfaces are part of the base Java platform, and are not Spring-specific.
src/main/java/org/acme/quickstart/StringFunction.java
Add this code for the interface:
package org.acme.quickstart;
import java.util.function.Function;
public interface StringFunction extends Function<String, String> {
}
With the interface in place, we will add an AppConfiguration
class which will use Spring’s Java Config style for defining a bean. It will be used to create a StringFunction
bean that will capitalize the text passed as a parameter.
src/main/java/org/acme/quickstart/AppConfiguration.java
Add this code:
package org.acme.quickstart;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfiguration {
@Bean(name = "capitalizeFunction")
public StringFunction capitalizer() {
return String::toUpperCase;
}
}
Creating Functions
The next step is to define another bean that will implement StringFunction
using Spring’s stereotype annotation style. This bean will effectively be a no-op bean that simply returns the input as is.
src/main/java/org/acme/quickstart/NoOpSingleStringFunction.java
Add this code:
package org.acme.quickstart;
import org.springframework.stereotype.Component;
@Component("noopFunction")
public class NoOpSingleStringFunction implements StringFunction {
@Override
public String apply(String s) {
return s;
}
}
Adding Injectable Configuration
Quarkus also provides support for injecting configuration values using Spring’s @Value
annotation. Configuration parameters are added to the file:
src/main/resources/application.properties
taste.message = tastes great
You'll also need to add a new Spring Bean to use this configuration value. Create a new file at:
src/main/java/org/acme/quickstart/MessageProducer.java
Add this code:
package org.acme.quickstart;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class MessageProducer {
@Value("${taste.message}")
String message;
public String getTaste() {
return message;
}
}
Bringing Everything Together
The final bean you'll create ties together all of the previous beans.
Create a new file for this final bean at:
src/main/java/org/acme/quickstart/TasterBean.java
Add this code:
package org.acme.quickstart;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class TasterBean {
private final MessageProducer messageProducer;
@Autowired
@Qualifier("noopFunction")
StringFunction noopStringFunction;
@Autowired
@Qualifier("capitalizeFunction")
StringFunction capitalizerStringFunction;
@Value("${taste.suffix:!}")
String suffix;
public TasterBean(MessageProducer messageProducer) {
this.messageProducer = messageProducer;
}
public String taste(String fruitName) {
final String initialValue = fruitName + ": " + messageProducer.getTaste() + " " + suffix;
return noopStringFunction.andThen(capitalizerStringFunction).apply(initialValue);
}
}
In the code above, we see that both field injection and constructor injection are being used (note that constructor injection does not need the @Autowired
annotation since there is a single constructor). Furthermore, the @Value
annotation on suffix
has also a default value defined, which in this case will be used since we have not defined taste.suffix
in application.properties
.
This new TasterBean
has a method taste()
that will report how each fruit tastes. It also uses our functions noopStringFunction
and capitalizerStringFunction
that we've injected via @Autowired
to both do nothing and also transform the result INTO ALL CAPS.
With our data model, repository, and accessor beans in place, let's move to the final step where we'll expose our fruits to the outside world via Spring Web annotations.