quarkus.oidc.client.tls.trust-store-alias=certAlias
There is also support for the public OIDC providers:
GitHub
quarkus.oidc.provider=github
quarkus.oidc.client-id=github_app_clientid
quarkus.oidc.credentials.secret=github_app_clientsecret
Apple
quarkus.oidc.provider=apple
quarkus.oidc.client-id=${apple.client-id}
quarkus.oidc.credentials.jwt.token-key-id=${apple.key-id}
quarkus.oidc.provider=google
quarkus.oidc.client-id={GOOGLE_CLIENT_ID}
quarkus.oidc.credentials.secret={GOOGLE_CLIENT_SECRET}
quarkus.oidc.token.issuer=https://accounts.google.com
Configuration options with quarkus.oidc
prefix:
enabled
-
The OIDC is enabled. (default:
true
) tenant-enabled
-
If the tenant configuration is enabled. (default:
true
) application-type
-
The application type. Possible values:
web_app
,service
. (default:service
) connection-delay
-
The maximum amount of time the adapter will try connecting.
auth-server-url
-
The base URL of the OpenID Connect (OIDC) server.
introspection-path
-
Relative path of the RFC7662 introspection service.
jwks-path
-
Relative path of the OIDC service returning a JWK set.
public-key
-
Public key for the local JWT token verification
client-id
-
The client-id of the application.
roles.role-claim-path
-
Path to the claim containing an array of groups. (
realm/groups
) roles.role-claim-separator
-
Separator for splitting a string which may contain multiple group values.
token.issuer
-
Issuer claim value.
token.audience
-
Audience claim value.
token.expiration-grace
-
Expiration grace period in seconds.
token.principal-claim
-
Name of the claim which contains a principal name.
token.refresh-expired
-
If property is enabled then a refresh token request is performed.
credentials.secret
-
The client secret
authentication.redirect-path
-
Relative path for calculating a
redirect_uri
query parameter. authentication.restore-path-after-redirect
-
The original request URI used before the authentication will be restored after the user has been redirected back to the application. (default:
true
) authentication.force-redirect-https-scheme
-
Force 'https' as the 'redirect_uri' parameter scheme when running behind an SSL terminating reverse proxy.
authentication.scopes
-
List of scopes.
authentication.extra-params
-
Additional properties which will be added as the query parameters .
authentication.cookie-path
-
Cookie path parameter.
proxy.host
-
The host (name or IP address) of the Proxy.
proxy.port
-
The port number of the Proxy. (default:
80
) proxy.username
-
The username to authenticate.
proxy.password
-
The password to authenticate.
end-session-path
-
Relative path of the OIDC
end_session_endpoint
. logout.path
-
The relative path of the logout endpoint at the application.
logout.post-logout-path
-
Relative path of the application endpoint where the user should be redirected to after logging out.
tls.verification
-
Sets the TLs verification. Possible values:
REQUIRED
,NONE
. (default:REQUIRED
).
With Keycloak OIDC server https://host:port/auth/realms/{realm} where {realm} has to be replaced by the name of the Keycloak realm.
|
You can use quarkus.http.cors property to enable consuming form different domain.
|
Testing
You can use @TestSecurity
annotation tooin OIDC by registering the following dependency:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-security-oidc</artifactId>
<scope>test</scope>
</dependency>
@Test
@TestSecurity(user = "userOidc", roles = "viewer")
@OidcSecurity(claims = {
@Claim(key = "email", value =<EMAIL_ADDRESS>}, userinfo = {
@UserInfo(key = "sub", value = "subject")
}, config = {
@ConfigMetadata(key = "issuer", value = "issuer")
})
public void testOidcWithClaimsUserInfoAndMetadata() {}
DevServices
When testing or running in dev mode Quarkus can even provide you with a zero config Keycloak out of the box.
Possible configuration values prefixed with quarkus.keycloak
:
devservices.enabled
-
If devservices is enabled or not. (default:
true
) devservices.image-name
-
The container image name to use instead of the default one. Keycloak-X can be used (
quay.io/keycloak/keycloak-x:15.0.2
) (default:quay.io/keycloak/keycloak:15.0.2
) devservices.keycloak-x-image
-
Set
quarkus.devservices.keycloak.keycloak-x-image
to override this check which may be necessary if you build custom Keycloak-X or Keycloak images. You do not need to set this property if the default check works. devservices.port
-
Optional fixed port the dev service will listen to. If not defined, the port will be chosen randomly.
devservices.shared
-
Indicates if the Keycloak broker managed by Quarkus Dev Services is shared. When shared, Quarkus looks for running containers using label-based service discovery. (default:
true
) devservices.service-name
-
The value of the
quarkus-dev-service-keycloak
label attached to the started container. (default:kafka
) devservices.realm-path
-
The class or file system path to a Keycloak realm file which will be used to initialize Keycloak
devservices.java-opts
-
The JAVA_OPTS passed to the keycloak JVM
devservices.realm-name
-
The Keycloak realm name
devservices.create-realm
-
Indicates if the Keycloak realm has to be created when the realm file pointed to by the 'realm-path' property does not exist
devservices.users
-
The Keycloak users map containing the user name and password pairs
devservices.roles
-
The Keycloak user roles
Multi-tenancy
Multi-tenancy is supported by adding a sub-category to OIDC configuration properties (ie quarkus.oidc.{tenent_id}.property
).
quarkus.oidc.auth-server-url=http://localhost:8180/auth/realms/quarkus
quarkus.oidc.client-id=multi-tenant-client
quarkus.oidc.application-type=web-app
quarkus.oidc.tenant-b.auth-server-url=https://accounts.google.com
quarkus.oidc.tenant-b.application-type=web-app
quarkus.oidc.tenant-b.client-id=xxxx
quarkus.oidc.tenant-b.credentials.secret=yyyy
quarkus.oidc.tenant-b.token.issuer=https://accounts.google.com
quarkus.oidc.tenant-b.authentication.scopes=email,profile,openid
You can inject io.quarkus.oidc.client.Tokens
, io.quarkus.oidc.OidcSession
, and io.quarkus.oidc.client.OidcClient
to interact with OIDC.
@Inject
@io.quarkus.oidc.client.NamedOidcClient("client2")
OidcClient client;
@Inject
@io.quarkus.oidc.client.NamedOidcClient("client1")
Tokens tokens1;
@Inject
OidcSession oidcSession;
OAuth2
Quarkus integrates with OAuth2 to be used in case of opaque tokens (none JWT) and its validation against an introspection endpoint.
mvn quarkus:add-extension
-Dextensions="security-oauth2"
And configuration in src/main/resources/application.properties
:
quarkus.oauth2.client-id=client_id
quarkus.oauth2.client-secret=secret
quarkus.oauth2.introspection-url=http://oauth-server/introspect
And you can map roles to be used in security annotations.
@RolesAllowed("Subscriber")
Configuration options:
quarkus.oauth2.enabled
-
Determine if the OAuth2 extension is enabled. (default:
true
) quarkus.oauth2.client-id
-
The OAuth2 client id used to validate the token.
quarkus.oauth2.client-secret
-
The OAuth2 client secret used to validate the token.
quarkus.oauth2.introspection-url
-
URL used to validate the token and gather the authentication claims.
quarkus.oauth2.role-claim
-
The claim that is used in the endpoint response to load the roles ((default:
scope
)
Authenticating via HTTP
HTTP basic auth is enabled by the quarkus.http.auth.basic=true
property.
HTTP form auth is enabled by the quarkus.http.auth.form.enabled=true
property.
Then you need to add elytron-security-properties-file
or elytron-security-jdbc
.
Security with Properties File
You can also protect endpoints and store identities (user, roles) in the file system.
mvn quarkus:add-extension
-Dextensions="elytron-security-properties-file"
You need to configure the extension with users and roles files:
And configuration in src/main/resources/application.properties
:
quarkus.security.users.file.enabled=true
quarkus.security.users.file.users=test-users.properties
quarkus.security.users.file.roles=test-roles.properties
quarkus.security.users.file.auth-mechanism=BASIC
quarkus.security.users.file.realm-name=MyRealm
quarkus.security.users.file.plain-text=true
Then users.properties
and roles.properties
:
scott=jb0ss
jdoe=p4ssw0rd
scott=Admin,admin,Tester,user
jdoe=NoRolesUser
IMPORTANT: If plain-text
is set to false
(or omitted) then passwords must be stored in the form MD5 (username
:`realm`:`password`).
Elytron File Properties configuration properties.
Prefix quarkus.security.users
is skipped.
file.enabled
-
The file realm is enabled. (default:
false
) file.auth-mechanism
-
The authentication mechanism. ( default:
BASIC
) file.realm-name
-
The authentication realm name. (default:
Quarkus
) file.plain-text
-
If passwords are in plain or in MD5. (default:
false
) file.users
-
Classpath resource of user/password. (default:
users.properties
) file.roles
-
Classpath resource of user/role. (default:
roles.properties
)
Embedded Realm
You can embed user/password/role in the same application.properties
:
quarkus.security.users.embedded.enabled=true
quarkus.security.users.embedded.plain-text=true
quarkus.security.users.embedded.users.scott=jb0ss
quarkus.security.users.embedded.roles.scott=admin,tester,user
quarkus.security.users.embedded.auth-mechanism=BASIC
IMPORTANT: If plain-text is set to false
(or omitted) then passwords must be stored in the form MD5 (username
:`realm`:`password`).
Prefix quarkus.security.users.embedded
is skipped.
algorithm
-
Determine which algorithm to use. Possible values:
DIGEST_MD5
,DIGEST_SHA
,DIGEST_SHA_256
,DIGEST_SHA_384
,DIGEST_SHA_512
,DIGEST_SHA_512_256
. (default:DIGEST_MD5
) file.enabled
-
The file realm is enabled. (default:
false
) file.auth-mechanism
-
The authentication mechanism. (default:
BASIC
) file.realm-name
-
The authentication realm name. (default:
Quarkus
) file.plain-text
-
If passwords are in plain or in MD5. (default:
false
) file.users.*
-
*
is user and value is password. file.roles.*
-
*
is user and value is role.
Security with a JDBC Realm
You can also protect endpoints and store identities in a database.
mvn quarkus:add-extension
-Dextensions="elytron-security-jdbc"
You still need to add the database driver (ie jdbc-h2
).
You need to configure JDBC and Elytron JDBC Realm:
quarkus.datasource.url=
quarkus.datasource.driver=org.h2.Driver
quarkus.datasource.username=sa
quarkus.datasource.password=sa
quarkus.security.jdbc.enabled=true
quarkus.security.jdbc.principal-query.sql=
SELECT u.password, u.role FROM test_user u WHERE u.user=?
quarkus.security.jdbc.principal-query
.clear-password-mapper.enabled=true
quarkus.security.jdbc.principal-query
.clear-password-mapper.password-index=1
quarkus.security.jdbc.principal-query
.attribute-mappings.0.index=2
quarkus.security.jdbc.principal-query
.attribute-mappings.0.to=groups
You need to set the index (1-based) of password and role.
Elytron JDBC Realm configuration properties.
Prefix quarkus.security.jdbc
is skipped.
auth-mechanism
-
The authentication mechanism. (default:
BASIC
) realm-name
-
The authentication realm name. (default:
Quarkus
) enabled
-
If the properties store is enabled. (default:
false
) principal-query.sql
-
The sql query to find the password.
principal-query.datasource
-
The data source to use.
principal-query.clear-password-mapper.enabled
-
If the clear-password-mapper is enabled. (default:
false
) principal-query.clear-password-mapper.password-index
-
The index of column containing clear password. (default:
1
) principal-query.bcrypt-password-mapper.enabled
-
If the bcrypt-password-mapper is enabled. (default:
false
) principal-query.bcrypt-password-mapper.password-index
-
The index of column containing password hash. (default:
0
) principal-query.bcrypt-password-mapper.hash-encoding
-
A string referencing the password hash encoding (
BASE64
orHEX
). (default:BASE64
) principal-query.bcrypt-password-mapper.salt-index
-
The index column containing the Bcrypt salt. (default:
0
) principal-query.bcrypt-password-mapper.salt-encoding
-
A string referencing the salt encoding (
BASE64
orHEX
). (default:BASE64
) principal-query.bcrypt-password-mapper.iteration-count-index
-
The index column containing the Bcrypt iteration count. (default:
0
)
For multiple datasources you can use the datasource name in the properties:
quarkus.datasource.url=
quarkus.security.jdbc.principal-query.sql=
quarkus.datasource.permissions.url=
quarkus.security.jdbc.principal-query.permissions.sql=
Security with JPA
You can also protect endpoints and store identities in a database using JPA.
mvn quarkus:add-extension
-Dextensions="security-jpa"
Also you might require jdbc-postgresql , resteasy , hibernate-orm-panache .
|
@io.quarkus.security.jpa.UserDefinition
@Table(name = "test_user")
@Entity
public class User extends PanacheEntity {
@io.quarkus.security.Username
public String name;
@io.quarkus.security.Password
public String pass;
@ManyToMany
@Roles
public List<Role> roles = new ArrayList<>();
public static void add(String username, String password) {
User user = new User();
user.username = username;
user.password = BcryptUtil.bcryptHash(password);
user.persist();
}
}
@Entity
public class Role extends PanacheEntity {
@ManyToMany(mappedBy = "roles")
public List<ExternalRolesUserEntity> users;
@io.quarkus.security.RolesValue
public String role;
}
You need to configure JDBC:
quarkus.datasource.url=jdbc:postgresql:security_jpa
quarkus.datasource.driver=org.postgresql.Driver
quarkus.datasource.username=quarkus
quarkus.datasource.password=quarkus
quarkus.hibernate-orm.database.generation=drop-and-create
Security with LDAP
You can also protect endpoints and store identities in a database using LDAP.
mvn quarkus:add-extension
-Dextensions="elytron-security-ldap"
quarkus.security.ldap.enabled=true
quarkus.security.ldap.dir-context.principal=uid=tool,ou=accounts,o=YourCompany,c=DE
quarkus.security.ldap.dir-context.url=ldaps://ldap.server.local
quarkus.security.ldap.dir-context.password=PASSWORD
quarkus.security.ldap.identity-mapping.rdn-identifier=uid
quarkus.security.ldap.identity-mapping.search-base-dn=ou=users,ou=tool,o=YourCompany,c=DE
quarkus.security.ldap.identity-mapping.attribute-mappings."0".from=cn
quarkus.security.ldap.identity-mapping.attribute-mappings."0".to=groups
quarkus.security.ldap.identity-mapping.attribute-mappings."0".filter=(member=uid={0})
quarkus.security.ldap.identity-mapping.attribute-mappings."0".filter-base-dn=ou=roles,ou=tool,o=YourCompany,c=DE
Testing
There is a Quarkus Test Resource that starts and stops InMemory LDAP server before and after test suite.
It is running in localhost
with dc=quarkus,dc=io
and binding credentials ("uid=admin,ou=system", "secret"
).
Imports LDIF from a file located at root of the classpath named quarkus-io.ldif
.
Register dependency io.quarkus:quarkus-test-ldap:test.
And annotate the test:
@QuarkusTestResource(io.quarkus.test.ldap.LdapServerTestResource.class)
public class ElytronLdapExtensionTestResources {
}
Elytron LDAP Realm configuration properties.
Prefix quarkus.security.ldap
is skipped.
enabled
-
Enable the LDAP elytron module (default:
false
) realm-name
-
The elytron realm name (default:
Quarkus
) direct-verification
-
Provided credentials are verified against LDAP (default:
true
) dir-context.url
-
The url of the LDAP server.
dir-context.principal
-
User (
bindDn
) which is used to connect to LDAP server. dir-context.password
-
The password (
bindCredential
) which belongs to the principal. identity-mapping.rdn-identifier
-
The identifier (
baseFilter
) which correlates to the provided user (default:uid
) identity-mapping.search-base-dn
-
The dn where we look for users.
identity-mapping.attribute-mappings.<id>.from
-
The
roleAttributeId
from which is mapped identity-mapping.attribute-mappings.<id>.to
-
The identifier whom the attribute is mapped to (default:
gropus
) identity-mapping.attribute-mappings.<id>.filter
-
The filter (
roleFilter
) identity-mapping.attribute-mappings.<id>.filter-base-dn
-
The filter base dn (
rolesContextDn
)
Vault
Quarkus integrates with Vault to manage secrets or protecting sensitive data.
mvn quarkus:add-extension
-Dextensions="vault"
And configuring Vault in application.properties
:
# vault url
quarkus.vault.url=http://localhost:8200
quarkus.vault.authentication.userpass.username=
bob
quarkus.vault.authentication.userpass.password=
sinclair
# path within the kv secret engine
quarkus.vault.secret-config-kv-path=
myapps/vault-quickstart/config
quarkus.vault.secret-config-kv-prefix.singer.paths=
multi/singer1, multi/singer2
vault kv put secret/myapps/vault-quickstart/config a-private-key=123456
vault kv put secret/multi/singer1 firstname=paul
@ConfigProperty(name = "a-private-key")
String privateKey;
@ConfigProperty(name = "singer.firstname")
String firstName;
You can access the KV engine programmatically:
@Inject
VaultKVSecretEngine kvSecretEngine;
kvSecretEngine.readSecret("myapps/vault-quickstart/" + vaultPath).toString();
Map<String, String> secrets;
kvSecretEngine.writeSecret("myapps/vault-quickstart/crud", secrets);
kvSecretEngine.deleteSecret("myapps/vault-quickstart/crud");
Fetching credentials DB
With the next kv vault kv put secret/myapps/vault-quickstart/db password=connor
quarkus.vault.credentials-provider.mydatabase.kv-path=
myapps/vault-quickstart/db
quarkus.datasource.db-kind=
postgresql
quarkus.datasource.username=
sarah
quarkus.datasource.credentials-provider=
mydatabase
quarkus.datasource.jdbc.url=
jdbc:postgresql://localhost:5432/mydatabase
No password is set as it is fetched from Vault.
Dynamic credentials are also supported:
Running the following dynamic database config in Vault:
vault write database/config/mydb plugin_name=postgresql-database-plugin …..
You can configure as:
quarkus.vault.credentials-provider
.mydatabase.database-credentials-role=mydbrole
quarkus.datasource.db-kind=
postgresql
quarkus.datasource.credentials-provider=
mydatabase
quarkus.datasource.jdbc.url=
jdbc:postgresql://localhost:5432/mydatabase
Username and password are fetched from Vault
Transit
@Inject
VaultTransitSecretEngine transit;
transit.encrypt("my_encryption", text);
transit.decrypt("my_encryption", text).asString();
transit.sign("my-sign-key", text);
Transit Key
@Inject
VaultTransitSecretEngine transit;
transit.createKey(KEY_NAME, new KeyCreationRequestDetail().setExportable(true));
transit.readKey(KEY_NAME);
transit.listKeys();
transit.exportKey(KEY_NAME, VaultTransitExportKeyType.encryption, null);
transit.updateKeyConfiguration(KEY_NAME, new KeyConfigRequestDetail().setDeletionAllowed(true));
transit.deleteKey(KEY_NAME);
Vault TOTP
TOTP secret engine is supported by using io.quarkus.vault.VaultTOTPSecretEngine
class:
@Inject
VaultTOTPSecretEngine vaultTOTPSecretEngine;
CreateKeyParameters createKeyParameters = new CreateKeyParameters("Google", "test@gmail.com");
createKeyParameters.setPeriod("30m");
/** Generate Key (QR code) */
final Optional<KeyDefinition> myKey = vaultTOTPSecretEngine
.createKey("my_key_2", createKeyParameters);
/** Generate key number to login */
final String keyCode = vaultTOTPSecretEngine.generateCode("my_key_2");
/** Login logic */
boolean valid = vaultTOTPSecretEngine.validateCode("my_key_2", keyCode);
Vault Provisioning
Vault extension offers façade classes to Vault provisioning functions:
@Inject
VaultSystemBackendEngine vaultSystemBackendEngine;
@Inject
VaultKubernetesAuthService vaultKubernetesAuthService;
String rules = "path \"transit/*\" {\n" +
" capabilities = [ \"create\", \"read\", \"update\" ]\n" +
"}";
String policyName = "sys-test-policy";
vaultSystemBackendEngine.createUpdatePolicy(policyName, rules);
vaultKubernetesAuthService
.createRole(roleName, new VaultKubernetesAuthRole()
.setBoundServiceAccountNames(boundServiceAccountNames)
.setBoundServiceAccountNamespaces(boundServiceAccountNamespaces)
.setTokenPolicies(tokenPolicies));
PKI
@Inject
public VaultPKISecretEngine pkiSecretEngine;
GenerateCertificateOptions options = new GenerateCertificateOptions();
SignedCertificate signed = pkiSecretEngine.signRequest("example-dot-com", csr, options);
return signed.certificate.getData();
Vault configuration properties.
Prefix quarkus.vault
is skipped.
url
-
Vault server URL
authentication.client-token
-
Vault token to access
authentication.app-role.role-id
-
Role Id for AppRole auth
authentication.app-role.secret-id
-
Secret Id for AppRole auth
authentication.app-role.secret-id-wrapping-token
-
Wrapping token containing a Secret Id.
secret-id
andsecret-id-wrapping-token
are exclusive. authentication.userpass.username
-
Username for userpass auth
authentication.userpass.password
-
Password for userpass auth
authentication.userpass.password-wrapping-token
-
Wrapping token containing a password.
password
andpassword-wrapping-token
are exclusive. authentication.kubernetes.role
-
Kubernetes authentication role
authentication.kubernetes.jwt-token-path
-
Location of the file containing the Kubernetes JWT token
renew-grace-period
-
Renew grace period duration (default:
1H
) secret-config-cache-period
-
Vault config source cache period (default:
10M
) secret-config-kv-path
-
Vault path in kv store. List of paths is supported in CSV
log-confidentiality-level
-
Used to hide confidential infos.
low
,medium
,high
(default:medium
) kv-secret-engine-version
-
Kv secret engine version (default: 1)
kv-secret-engine-mount-path
Kv secret engine path (default: secret
)
tls.skip-verify
-
Allows to bypass certificate validation on TLS communications (default:
false
) tls.ca-cert
-
Certificate bundle used to validate TLS communications
tls.use-kubernetes-ca-cert
-
TLS will be active (default:
true
) connect-timeout
-
Tiemout to establish a connection (default:
5S
) read-timeout
-
Request timeout (default:
1S
) credentials-provider."credentials-provider".database-credentials-role
-
Database credentials role
credentials-provider."credentials-provider".kv-path
-
A path in vault kv store, where we will find the kv-key
credentials-provider."credentials-provider".kv-key
-
Key name to search in vault path kv-path (default:
password
)
DevServices
When testing or running in dev mode Quarkus can even provide you with a zero config Vault out of the box.
Possible configuration values are shown at Vault
Amazon KMS
mvn quarkus:add-extension
-Dextensions="amazon-kms"
@Inject
KmsClient kms;
kms.encrypt(req -> req.keyId(keyArn).plaintext(
SdkBytes.fromUtf8String(data))).ciphertextBlob();
quarkus.kms.endpoint-override=http://localhost:8011
quarkus.kms.aws.region=us-east-1
quarkus.kms.aws.credentials.type=static
quarkus.kms.aws.credentials.static-provider.access-key-id=test-key
quarkus.kms.aws.credentials.static-provider.secret-access-key=test-secret
You need to set a HTTP client either URL Connection
:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
or Apache HTTP:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</dependency>
quarkus.sqs.sync-client.type=apache
You can go async by using Mutiny:
@Inject
software.amazon.awssdk.services.kms.KmsAsyncClient kms;
Uni.createFrom().completionStage(
kms.encrypt(req -> req.keyId(keyArn).plaintext(SdkBytes.fromUtf8String(data))
))
And you need to add the asynchronous Netty client:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>
Configuration properties are the same as Amazon DynamoDB but changing the prefix from dynamodb
to kms
.
Amazon IAM
mvn quarkus:add-extension
-Dextensions="quarkus-amazon-iam"
You need to set a HTTP client either URL Connection
:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
or Apache HTTP:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</dependency>
And you need to add the asynchronous Netty client:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>
@Inject
IamClient client;
@Inject
IamAsyncClient async;
quarkus.iam.endpoint-override=${iam.url}
quarkus.iam.aws.region=us-east-1
quarkus.iam.aws.credentials.type=static
quarkus.iam.aws.credentials.static-provider.access-key-id=test-key
quarkus.iam.aws.credentials.static-provider.secret-access-key=test-secret
Configuration properties are the same as Amazon DynamoDB but changing the prefix from dynamodb
to iam
.
HTTP Configuration
You can configure HTTP parameters.
Using quarkus.http
prefix:
http.access-log.exclude-pattern
-
A regular expression that can be used to exclude some paths from logging
cors
-
Enable CORS. (default:
false
) cors.origins
-
CSV of origins allowed. Regular expressions are also allowed (dedault: Any request valid.)
cors.methods
-
CSV of methods valid. (default: Any method valid.)
cors.headers
-
CSV of valid allowed headers. (default: Any requested header valid.)
cors.exposed-headers
-
CSV of valid exposed headers.
port
-
The HTTP port. (default:
8080
) test-port
-
The HTTP test port. (default:
8081
) host
-
The HTTP host. (default:
<IP_ADDRESS>
) host-enabled
-
Enable listening to host:port. (default:
true
) ssl-port
-
The HTTPS port. (default
8443
) test-ssl-port
-
The HTTPS port used to run tests. (default:
8444
) insecure-requests
-
If insecure requests are allowed. Possible values:
enabled
,redirect
,disable
. (default:enabled
) http2
-
Enables HTTP/2. (default:
true
) proxy.proxy-address-forwarding
-
The address, scheme etc will be set from headers forwarded by the proxy server.
proxy.allow-forwarded
-
Proxy address forwarding is enabled then the standard
Forwarded
header will be used, rather than the more common but not standardX-Forwarded-For
. proxy.enable-forwarded-host
-
Enable override the received request’s host through a forwarded host header
proxy.forwarded-host-header
-
Configure the forwarded host header to be used if override enabled
ssl.port
-
The HTTPS port. (default:
8443
) ssl.certificate.files
-
The files path to a service certificate or certificate chain in PEM format. Relative to
src/main/resources
. ssl.certificate.key-files
-
The files path to the corresponding certificate private key in PEM format. Relative to
src/main/resources
. ssl.certificate.key-store-file
-
The key store contains the certificate information. Relative to
src/main/resources
. ssl.certificate.key-store-key-alias
-
An optional parameter to select a specific key in the key store.
ssl.certificate.key-store-file-type
-
The key store type. It is automatically detected based on the file name or can be set manually. Supported values are:
JKS
,JCEKS
,P12
,PKCS12
orPFX
. ssl.certificate.key-store-password
-
The password to open the key store file.
ssl.certificate.trust-store-file
-
The trust store location which contains the certificate information of the certificates to trust. Relative to
src/main/resources
. ssl.certificate.trust-store-cert-alias
-
An optional parameter to trust only one specific certificate in the trust store
ssl.certificate.trust-store-file-type
-
The trust store type. It is automatically detected based on the file name or can be set manually.
ssl.certificate.trust-store-password
-
The password to open the trust store file.
ssl.cipher-suites
-
A list of strings of cipher suites to use. If not provided, a reasonable default is selected.
ssl.protocols
-
The list of protocols to explicitly enable. (default:
TLSv1.3
andTLSv1.2
). ssl.sni
-
Enables Server Name Indication (SNI), an TLS extension allowing the server to use multiple certificates. (default:
false
) ssl.client-auth
-
Configures the engine to require/request client authentication. Possible values are:
none
,request
andrequired
. (default:none
). io-threads
-
The number if IO threads used to perform IO.
limits.max-header-size
-
The maximum length of all headers. (default:
20k
) limits.max-body-size
-
The maximum size of a request body. (default:
10M
) limits.max-chunk-size
-
The max HTTP chunk size.
limits.max-initial-line-length
-
The maximum length of the initial line. (default:
4096
) idle-timeout
-
Http connection idle timeout. (default:
30M
) enable-compression
-
If responses should be compressed.
read-timeout
-
Http connection read timeout for blocking IO. (default:
60s
) body.handle-file-uploads
-
If the files sent using
multipart/form-data
will be stored locally. (default:true
) body.uploads-directory
-
The directory where the files sent using
multipart/form-data
should be stored. (default:file-uploads
) body.merge-from-attributes
-
If the form attributes should be added to the request parameters. (default:
true
) body.delete-uploaded-files-on-end
-
If the uploaded files should be removed after serving the request.
body.preallocate-body-buffer
-
If the body buffer should pre-allocated based on the
Content-Length
header value. (default:1K
) auth.session.encryption-key
-
The encryption key that is used to store persistent logins.
so-reuse-port
-
Enable socket reuse port.
tcp-quick-ack
-
Enable tcp quick ack.
tcp-cork
-
Enable tcp cork.
tcp-fast-open
-
Enable tcp fast open.
domain-socket
-
Path to a unix domain socket. (default:
/var/run/io.quarkus.app.socket
) domain-socket-enabled
-
Enables domain socket.
record-request-start-time
-
If enabled then start time will be recorded to enable logging of total request time. (default:
false
) access-log.enabled
-
If access logging is enabled. (default:
false
) access-log.pattern
-
The access log pattern. (default:
common
) access-log.log-to-file
-
If logging should be done to a separate file. (default:
false
) access-log.base-file-name
-
The access log file base name. (default:
quarkus
) access-log.log-directory
-
The log directory to use when logging access to a file.
access-log.log-directory
-
The log directory to use when logging access to a file.
access-log.log-suffix
-
The log file suffix. (default:
.log
) access-log.category
-
The log category to use if logging is being done via the standard log mechanism. (default:
io.quarkus.http.access-log
) access-log.rotate
-
If the log should be rotated daily. (default:
true
) same-site-cookie.<name>.case-sensitive
-
If the cookie pattern is case sensitive.
same-site-cookie.<name>.value
-
The value to set in the samesite attribute.
same-site-cookie.<name>.enable-client-checker
-
Some User Agents break when sent SameSite=None, this will detect them and avoid sending the value. (default:
true
) same-site-cookie.<name>.add-secure-for-none
-
If this is true then the 'secure' attribute will automatically be sent on cookies with a SameSite attribute of None. (default:
true
)
If metrics extension is registered, you can enable to get HTTP metrics by setting quarkus.resteasy.metrics.enabled
to true.
JAX-RS
Quarkus uses JAX-RS to define REST-ful web APIs. Under the covers, Rest-EASY is working with Vert.X directly without using any Servlet.
It is important to know that if you want to use any feature that implies a Servlet
(ie Servlet Filters) then you need to add the quarkus-undertow
extension to switch back to the Servlet
ecosystem but generally speaking, you don’t need to add it as everything else is well-supported.
@Path("/book")
public class BookResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Book> getAllBooks() {}
@POST
@Produces(MediaType.APPLICATION_JSON)
public Response createBook(Book book) {}
@DELETE
@Path("{isbn}")
@Produces(MediaType.APPLICATION_JSON)
public Response deleteBook(
@PathParam("isbn") String isbn) {}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("search")
public Response searchBook(
@QueryParam("description") String description) {}
}
To get information from request:
@PathParam
-
Gets content from request URI. (example:
/book/{id} @PathParam("id")
) @QueryParam
-
Gets query parameter. (example:
/book?desc="" @QueryParam("desc)
) @FormParam
-
Gets form parameter.
@MatrixParam
-
Get URI matrix parameter. (example:
/book;author=mkyong;country=malaysia
) @CookieParam
-
Gets cookie param by name.
@HeaderParam
-
Gets header parameter by name.
Valid HTTP method annotations provided by the spec are: @GET
, @POST
, @PUT
, @DELETE
, @PATCH
, @HEAD
and @OPTIONS
.
You can create new annotations that bind to HTTP methods not defined by the spec.
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("LOCK")
public @interface LOCK {
}
@LOCK
public void lockIt() {}
}
Injecting
Using @Context
annotation to inject JAX-RS and Servlet information.
@GET
public String getBase(@Context UriInfo uriInfo) {
return uriInfo.getBaseUri();
}
Possible injectable objects: SecurityContext
, Request
, Application
, Configuration
, Providers
, ResourceContext
, ServletConfig
, ServletContext
, HttpServletRequest
, HttpServletResponse
, HttpHeaders
, Urinfo
, SseEventSink
and Sse
.
HTTP Filters
HTTP request and response can be intercepted to manipulate the metadata (ie headers, parameters, media type, …) or abort a request.
You only need to implement the next ContainerRequestFilter
and ContainerResponseFilter
JAX-RS interfaces respectively.
@Provider
public class LoggingFilter
implements ContainerRequestFilter {
@Context
UriInfo info;
@Context
HttpServletRequest request;
@Override
public void filter(ContainerRequestContext context) {
final String method = context.getMethod();
final String path = info.getPath();
final String address = request.getRemoteAddr();
System.out.println("Request %s %s from IP %s",
method, path, address);
}
}
Exception Mapper
You can map exceptions to produce a custom output by implementing ExceptionMapper
interface:
@Provider
public class ErrorMapper
implements ExceptionMapper<Exception> {
@Override
public Response toResponse(Exception exception) {
int code = 500;
if (exception instanceof WebApplicationException) {
code = ((WebApplicationException) exception)
.getResponse().getStatus();
}
return Response.status(code)
.entity(
Json.createObjectBuilder()
.add("error", exception.getMessage())
.add("code", code)
.build()
)
.build();
}
}
Caching
Annotations to set Cache-Control headers:
@Produces(MediaType.APPLICATION_JSON)
@org.jboss.resteasy.annotations.cache.NoCache
public User me() {}
@Produces(MediaType.APPLICATION_JSON)
@org.jboss.resteasy.annotations.cache.Cache(
maxAge = 2000,
noStore = false
)
public User you() {}
Vert.X Filters and Routes
Programmatically
You can also register Vert.X Filters and Router programmatically inside a CDI bean:
import io.quarkus.vertx.http.runtime.filters.Filters;
import io.vertx.ext.web.Router;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
@ApplicationScoped
public class MyBean {
public void filters(
@Observes Filters filters) {
filters
.register(
rc -> {
rc.response()
.putHeader("X-Filter", "filter 1");
rc.next();
},
10);
}
public void routes(
@Observes Router router) {
router
.get("/")
.handler(rc -> rc.response().end("OK"));
}
}
Declarative
You can use @Route
annotation to use reactive routes and @RouteFilter
to sue reactive filters in a declarative way:
./mvnw quarkus:add-extension
-Dextensions="quarkus-vertx-web"
@ApplicationScoped
public class MyDeclarativeRoutes {
@Route(path = "/hello", methods = HttpMethod.GET)
public void greetings(RoutingContext rc) {
String name = rc.request().getParam("name");
if (name == null) {
name = "world";
}
rc.response().end("hello " + name);
}
@RouteFilter(20)
void filter(RoutingContext rc) {
rc.response().putHeader("X-Filter", "filter 2");
rc.next();
}
@Route
String hello(@Param Optional<String> name) {}
@Route
String helloFromHeader(@Header("My-Header") String header) {}
@Route
String createPerson(@Body Person person) {}
}
GraphQL
Quarkus integrates with GraphQL using MicroProfile GraphQL integration.
./mvnw quarkus:add-extension
-Dextensions="graphql"
@GraphQLApi
public class FilmResource {
@Query("allFilms")
public List<String> films() {
}
@Query
public String getFilm(@Name("filmId") int id)) {}
@Query
public List<Hero> getHeroesWithSurname(
@DefaultValue("Skywalker") String surname) {
}
@Mutation
public Greetings load(Greetings greetings) {
}
}
If name not provided, then query name is resolved from method name.
You can see the full schema at /graphql/schema.graphql
.
Also GraphiQL UI is enabled at dev and test mode at /graphql-ui/
.
Extension can be configured with the follwoing paramters prefixed with quarkus.smallrye-graphql
.
root-path
-
The rootPath under which queries will be served. (default:
/graphql
) root-path-ui
-
The path where GraphQL UI is available. (default:
/graphql-ui
) always-include-ui
-
The path where GraphQL UI is available. (default:
/graphql-ui
) root-path-ui
-
Always include the UI. By default this will only be included in dev and test. (default:
false
) enable-ui
-
If GraphQL UI should be enabled. (default:
false
) schema-available
-
Make the schema available over HTTP. (default:
true
) metrics.enabled
-
Enable metrics. (default:
false
)
GraphQL Clients
./mvnw quarkus:add-extension
-Dextensions="graphql-client"
quarkus.smallrye-graphql-client.star-wars.url=https://swapi-graphql.netlify.app/.netlify/functions/index
Typesafe client
@GraphQLClientApi(configKey = "star-wars")
public interface StarWarsClientApi {
FilmConnection allFilms();
}
@Inject
StarWarsClientApi typesafeClient;
allFilms
is also the name of the query.
You can override the value using @Query(value="allStarWarsFilms")
Dynamic client
@Inject
@GraphQLClient("star-wars")
DynamicGraphQLClient dynamicClient;
Document query = document(
operation(
field("allFilms",
field("films",
field("title"),
field("planetConnection",
field("planets",
field("name")
)
)
)
)
)
);
Response response = dynamicClient.executeSync(query)
Vert.X Verticle
Vert.X Verticles are also supported:
@ApplicationScoped
public class VerticleDeployer {
@Inject
Vertx vertx;
public void init(@Observes StartupEvent ev) {
CountDownLatch latch = new CountDownLatch(1);
vertx.deployVerticle(BareVerticle::new,
new DeploymentOptions()
.setConfig(
new JsonObject()
.put("id", "bare")
)
)
.thenAccept(x -> latch.countDown());
latch.countDown();
}
}
Verticles can be:
- bare
-
extending
io.vertx.core.AbstractVerticle
. - mutiny
-
extendig
io.smallrye.mutiny.vertx.core.AbstractVerticle
.
GZip Support
You can configure Quarkus to use GZip in the application.properties
file using the next properties with quarkus.resteasy
suffix:
gzip.enabled
-
EnableGZip. (default:
false
) gzip.max-input
-
Configure the upper limit on deflated request body. (default:
10M
)
GRPC
Quarkus integrates with gRPC:
./mvnw quarkus:add-extension
-Dextensions="quarkus-grpc"
Then you need to configure build tool
with gRPC plugins. In the case of Maven, the kr.motd.maven:os-maven-plugin
extension and org.xolstice.maven.plugins:protobuf-maven-plugin
Protos files are stored at src/main/proto
.
When java
files are created two service implementations are provided: one with default gRPC API and other with Mutiny support.
With quarkus.grpc.server
prefix, the next configuration properties can be set:
port
-
The gRPC Server port. (default:
9000
) host
-
The gRPC server host. (default:
<IP_ADDRESS>
) handshake-timeout
-
The gRPC handshake timeout.
max-inbound-message-size
-
The max inbound message size in bytes.
plain-text
-
Use plain text. (default:
true
) alpn
-
TWhether ALPN should be used. (default:
true
) enable-reflection-service
-
Enables the gRPC Reflection Service. (default:
false
) ssl.certificate
-
The file path to a server certificate or certificate chain in PEM format.
ssl.key
-
The file path to the corresponding certificate private key file in PEM format.
ssl.key-store
-
An optional key store which holds the certificate information instead of specifying separate files.
ssl.key-store-type
-
An optional parameter to specify the type of the key store file.
ssl.key-store-password
-
A parameter to specify the password of the key store file. (default:
password
) ssl.trust-store
-
Trust store which holds the certificate information of the certificates to trust
ssl.trust-store-type
-
Parameter to specify type of the trust store file.
ssl.trust-store-password
-
A parameter to specify the password of the trust store file.
ssl.cipher-suites
-
A list of the cipher suites to use.
ssl.protocols
-
The list of protocols to explicitly enable. (default:
TLSv1.3,TLSv1.2
) transport-security.certificate
-
The path to the certificate file.
transport-security.key
-
The path to the private key file.
load-balancing-policy
-
Use a custom load balancing policy. Possible values:
pick_first
,round_robin
,grpclb
. (default:pick_first
)
To consume the service:
@GrpcClient("hello")
GreeterGrpc.GreeterBlockingStub client;
@GrpcClient("hello")
io.grpc.Channel channel;
// Adding headers
Metadata extraHeaders = new Metadata();
extraHeaders.put("my-header", "my-interface-value");
GreeterBlockingStub alteredClient = io.quarkus.grpc.GrpcClientUtils.attachHeaders(client, extraHeaders);
Interceptors
import io.quarkus.grpc.GlobalInterceptor;
import io.grpc.ClientInterceptor;
@GlobalInterceptor
@ApplicationScoped
public class MyInterceptor implements ClientInterceptor {}
@RegisterClientInterceptor(MySpecialInterceptor.class) (1)
@GrpcClient("helloService")
Greeter greeter;
Some configuration example to set the host and the SSL parameters:
quarkus.grpc.clients.hello.host=localhost
quarkus.grpc.clients.hello.plain-text=false
quarkus.grpc.clients.hello.ssl.certificate=src/main/resources/tls/client.pem
quarkus.grpc.clients.hello.ssl.key=src/main/resources/tls/client.key
quarkus.grpc.clients.hello.ssl.trust-store=src/main/resources/tls/ca.pem
Smallrye Stork
Stork implements client load-balancing strategies supporting Kubernetes, and Consul.
Consul
Add following dependencies:
<dependency>
<groupId>io.smallrye.stork</groupId>
<artifactId>stork-service-discovery-consul</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-mutiny-vertx-consul-client</artifactId>
</dependency>
Register service instances to Consul:
@ApplicationScoped
public class Registration {
@ConfigProperty(name = "consul.host") String host;
@ConfigProperty(name = "consul.port") int port;
public void init(@Observes StartupEvent ev, Vertx vertx) {
ConsulClient client = ConsulClient.create(vertx,
new ConsulClientOptions().setHost(host).setPort(port));
client.registerServiceAndAwait(
new ServiceOptions().setPort(8080)
.setAddress("host1").setName("my-service").setId("blue"));
client.registerServiceAndAwait(
new ServiceOptions().setPort(8080)
.setAddress("host2").setName("my-service").setId("red"));
}
}
Configuration:
consul.host=localhost
consul.port=8500
stork.my-service.service-discovery=consul
stork.my-service.service-discovery.consul-host=localhost
stork.my-service.service-discovery.consul-port=8500
stork.my-service.load-balancer=round-robin
Kubernetes
Add following dependencies:
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>stork-service-discovery-kubernetes</artifactId>
</dependency>
stork.my-service.service-discovery=kubernetes
stork.my-service.service-discovery.k8s-namespace=my-namespace
stork.my-service.load-balancer=round-robin
Using Stork at client
@RegisterRestClient(baseUri = "stork://my-service")
public interface MyService {
@GET
@Produces(MediaType.TEXT_PLAIN)
String get();
}
Fault Tolerance
Quarkus uses MicroProfile Fault Tolerance spec:
./mvnw quarkus:add-extension
-Dextensions="io.quarkus:quarkus-smallrye-fault-tolerance"
MicroProfile Fault Tolerance spec uses CDI interceptor and it can be used in several elements such as CDI bean, JAX-RS resource or MicroProfile Rest Client.
To do automatic retries on a method:
@Path("/api")
@RegisterRestClient
public interface WorldClockService {
@GET @Path("/json/cet/now")
@Produces(MediaType.APPLICATION_JSON)
@Retry(maxRetries = 2)
WorldClock getNow();
}
You can set fallback code in case of an error by using @Fallback
annotation:
@Retry(maxRetries = 1)
@Fallback(fallbackMethod = "fallbackMethod")
WorldClock getNow(){}
public WorldClock fallbackMethod() {
return new WorldClock();
}
fallbackMethod
must have the same parameters and return type as the annotated method.
You can also set logic into a class that implements FallbackHandler
interface:
public class RecoverFallback
implements FallbackHandler<WorldClock> {
@Override
public WorldClock handle(ExecutionContext context) {
}
}
And set it in the annotation as value @Fallback(RecoverFallback.class)
.
In case you want to use circuit breaker pattern:
@CircuitBreaker(requestVolumeThreshold = 4,
failureRatio=0.75,
delay = 1000)
WorldClock getNow(){}
If 3 (4 x 0.75)
failures occur among the rolling window of 4 consecutive invocations then the circuit is opened for 1000 ms and then be back to half open.
If the invocation succeeds then the circuit is back to closed again.
You can use bulkahead pattern to limit the number of concurrent access to the same resource.
If the operation is synchronous it uses a semaphore approach, if it is asynchronous a thread-pool one.
When a request cannot be processed BulkheadException
is thrown.
It can be used together with any other fault tolerance annotation.
@Bulkhead(5)
@Retry(maxRetries = 4,
delay = 1000,
retryOn = BulkheadException.class)
WorldClock getNow(){}
From smallrye project Fibonacci and Exponential Backoff retries annotations are provided:
public class TwoBackoffsOnMethodService {
@Retry
@io.smallrye.faulttolerance.api.ExponentialBackoff
@io.smallrye.faulttolerance.api.FibonacciBackoff
public void hello() {
throw new IllegalArgumentException();
}
}
Fault tolerance annotations:
| Annotation | Properties |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
You can override annotation parameters via configuration file using property [classname/methodname/]annotation/parameter
:
org.acme.quickstart.WorldClock/getNow/Retry/maxDuration=30
# Class scope
org.acme.quickstart.WorldClock/Retry/maxDuration=3000
# Global
Retry/maxDuration=3000
You can also enable/disable policies using special parameter enabled
.
org.acme.quickstart.WorldClock/getNow/Retry/enabled=false
# Disable everything except fallback
MP_Fault_Tolerance_NonFallback_Enabled=false
MicroProfile Fault Tolerance integrates with MicroProfile Metrics spec. You can disable it by setting MP_Fault_Tolerance_Metrics_Enabled to false.
|
Observability
Health Checks
Quarkus relies on MicroProfile Health spec to provide health checks.
./mvnw quarkus:add-extension
-Dextensions="io.quarkus:quarkus-smallrye-health"
By just adding this extension, an endpoint is registered to /q/health
providing a default health check.
{
"status": "UP",
"checks": [
]
}
To create a custom health check you need to implement the HealthCheck
interface and annotate either with @Readiness
(ready to process requests) or @Liveness
(is running) annotations.
@Readiness
public class DatabaseHealthCheck implements HealthCheck {
@Override
public HealthCheckResponse call() {
HealthCheckResponseBuilder responseBuilder =
HealthCheckResponse.named("Database conn");
try {
checkDatabaseConnection();
responseBuilder.withData("connection", true);
responseBuilder.up();
} catch (IOException e) {
// cannot access the database
responseBuilder.down()
.withData("error", e.getMessage());
}
return responseBuilder.build();
}
}
Builds the next output:
{
"status": "UP",
"checks": [
{
"name": "Database conn",
"status": "UP",
"data": {
"connection": true
}
}
]
}
Since health checks are CDI beans, you can do:
@ApplicationScoped
public class DatabaseHealthCheck {
@Liveness
HealthCheck check1() {
return io.smallrye.health.HealthStatus
.up("successful-live");
}
@Readiness
HealthCheck check2() {
return HealthStatus
.state("successful-read", this::isReady)
}
private boolean isReady() {}
}
You can ping liveness or readiness health checks individually by querying /q/health/live
or /q/health/ready
.
Quarkus comes with some HealthCheck
implementations for checking service status.
-
SocketHealthCheck: checks if host is reachable using a socket.
-
UrlHealthCheck: checks if host is reachable using a Http URL connection.
-
InetAddressHealthCheck: checks if host is reachable using
InetAddress.isReachable
method.
@Liveness
HealthCheck check1() {
return new UrlHealthCheck("https://www.google.com")
.name("Google-Check");
}
If you want to override or set manually readiness/liveness probes, you can do it by setting health properties:
quarkus.smallrye-health.root-path=/hello
quarkus.smallrye-health.liveness-path=/customlive
quarkus.smallrye-health.readiness-path=/customready
Automatic readiness probes
Some default readiness probes are provided by default if any of the next features are added:
- datasource
-
A probe to check database connection status.
- kafka
-
A probe to check kafka connection status. In this case you need to enable manually by setting
quarkus.kafka.health.enabled
totrue
. - mongoDB
-
A probe to check MongoDB connection status.
- neo4j
-
A probe to check Neo4J connection status.
- artemis
-
A probe to check Artemis JMS connection status.
- kafka-streams
-
Liveness (for stream state) and Readiness (topics created) probes.
- vault
-
A probe to check Vault conection status.
- gRPC
-
A readiness probe for the gRPC services.
- Cassandra
-
A readiness probe to check Cassandra connection status.
- Redis
-
A readiness probe to check Redis connection status.
You can disable the automatic generation by setting <component>.health.enabled
to false.
quarkus.datasource.myotherdatasource.health-exclude=true
quarkus.datasource.health.enabled=true
quarkus.kafka-streams.health.enabled=false
quarkus.mongodb.health.enabled=false
quarkus.neo4j.health.enabled=false
In the case of Vault you can pass parameters to modify the call of the status
endpoint in Vault.
quarkus.vault.health.enabled=true
quarkus.vault.health.stand-by-ok=true
quarkus.vault.health.performance-stand-by-ok=true
Health groups are supported to provide custom health checks groups:
@io.smallrye.health.HealthGroup("mygroup1")
public class SimpleHealthGroupCheck implements HealthCheck {
}
You can ping grouped health checks by querying /group/mygroup1
.
Group root path can be configured:
quarkus.smallrye-health.group-path=/customgroup
MicroProfile Health currently doesn’t support returning reactive types, but SmallRye Health does.
Implement the io.smallrye.health.api.AsyncHealthCheck
interface instead of the org.eclipse.microprofile.health.HealthCheck
.
@Liveness
@ApplicationScoped
public class LivenessAsync implements AsyncHealthCheck {
@Override
public Uni<HealthCheckResponse> call() {
return Uni.createFrom().item(HealthCheckResponse.up("liveness-reactive"))
.onItem().delayIt().by(Duration.ofMillis(10));
}
}
Metrics
Quarkus can utilize the MicroProfile Metrics spec to provide metrics support.
./mvnw quarkus:add-extension
-Dextensions="io.quarkus:quarkus-smallrye-metrics"
The metrics can be read with JSON or the OpenMetrics format.
An endpoint is registered automatically at /q/metrics
providing default metrics.
MicroProfile Metrics annotations:
@Timed
-
Tracks the duration.
@SimplyTimed
-
Tracks the duration without mean and distribution calculations.
@Metered
-
Tracks the frequency of invocations.
@Counted
-
Counts number of invocations.
@Gauge
-
Samples the value of the annotated object.
@ConcurrentGauge
-
Gauge to count parallel invocations.
@Metric
-
Used to inject a metric. Valid types
Meter
,Timer
,Counter
,Histogram
.Gauge
only on producer methods/fields.
@GET
//...
@Timed(name = "checksTimer",
description = "A measure of how long it takes
to perform a hello.",
unit = MetricUnits.MILLISECONDS)
public String hello() {}
@Counted(name = "countWelcome",
description = "How many welcome have been performed.")
public String hello() {}
@Gauge
annotation returning a measure as a gauge.
@Gauge(name = "hottestSauce", unit = MetricUnits.NONE,
description = "Hottest Sauce so far.")
public Long hottestSauce() {}
Injecting a histogram using @Metric
.
@Inject
@Metric(name = "histogram")
Histogram historgram;
You can configure Metrics:
quarkus.smallrye-metrics.path=/mymetrics
Prefix is quarkus.smallrye-metrics
.
path
-
The path to the metrics handler. (default:
/q/metrics
) extensions.enabled
-
Metrics are enabled or not. (default:
true
) micrometer.compatibility
-
Apply Micrometer compatibility mode. (default:
false
)
quarkus.hibernate-orm.metrics.enabled
set to true
exposes Hibernate metrics under vendor
scope.
quarkus.mongodb.metrics.enabled
set to true
exposes MongoDB metrics under vendor
scope.
You can apply metrics annotations via CDI stereotypes:
@Stereotype
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
@Timed(name = "checksTimer",
description = "A measure of how long it takes
to perform a hello.",
unit = MetricUnits.MILLISECONDS)
public @interface TimedMilliseconds {
}
There is a tight integration with Micrometer in the form of an extension:
./mvnw quarkus:add-extension
-Dextensions="micrometer"
Add a micrometer dependency for the registry of your choosing:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
You can configure Micrometer.
Prefix is quarkus.micrometer
:
enabled
-
Micrometer metrics support. (default:
true
) registry-enabled-default
-
Micrometer MeterRegistry discovery. (default:
true
) binder-enabled-default
-
Micrometer MeterBinder discovery. (default:
true
) binder.vertx.enabled
-
Vert.x metrics support.
binder.mp-metrics.enabled
-
Microprofile Metrics support.
binder.jvm
-
Micrometer JVM metrics support. (default:
true
) binder.system
-
Micrometer System metrics support. (default:
true
) export.datadog.enabled
-
Support for export to Datadog Support for Datadog.
export.jmx.enabled
-
Support for export to JMX Support for JMX.
export.prometheus.enabled
-
Support for export to Prometheus.
export.prometheus.path
-
The path for the prometheus metrics endpoint (produces text/plain). (default:
/q/metrics
) export.azuremonitor.enabled
-
Support for export to Azure Monitor.
export.azuremonitor.instrumentation-key
-
The path for the azure monitor instrumentationKey.
export.statsd.enabled
-
Support for export to StatsD.
export.stackdriver.enabled
-
Micrometer metrics support. (default:
true
) export.signalfx.enabled
-
Micrometer metrics support. (default:
true
) export.signalfx.uri
-
Signalfx URI.
export.signalfx.access-token
-
Access Token.
binder.vertx.match-patterns
-
Comma-separated case-sensitive list of regular expressions defining Paths that should be matched and used as tags
binder.vertx.ignore-patterns
-
Comma-separated case-sensitive list of regular expressions defining Paths that should be ignored / not measured.
export.datadog
-
Datadog MeterRegistry configuration in
Map<String, String>
format. export.jmx
-
JMX registry configuration properties in
Map<String, String>
format. export.prometheus
-
Prometheus registry configuration properties in
Map<String, String>
format. export.stackdriver
-
Stackdriver registry configuration properties in
Map<String, String>
format.
Tracing
Quarkus can utilize the MicroProfile OpenTracing spec.
./mvnw quarkus:add-extension
-Dextensions="io.quarkus:quarkus-smallrye-opentracing"
Requests sent to any endpoint are traced automatically.
This extension includes OpenTracing support and Jaeger
tracer.
Jaeger tracer configuration:
quarkus.jaeger.service-name=myservice
quarkus.jaeger.sampler-type=const
quarkus.jaeger.sampler-param=1
quarkus.jaeger.endpoint=http://localhost:14268/api/traces
quarkus.jaeger.metrics.enabled=true
@Traced
annotation can be set to disable tracing at class or method level.
Tracer
class can be injected into the class.
@Inject
Tracer tracer;
tracer.activeSpan().setBaggageItem("key", "value");
You can disable Jaeger
extension by using quarkus.jaeger.enabled
property.
You can log the traceId
, spanId
and sampled
in normal log:
quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId},
spanId=%X{spanId}, sampled=%X{sampled} [%c{2.}] (%t) %s%e%n
Additional tracers
JDBC Tracer
Adds a span for each JDBC queries.
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-jdbc</artifactId>
</dependency>
Configure JDBC driver apart from tracing properties seen before:
# add ':tracing' to your database URL
quarkus.datasource.url=
jdbc:tracing:postgresql://localhost:5432/mydatabase
quarkus.datasource.driver=
io.opentracing.contrib.jdbc.TracingDriver
quarkus.hibernate-orm.dialect=
org.hibernate.dialect.PostgreSQLDialect
OpenTelemetry
./mvnw quarkus:add-extension
-Dextensions="opentelemetry-otlp-exporter"
Possible configuration:
quarkus.application.name=myservice
quarkus.opentelemetry.enabled=true
quarkus.opentelemetry.tracer.exporter.otlp.endpoint=http://localhost:4317
quarkus.opentelemetry.tracer.exporter.otlp.headers=Authorization=Bearer my_secret
The OpenTelemetry extension enables the W3C Trace Context and the W3C Baggage propagators, you can however choose any of the supported OpenTelemetry propagators.
The b3
, b3multi
, jaeger
and ottrace
propagators:
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-extension-trace-propagators</artifactId>
</dependency>
The xray
propagator:
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-extension-aws</artifactId>
</dependency>
You can configure OpenTelemetry.
Prefix is quarkus.opentelemetry
:
enabled
-
OpenTelemetry support (default:
true
) propagators
-
Comma separated list of OpenTelemetry propagators which must be supported. Possible values b3, b3multi, baggage, jaeger, ottrace, tracecontext, xray (default:
traceContext
,baggage
). tracer.enabled
-
Support for tracing with OpenTelemetry.
tracer.resource-attributes
-
A comma separated list of name=value resource attributes that represents the entity producing telemetry
tracer.sampler
-
The sampler to use for tracing. Possible values
off
,on
,ratio
. (Default:on
) tracer.sampler.ratio
-
Ratio to sample
tracer.sampler.parent-based
-
If the sampler to use for tracing is parent based (default:
true
) tracer.suppress-non-application-uris
-
Suppress non-application uris from trace collection. (default:
true
) tracer.exporter.otlp.enabled
-
OTLP SpanExporter support (default:
true
) - tracer.exporter.otlp.endpoint
-
The OTLP endpoint to connect to
tracer.exporter.otlp.headers
-
Key-value pairs to be used as headers associated with gRPC requests
tracer.exporter.otlp.export-timeout
-
The maximum amount of time to wait for the collector to process exported spans before an exception is thrown. (default:
10S
) tracer.exporter.otlp.compression
-
Compression method to be used by exporter to compress the payload
Kafka Tracer
Adds a span for each message sent to or received from a Kafka topic.
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-kafka-client<</artifactId>
</dependency>
And configure it:
...
mp.messaging.outgoing.generated-price.topic=prices
# For Produces
mp.messaging.outgoing.generated-price.interceptor.classes=io.opentracing.contrib.kafka.TracingProducerInterceptor
...
# For consumers
mp.messaging.incoming.prices.interceptor.classes=io.opentracing.contrib.kafka.TracingConsumerInterceptor
AWS XRay
If you are building native images, and want to use AWS X-Ray Tracing with your lambda you will need to include quarkus-amazon-lambda-xray
as a dependency in your pom.
Native Executable
You can build a native image by using GraalVM. The common use case is creating a Docker image so you can execute the next commands:
./mvnw package -Pnative -Dquarkus.native.container-build=true
docker build -f src/main/docker/Dockerfile.native
-t quarkus/getting-started .
docker run -i --rm -p 8080:8080 quarkus/getting-started
You can use quarkus.native.container-runtime
to select the container runtime to use.
Now docker
(default) and podman
are the valid options.
./mvnw package -Pnative -Dquarkus.native.container-runtime=podman
To configure native application, you can create a config
directory at the same place as the native file and place an application.properties
file inside. config/application.properties
.
To produce a native executable with native excutable use -Dquarkus.native.additional-build-args=-J—enable-preview
.
SSL
To create a native image with SSL you need to copy SunEC library and certificates:
Java 8:
FROM quay.io/quarkus/ubi-quarkus-native-image:{graalvm-version}-java8 as nativebuilder
RUN mkdir -p /tmp/ssl-libs/lib \
&& cp /opt/graalvm/jre/lib/security/cacerts /tmp/ssl-libs \
&& cp /opt/graalvm/jre/lib/amd64/libsunec.so /tmp/ssl-libs/lib/
FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY --from=nativebuilder /tmp/ssl-libs/ /work/
COPY target/*-runner /work/application
RUN chmod 775 /work /work/application
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=<IP_ADDRESS>", "-Djava.library.path=/work/lib", "-Djavax.net.ssl.trustStore=/work/cacerts"]
Java 11:
FROM quay.io/quarkus/ubi-quarkus-native-image:{graalvm-version}-java11 as nativebuilder
RUN mkdir -p /tmp/ssl-libs/lib \
&& cp /opt/graalvm/lib/security/cacerts /tmp/ssl-libs \
&& cp /opt/graalvm/lib/libsunec.so /tmp/ssl-libs/lib/
FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY --from=nativebuilder /tmp/ssl-libs/ /work/
COPY target/*-runner /work/application
RUN chmod 775 /work /work/application
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=<IP_ADDRESS>", "-Djava.library.path=/work/lib", "-Djavax.net.ssl.trustStore=/work/cacerts"]
Inclusion of resources
By default, no resources are included in native executable.
quarkus.native.resources.includes
allows to set glob expressions to include resources based on src/main/resources
path.
Given src/main/resources/foo/selected.png
:
quarkus.native.resources.includes=foo/**
Exclusion of resources
By default, no resources are excluded.
quarkus.native.resources.excludes = foo/**
Native configuration properties prefixed with quarkus.native
:
additional-build-args
-
Additional arguments to pass to the build process.
enable-http-url-handler
-
If the HTTP url handler should be enabled. (default:
true
) enable-https-url-handler
-
If the HTTPS url handler should be enabled.
enable-all-security-services
-
If all security services should be added to the native image.
user-language
-
Defines the user language used for building the native executable.
user-country
-
Defines the user country used for building the native executable.
file-encoding
-
Defines the file encoding.
add-all-charsets
-
If all character sets should be added to the native image.
graalvm-home
-
The location of the Graal distribution.
java-home
-
The location of the JDK.
native-image-xmx
-
The maximum Java heap to be used during the native image generation.
debug-build-process
-
If the native image build should wait for a debugger to be attached before running.
publish-debug-build-process-port
-
If the debug port should be published when building with docker and debug-build-process. (default:
true
) cleanup-server
-
If the native image server should be restarted.
enable-isolates
-
If isolates should be enabled. (default:
true
) enable-fallback-images
-
If a JVM based 'fallback image' should be created if native image fails.
enable-server
-
If the native image server should be used.
auto-service-loader-registration
-
If all META-INF/services entries should be automatically registered.
dump-proxies
-
If the bytecode of all proxies should be dumped for inspection.
container-build
-
If this build should be done using a container runtime.
remote-container-build
-
If this build is done using a remote docker daemon.
builder-image
-
The docker image to use to do the image build.
container-runtime
-
The container runtime that is used to do an image based build. (
docker
,podman
) container-runtime-options
-
Options to pass to the container runtime.
enable-vm-inspection
-
If the resulting image should allow VM introspection.
full-stack-traces
-
If full stack traces are enabled in the resulting image.
enable-reports
-
If the reports on call paths and included packages/classes/methods should be generated.
report-exception-stack-traces
-
If exceptions should be reported with a full stack trace.
report-errors-at-runtime
-
If errors should be reported at runtime.
enable-dashboard-dump
-
Generate the report files for GraalVM Dashboard.
resources.includes
-
A comma separated list of globs to match resource paths that should be added to the native image.
resources.excludes
-
A comma separated list of globs to match resource paths that should exclude to the native image.
debug.enabled
-
If debug is enabled and debug symbols are generated.
Container Images Creation
You can levarage to Quarkus to generation and release of Docker containers. It provides several extensions to make it so.
mvn clean package
-Dquarkus.container-image.build=true
-Dquarkus.container-image.push=true
-Dquarkus.container-image.registry=quay.io
Prefix is quarkus.container-image
:
group
-
The group/repository of the image. (default: the
${user.name}
) name
-
The name of the image. (default: the application name)
tag
-
The tag of the image. (default: the application version)
additional-tags
-
Additional tags of the container image.
registry
-
The registry to use for pushing. (default:
docker.io
) username
-
The registry username.
password
-
The registry password.
insecure
-
Flag to allow insecure registries. (default:
false
) build
-
Boolean to set if image should be built. (default:
false
) push
-
Boolean to set if image should be pushed. (default:
false
) labels
-
Custom labels to add to the generated image.
Jib
./mvnw quarkus:add-extensions
-Dextensions="quarkus-container-image-jib"
Quarkus copies any file under src/main/jib
into the built container image.
Prefix is quarkus.container-image-jib
:
base-jvm-image
-
The base image to use for the jib build. (default:
fabric8/java-alpine-openjdk8-jre
) base-native-image
-
The base image to use for the native build. (default:
registry.access.redhat.com/ubi8/ubi-minimal
) jvm-arguments
-
The arguments to pass to java. (default:
-Dquarkus.http.host=<IP_ADDRESS>,-Djava.util.logging.manager=org.jboss.logmanager.LogManager
) native-arguments
-
The arguments to pass to the native application. (default:
-Dquarkus.http.host=<IP_ADDRESS>
) environment-variables
-
Map of environment variables.
jvm-entrypoint
-
A custom entry point of the container image in JVM mode.
native-entrypoint
-
A custom entry point of the container image in native mode.
offline-mode
-
Whether or not to operate offline. (default:
false
) base-registry-username
-
The username to use to authenticate with the registry used to pull the base JVM image.
base-registry-password
-
The password to use to authenticate with the registry used to pull the base JVM image.
ports
-
The ports to expose.
user
-
The user to use in generated image.
always-cache-base-image
-
Controls the optimization which skips downloading base image layers that exist in a target registry (default:
false
). appcds-builder-image
-
When AppCDS generation is enabled, if this property is set, then the JVM used to generate the AppCDS file will be the JVM present in the container image.
platforms
-
List of target platforms. (ie
linux/amd64
). docker-executable-ame
-
Name of binary used to execute the docker commands.
Docker
./mvnw quarkus:add-extensions
-Dextensions="quarkus-container-image-docker"
Prefix is quarkus.container-image-s2i
:
dockerfile-jvm-path
-
Path to the JVM Dockerfile. (default:
${project.root}/src/main/docker/Dockerfile.jvm
) dockerfile-native-path
-
Path to the native Dockerfile. (default:
${project.root}/src/main/docker/Dockerfile.native
)
Buildpacks
./mvnw quarkus:add-extensions
-Dextensions="quarkus-container-image-buildpack"
Prefix is quarkus.buildpack
:
jvm-builder-image
-
The buildpacks builder image to use when building the project in jvm mode.
native-builder-image
-
The buildpacks builder image to use when building the project in native mode.
builder-env
-
Environment key/values to pass to buildpacks.
run-image
-
The buildpacks run image to use when building the project.
pull-timeout-seconds
-
Max pull timeout for builder/run images, in seconds (default:
300
) docker-host
-
DOCKER_HOST value to use.
log-level
-
Log level to use. (default
info
) base-registry-username
-
The username to use to authenticate with the registry used to pull the base image.
base-registry-password
-
The password to use to authenticate with the registry used to pull the base image.
S2I
./mvnw quarkus:add-extensions
-Dextensions="quarkus-container-image-s2i"
Prefix is quarkus.container-image-docker
:
base-jvm-image
-
The base image to use for the s2i build. (default:
fabric8/java-alpine-openjdk8-jre
) base-native-image
-
The base image to use for the native build. (default:
registry.access.redhat.com/ubi8/ubi-minimal
)
Kubernetes
Quarkus can use Dekorate to generate Kubernetes resources.
./mvnw quarkus:add-extensions
-Dextensions="quarkus-kubernetes"
Running ./mvnw package
the Kubernetes resources are created at target/kubernetes/
directory.
| Container Images Creation integrates with Kubernetes extension, so no need of extra Kubernetes properties. |
Generated resource is integrated with MicroProfile Health annotations.
Also, you can customize the generated resource by setting the new values in application.properties
:
quarkus.kubernetes.namespace=mynamespace
quarkus.kubernetes.replicas=3
quarkus.kubernetes.labels.foo=bar
quarkus.kubernetes.readiness-probe.period-seconds=45
quarkus.kubernetes.mounts.github-token.path=/deployment/github
quarkus.kubernetes.mounts.github-token.read-only=true
quarkus.kubernetes.secret-volumes.github-token.volume-name=github-token
quarkus.kubernetes.secret-volumes.github-token.secret-name=greeting-security
quarkus.kubernetes.secret-volumes.github-token.default-mode=420
quarkus.kubernetes.config-map-volumes.github-token.config-map-name=my-secret
quarkus.kubernetes.expose=true
quarkus.kubernetes.ingress.expose=true
quarkus.kubernetes.ingress.host=example.com
quarkus.kubernetes.env.vars.my-env-var=foobar
quarkus.kubernetes.env.configmaps=my-config-map,another-config-map
quarkus.kubernetes.env.secrets=my-secret,my-other-secret
quarkus.kubernetes.resources.requests.memory=64Mi
quarkus.kubernetes.resources.requests.cpu=250m
quarkus.kubernetes.resources.limits.memory=512Mi
quarkus.kubernetes.resources.limits.cpu=1000m
All possible values are explained at https://quarkus.io/guides/kubernetes#configuration-options.
Labels and Annotations
The generated manifest use the Kubernetes recommended labels and annotations.
"labels" : {
"app.kubernetes.io/part-of" : "todo-app",
"app.kubernetes.io/name" : "todo-rest",
"app.kubernetes.io/version" : "1.0-rc.1"
}
"annotations": {
"app.quarkus.io/vcs-url" : "<some url>",
"app.quarkus.io/commit-id" : "<some git SHA>",
}
You can override the labels by using the next properties:
quarkus.kubernetes.part-of=todo-app
quarkus.kubernetes.name=todo-rest
quarkus.kubernetes.version=1.0-rc.1
Or add new labels and/or annotations:
quarkus.kubernetes.labels.foo=bar
quarkus.kubernetes.annotations.foo=bar
metrics
When using metrics extension, Prometheus annotations are generated:
prometheus.io/scrape: "true"
prometheus.io/path: /metrics
prometheus.io/port: "8080"
Kubernetes Deployment Targets
You can generate different resources setting the property quarkus.kubernetes.deployment-target
.
Possible values are kubernetes
, openshift
and knative
.
The default value is kubernetes
.
Knative Properties
Most of the Kubernetes properties are valid in Knative output by just changing the kubernetes
prefix to knative
prefix (ie quarkus.kubernetes.readiness-probe.period-seconds
to quarkus.knative.readiness-probe.period-seconds
).
There are also specific properties for Knative:
quarkus.kubernetes.deployment-target=knative
quarkus.knative.revision-name=my-revision
quarkus.knative.traffic.my-revision.percentage=80
List of configuration options:
Using Existing Resources
You an provide your Kubernetes resources in form of yaml/json and they will provide additional resources or be used as base for the generation process:
Resources are added in src/main/kubernetes
directory with the target name (kubernetes.json
, openshift.json
, knative.json
, or the yml equivalents) with one orm ore Kubernetes resources.
Any resource found will be added in the generated manifests.
If one of the provided resources has the same name as one of the generated ones, then the generated resource will be created on top of the provided resource, respecting existing content.
To override the name of the generated resource you can use: quarkus.kubernetes.name
, quarkus.openshift.name
and quarkus.knative.name
.
Deployment
To deploy automatically the generated resources, you need to set quarkus.container.deploy
flag to true
.
mvn clean package -Dquarkus.kubernetes.deploy=true
If you set this flag to true , the build and push flags from container-image are set to true too.
|
To deploy the application, the extension uses the https://github.com/fabric8io/kubernetes-client. All options described at Kubernetes Client are valid here.
Kubernetes Service Binding
Quarkus supports binding services to applications via the Service Binding Specification for Kubernetes.
The following Quarkus extensions support this feature:
-
quarkus-jdbc-mariadb
-
quarkus-jdbc-mssql
-
quarkus-jdbc-mysql
-
quarkus-jdbc-postgresql
-
quarkus-kafka-client
-
quarkus-smallrye-reactive-messaging-kafka
-
quarkus-mongodb
./mvnw quarkus:add-extensions
-Dextensions="quarkus-kubernetes-service-binding"
Datasource configuration part is absent as it is auto-discovered by Quarkus.
Minikube
Quarkus has a Minikube extension which creates Kubernetes manifests that are tailored for Minikube.
./mvnw quarkus:add-extension
-Dextensions="minikube"
Remember to execute eval $(minikube -p minikube docker-env) to build images directly inside Minkube cluster.
|
OpenShift
Instead of adding Kubernetes extension, set container image s2i and the target
to openshift
for working with OpenShift, an extension grouping all of the is created:
./mvnw quarkus:add-extension
-Dextensions="openshift"
Kubernetes Configuration Extension
Integration between MicroProfile Config spec and ConfigMaps & Secrets:
./mvnw quarkus:add-extensions
-Dextensions="quarkus-kubernetes-config"
quarkus.kubernetes-config.enabled=true
quarkus.kubernetes-config.config-maps=cmap1,cmap2
@ConfigProperty(name = "some.prop1")
String someProp1;
@ConfigProperty(name = "some.prop2")
String someProp2;
If the config key is a Quarkus configuration file application.properties
/application.yaml
, the content is parsed and each key of the configuration file is used as config property.
List of Kubernetes Config parameters.
quarkus.kubernetes-config
as prefix is skipped in the next table.
enabled
-
The application will attempt to look up the configuration from the API server. (default:
false
) fail-on-missing-config
-
The application will not start if any of the configured config sources cannot be located. (default:
true
) config-maps
-
ConfigMaps to look for in the namespace that the Kubernetes Client has been configured for. Supports CSV.
namespace
-
Access to ConfigMaps from a specific namespace.
secrets.enabled
-
Whether or not configuration can be read from secrets. (default:
false
)
Kubernetes Client
Quarkus integrates with Fabric8 Kubernetes Client.
./mvnw quarkus:add-extension
-Dextensions="quarkus-kubernetes-client"
List of Kubernetes client parameters.
quarkus.kubernetes-client
as prefix is skipped in the next table.
trust-certs
-
Trust self-signed certificates. (default:
false
) master-url
-
URL of Kubernetes API server.
namesapce
-
Default namespace.
ca-cert-file
-
CA certificate data.
client-cert-file
-
Client certificate file.
client-cert-data
-
Client certificate data.
client-key-data
-
Client key data.
client-key-algorithm
-
Client key algorithm.
client-key-passphrase
-
Client key passphrase.
username
-
Username.
password
-
Password.
watch-reconnect-interval
-
Watch reconnect interval. (default:
PT1S
) watch-reconnect-limit
-
Maximum reconnect attempts. (default:
-1
) connection-timeout
-
Maximum amount of time to wait for a connection. (default:
PT10S
) request-timeout
-
Maximum amount of time to wait for a request. (default:
PT10S
) rolling-timeout
-
Maximum amount of time to wait for a rollout. (default:
PT15M
) http-proxy
-
HTTP proxy used to access the Kubernetes.
https-proxy
-
HTTPS proxy used to access the Kubernetes.
proxy-username
-
Proxy username.
proxy-password
-
Proxy password.
no-proxy
-
IP addresses or hosts to exclude from proxying
Or programmatically:
@Dependent
public class KubernetesClientProducer {
@Produces
public KubernetesClient kubernetesClient() {
Config config = new ConfigBuilder()
.withMasterUrl("https://mymaster.com")
.build();
return new DefaultKubernetesClient(config);
}
}
And inject it on code:
@Inject
KubernetesClient client;
ServiceList myServices = client.services().list();
Service myservice = client.services()
.inNamespace("default")
.withName("myservice")
.get();
CustomResourceDefinitionList crds = client
.customResourceDefinitions()
.list();
dummyCRD = new CustomResourceDefinitionBuilder()
...
.build()
client.customResourceDefinitions()
.create(dummyCRD);
Testing
Quarkus provides a Kubernetes Mock test resource that starts a mock of Kubernetes API server and sets the proper environment variables needed by Kubernetes Client.
Register next dependency: io.quarkus:quarkus-test-kubernetes-client:test
.
@QuarkusTestResource(KubernetesMockServerTestResource.class)
@QuarkusTest
public class KubernetesClientTest {
@MockServer
private KubernetesMockServer mockServer;
@Test
public void test() {
final Pod pod1 = ...
mockServer
.expect()
.get()
.withPath("/api/v1/namespaces/test/pods")
.andReturn(200,
new PodListBuilder()
.withNewMetadata()
.withResourceVersion("1")
.endMetadata()
.withItems(pod1, pod2)
.build())
.always();
}
}
AWS Lambda
Quarkus integrates with Amazon Lambda.
./mvnw quarkus:add-extension
-Dextensions="io.quarkus:quarkus-amazon-lambda"
And then implement com.amazonaws.services.lambda.runtime.RequestHandler
interface.
public class TestLambda
implements RequestHandler<MyInput, MyOutput> {
@Override
public MyInput handleRequest(MyOutput input,
Context context) {
}
}
The interface com.amazonaws.services.lambda.runtime.RequestStreamHandler
is also supported.
The interface com.amazon.ask.SkillStreamHandler
is also supported.
You can set the handler name by using quarkus.lambda.handler
property or by annotating the Lambda with the CDI @Named
annotation.
Test
You can write tests for Amazon lambdas:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-amazon-lambda</artifactId>
<scope>test</scope>
</dependency>
@Test
public void testLambda() {
MyInput in = new MyInput();
in.setGreeting("Hello");
in.setName("Stu");
MyOutput out = LambdaClient.invoke(MyOutput.class, in);
}
To scaffold a AWS Lambda run:
mvn archetype:generate \
-DarchetypeGroupId=io.quarkus \
-DarchetypeArtifactId=quarkus-amazon-lambda-archetype \
-DarchetypeVersion={version}
Azure Functions
Quarkus can make a microservice be deployable to the Azure Functions.
To scaffold a deployable microservice to the Azure Functions run:
mvn archetype:generate \
-DarchetypeGroupId=io.quarkus \
-DarchetypeArtifactId=quarkus-azure-functions-http-archetype \
-DarchetypeVersion={version}
Funqy
Quarkus Funqy is part of Quarkus’s serverless strategy and aims to provide a portable Java API to write functions deployable to various FaaS environments like AWS Lambda, Azure Functions, Knative, and Knative events.
public class GreetingFunction {
@Inject
GreetingService service;
@io.quarkus.funqy.Funq
public String greet(String name) {}
@io.quarkus.funqy.Funq("HelloCustomer")
public String greet(Customer name) {}
@Funq
public Greeting greet(Friend friend,
@io.quarkus.funqy.Context AwsContext ctx) {}
}
In case of Amazon Lambda, only one Funqy function can be exported per Amazon Lambda deployment.
If there is only one method annotated with @Funq
then no prob, if not, you need to set the function name with quarkus.funqy.export
property.
Funqy HTTP
You can invoke on Funqy functions in a pure HTTP environment with simple adding the Funqy HTTP extension.
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-funqy-http</artifactId>
</dependency>
Funqy Cloud Events
Add the extension:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-funqy-knative-events</artifactId>
</dependency>
@Funq
public String defaultChain(String input) {}
The Cloud Event type that triggers the function is defaultChain
.
It generates a response that triggers a new Cloud Event whose type is defaultChain.output
and the event source is defaultChain
.
It can be changed by using the next properties:
quarkus.funqy.knative-events.mapping.defaultChain.trigger=configChain.output
quarkus.funqy.knative-events.mapping.defaultChain.response-type=annotated
quarkus.funqy.knative-events.mapping.defaultChain.response-source=configChain
The properties are of form: quarkus.funqy.knative-events.mapping.{function name}.
.
Also can be overriden with @io.quarkus.funqy.knative.events.CloudEventMapping
annotation.
@Funq
@CloudEventMapping(trigger = "annotated", responseSource = "annotated", responseType = "lastChainLink")
public String annotatedChain(String input) {}
responseType
chains annotatedChain
response to lastChainLink
function.
@Funq
public void lastChainLink(String input,
@Context io.quarkus.funqy.knative.events.CloudEvent event) {}
A K-Native Trigger looks like:
apiVersion: eventing.knative.dev/v1alpha1
kind: Trigger
metadata:
name: defaultchain
spec:
filter:
attributes:
type: defaultChain
subscriber:
ref:
apiVersion: serving.knative.dev/v1
kind: Service
name: funqy-knative-events-quickstart
And to curl
from inside the Kubernetes cluster:
curl -v "http://default-broker.knativetutorial.svc.cluster.local" \
-X POST \
-H "Ce-Id: 1234" \
-H "Ce-Specversion: 1.0" \
-H "Ce-Type: defaultChain" \
-H "Ce-Source: curl" \
-H "Content-Type: application/json" \
-d '"Start"'
Apache Camel
Apache Camel Quarkus has its own site: https://github.com/apache/camel-quarkus
WebSockets
Quarkus can be used to handling web sockets.
./mvnw quarkus:add-extension
-Dextensions="quarkus-websockets"
If you only want the client you can include quarkus-websockets-client
.
And web sockets classes can be used:
@ServerEndpoint("/chat/{username}")
@ApplicationScoped
public class ChatSocket {
@OnOpen
public void onOpen(Session session,
@PathParam("username") String username) {}
@OnClose
public void onClose(..) {}
@OnError
public void onError(..., Throwable throwable) {}
@OnMessage
public void onMessage(...) {}
}
OpenAPI
Quarkus can expose its API description as OpenAPI spec and test it using Swagger UI.
./mvnw quarkus:add-extension
-Dextensions="io.quarkus:quarkus-smallrye-openapi"
Then you only need to access to /openapi
to get OpenAPI v3 spec of services.
You can update the OpenApi path by setting quarkus.smallrye-openapi.path
property.
Also, in case of starting Quarkus application in dev
or test
mode, Swagger UI is accessible at /swagger-ui
.
If you want to use it in production mode you need to set quarkus.swagger-ui.always-include
property to true
.
You can update the Swagger UI path by setting quarkus.swagger-ui.path
property.
quarkus.swagger-ui.path=/my-custom-path
Possible Swagger UI options with quarkus.swagger-ui
prefix:
urls
-
The urls that will be included as options. (ie
quarkus.swagger-ui.urls.petstore=https://petstore.swagger.io/v2/swagger.json
) urls-primary-name
-
If urls option is used, this will be the name of the default selection.
title
-
The html title for the page.
theme
-
Swagger UI theme to be used.
footer
-
A footer for the html page. Nothing by default.
deep-linking
-
Enables deep linking for tags and operations.
display-operation-id
-
Controls the display of operationId in operations list.
default-models-expand-depth
-
The default expansion depth for models.
default-model-expand-depth
-
The default expansion depth for the model on the model-example section.
default-model-rendering
-
Controls how the model is shown when the API is first rendered.
display-request-duration
-
Controls the display of the request duration (in milliseconds) for "Try it out" requests.
doc-expansion
-
Controls the default expansion setting for the operations and tags.
filter
-
Enables filtering.
max-displayed-tags
-
Limits the number of tagged operations displayed to at most this many.
operations-sorter
-
Apply a sort to the operation list of each API. (
alpha
,method
,function
) show-extensions
-
Controls the display of vendor extension.
show-common-extensions
-
Controls the display of extensions.
tag-sorter
-
Apply a sort to the tag list of each API.
on-complete
-
Provides a mechanism to be notified when Swagger UI has finished rendering a newly provided definition.
syntax-highlight
-
Set to false to deactivate syntax highlighting of payloads and cURL command.
oauth2-redirect-url
-
OAuth redirect URL.
request-interceptor
-
Function to intercept remote definition, "Try it out", and OAuth 2.0 requests.
request-curl-options
-
Array of command line options available to the curl command.
response-interceptor
-
Function to intercept remote definition, "Try it out", and OAuth 2.0 responses.
show-mutated-request
-
Uses the mutated request returned from a requestInterceptor to produce the curl command in the UI.
supported-submit-methods
-
List of HTTP methods that have the "Try it out" feature enabled.
validator-url
-
Swagger UI attempts to validate specs against swagger.io’s online validator.
with-credentials
-
Enables passing credentials, as defined in the Fetch standard, in CORS requests that are sent by the browser.
model-property-macro
-
Function to set default values to each property in model.
parameter-macro
-
Function to set default value to parameters.
persist-authorization
-
It persists authorization data and it would not be lost on browser close/refresh.
layout
-
The name of a component available via the plugin system to use as the top-level layout for Swagger UI.
plugins
-
A list of plugin functions to use in Swagger UI.
presets
-
A list of presets to use in Swagger UI.
You can customize the output by using Open API v3 annotations.
@Schema(name="Developers",
description="POJO that represents a developer.")
public class Developer {
@Schema(required = true, example = "Alex")
private String name;
}
@POST
@Path("/developer")
@Operation(summary = "Create deeloper",
description = "Only be done by admin.")
public Response createDeveloper(
@RequestBody(description = "Developer object",
required = true,
content = @Content(schema =
@Schema(implementation = Developer.class)))
Developer developer)
All possible annotations can be seen at org.eclipse.microprofile.openapi.annotations package.
You can also serve OpenAPI Schema from static files instead of dynamically generated from annotation scanning.
You need to put OpenAPIdocumentation under META-INF
directory (ie: META-INF/openapi.yaml
).
A request to /openapi
will serve the combined OpenAPI document from the static file and the generated from annotations.
You can disable the scanning documents by adding the next configuration property: mp.openapi.scan.disable=true
.
Other valid document paths are: META-INF/openapi.yml
, META-INF/openapi.json
, WEB-INF/classes/META-INF/openapi.yml
, WEB-INF/classes/META-INF/openapi.yaml
, WEB-INF/classes/META-INF/openapi.json
.
You can store generated OpenAPI schema if quarkus.swagger-ui.store-schema-directory
is set.
Possible OpenAPI options with quarkus.smallrye-openapi
prefix:
path
-
The path at which to register the OpenAPI Servlet. (default:
openapi
) store-schema-directory
-
The generated OpenAPI schema documents will be stored here on build.
always-run-filter
-
Do not run the filter only at startup, but every time the document is requested (dynamic). (default:
false
) ignore-static-document
-
Do not include the provided static openapi document. (default:
false
) additional-docs-directory
-
A list of local directories that should be scanned for yaml and/or json files to be included in the static model.
security-scheme
-
Add a certain SecurityScheme with config. (
basic
,jwt
,oidc
,oauth2Implicit
) security-scheme-name
-
Add a Security Scheme name to the generated OpenAPI document. (default:
SecurityScheme
) security-scheme-description
-
Add a description to the Security Scheme. (default:
Authentication
) basic-security-scheme-value
-
Add a scheme value to the Basic HTTP Security Scheme. (default:
basic
) jwt-security-scheme-value
-
Add a scheme value to the JWT Security Scheme. (default:
bearer
) jwt-bearer-format
-
Add a bearer format to the JWT Security Scheme. (default:
JWT
) oidc-open-id-connect-url
-
Add a openIdConnectUrl value to the OIDC Security Scheme
oauth2-implicit-refresh-url
-
Add a implicit flow refreshUrl value to the OAuth2 Security Scheme
oauth2-implicit-authorization-url
-
Add an implicit flow authorizationUrl value to the OAuth2 Security Scheme
oauth2-implicit-token-url
-
Add an implicit flow tokenUrl value to the OAuth2 Security Scheme
open-api-version
-
Override the openapi version in the Schema document
info-title
-
Set the title in Info tag in the Schema document
info-version
-
Set the version in Info tag in the Schema document
info-description
-
Set the description in Info tag in the Schema document
info-terms-of-service
-
Set the terms of the service in Info tag in the Schema document
info-contact-email
-
Set the contact email in Info tag in the Schema document
info-contact-name
-
Set the contact name in Info tag in the Schema document
info-contact-url
-
Set the contact url in Info tag in the Schema document
info-license-name
-
Set the license name in Info tag in the Schema document
info-license-url
-
Set the license url in Info tag in the Schema document
operation-id-strategy
-
Set the strategy to automatically create an operation Id. Possible values:
method
,class-method
,package-class-method
Mail Sender
You can send emails by using Quarkus Mailer extension:
./mvnw quarkus:add-extension
-Dextensions="io.quarkus:quarkus-mailer"
You can inject two possible classes io.quarkus.mailer.Mailer
for synchronous API or io.quarkus.mailer.reactive.ReactiveMailer
for asynchronous/reactive API.
@Inject
Mailer mailer;
And then you can use them to send an email:
mailer.send(
<EMAIL_ADDRESS>"Subject", "Body")
);
Reactive Mail client
@Inject
ReactiveMailer reactiveMailer;
CompletionStage<Response> stage =
reactiveMailer.send(
<EMAIL_ADDRESS>"Subject", "Body")
)
.subscribeAsCompletionStage()
.thenApply(x -> Response.accepted().build());
If you are using quarkus-resteasy-mutiny , you can return io.smallrye.mutiny.Uni type.
|
Mail
class contains methods to add cc
, bcc
, headers
, bounce address
, reply to
, attachments
, inline attachments
and html body
.
<EMAIL_ADDRESS>"Subject", body)
.addInlineAttachment("quarkus.png",
new File("quarkus.png"),
"image/png", "<my-image@quarkus.io>"));
If you need deep control you can inject Vert.x mail client @Inject MailClient client;
|
You need to configure SMTP properties to be able to send an email:
<EMAIL_ADDRESS>quarkus.mailer.host=smtp.sendgrid.net
quarkus.mailer.port=465
quarkus.mailer.ssl=true
quarkus.mailer.username=....
quarkus.mailer.password=....
List of Mailer parameters.
quarkus.
as a prefix is skipped in the next table.
| Parameter | Default | Description |
|---|---|---|
|
Default address. |
|
|
false in |
Emails not sent, just printed and stored in a |
|
Default address. |
|
|
mandatory |
SMTP host. |
|
25 |
SMTP port. |
|
The username. |
|
|
The password. |
|
|
|
Enables SSL. |
|
false |
Trust all certificates. |
|
10 |
Max open connections . |
|
Hostname for |
|
|
|
Connection pool enabled. |
|
|
Disable ESMTP. |
|
|
TLS security mode. |
|
|
Login mode. |
|
All methods. |
Space-separated list. |
|
Path of the key store. |
|
|
Key store password. |
if you enable SSL for the mailer and you want to build a native executable, you will need to enable the SSL support quarkus.ssl.native=true .
|
Testing
If quarkus.mailer.mock
is set to true
, which is the default value in dev
and test
mode, you can inject MockMailbox
to get the sent messages.
@Inject
MockMailbox mailbox;
@BeforeEach
void init() {
mailbox.clear();
}
List<Mail> sent = mailbox
.getMessagesSentTo("to@acme.org");
Scheduled Tasks
You can schedule periodic tasks with Quarkus.
@ApplicationScoped
public class CounterBean {
@Scheduled(every="10s", delayed="1s")
void increment() {}
@Scheduled(cron="0 15 10 * * ?")
void morningTask() {}
}
every
and cron
parameters can be surrounded with {}
and the value is used as config property to get the value.
@Scheduled(cron = "${morning.check.cron.expr}") void morningTask() {} @Scheduled(cron = "${myMethod.cron.expr:0 0 15 ? * MON *}") void myMethod() {}
And configure the property into application.properties
:
morning.check.cron.expr=0 15 10 * * ?
morning.check.cron.expr=disabled
By default Quarkus expresion is used, but you can change that by setting quarkus.scheduler.cron-type
property.
quarkus.scheduler.cron-type=unix
org.quartz.Scheduler
can be injected as any other bean and scehdule jobs programmatically.
@Inject
org.quartz.Scheduler quartz;
quartz.scheduleJob(job, trigger);
Quarkus provides a built-in bean of type io.quarkus.scheduler.Scheduler
:
@Inject
io.quarkus.scheduler.Scheduler scheduler;
scheduler.pause(); // Pause all
scheduler.pause("myIdentity"); // Pause a specific scheduled method by its identity
scheduler.resume("myIdentity");
scheduler.resume()
Kogito
Quarkus integrates with Kogito, a next-generation business automation toolkit from Drools and jBPM projects for adding business automation capabilities.
To start using it you only need to add the next extension:
./mvnw quarkus:add-extension
-Dextensions="kogito"
DevServices
When testing or running in dev mode Quarkus can even provide you with a zero config Kogito out of the box.
Possible configuration values prefixed with quarkus.kogito
:
devservices.enabled
-
If devservices is enabled or not. (default:
true
) devservices.image-name
-
The container image name to use instead of the default one. (default:
quay.io/kiegroup/kogito-data-index-ephemeral
) devservices.port
-
Optional fixed port the dev service will listen to. (default:
8180
) devservices.shared
-
Indicates if the Data Index instance managed by Quarkus Dev Services is shared. When shared, Quarkus looks for running containers using label-based service discovery. (default:
true
) devservices.service-name
-
The value of the
kogito-dev-service-data-index
label attached to the started container. (default:kogito-data-index
)
Apache Tika
Quarkus integrates with Apache Tika to detect and extract metadata/text from different file types:
./mvnw quarkus:add-extension
-Dextensions="quarkus-tika"
@Inject
io.quarkus.tika.TikaParser parser;
@POST
@Path("/text")
@Consumes({ "text/plain", "application/pdf",
"application/vnd.oasis.opendocument.text" })
@Produces(MediaType.TEXT_PLAIN)
public String extractText(InputStream stream) {
return parser.parse(stream).getText();
}
You can configure Apache Tika in application.properties
file by using next properties prefixed with quarkus
:
| Parameter | Default | Description |
|---|---|---|
|
|
Path to the Tika configuration resource. |
|
CSV of the abbreviated or full parser class to be loaded by the extension. |
|
|
|
The document may have other embedded documents. Set if autmatically append. |
JGit
Quarkus integrates with JGit to integrate with Git repositories:
./mvnw quarkus:add-extension
-Dextensions="quarkus-jgit"
And then you can start using JGit:
try (Git git = Git.cloneRepository()
.setDirectory(tmpDir)
.setURI(url)
.call()) {
return tmpDir.toString();
}
When running in native mode, make sure to configure SSL access correctly quarkus.ssl.native=true (Native and SSL).
|
Web Resources
You can serve web resources with Quarkus.
You need to place web resources at src/main/resources/META-INF/resources
and then they are accessible (ie http://localhost:8080/index.html)
By default static resources as served under the root context.
You can change this by using quarkus.http.root-path
property.
Transactional Memory
Quarkus integrates with the Software Transactional Memory (STM) implementation provided by the Narayana project.
./mvnw quarkus:add-extension
-Dextensions="narayana-stm"
Transactional objects must be interfaces and annotated with org.jboss.stm.annotations.Transactional
.
@Transactional
@NestedTopLevel
public interface FlightService {
int getNumberOfBookings();
void makeBooking(String details);
}
The pessimistic strategy is the default one, you can change to optimistic by using @Optimistic
.
Then you need to create the object inside org.jboss.stm.Container
.
Container<FlightService> container = new Container<>();
FlightServiceImpl instance = new FlightServiceImpl();
FlightService flightServiceProxy = container.create(instance);
The implementation of the service sets the locking and what needs to be saved/restored:
import org.jboss.stm.annotations.ReadLock;
import org.jboss.stm.annotations.State;
import org.jboss.stm.annotations.WriteLock;
public class FlightServiceImpl
implements FlightService {
@State
private int numberOfBookings;
@ReadLock
public int getNumberOfBookings() {
return numberOfBookings;
}
@WriteLock
public void makeBooking(String details) {
numberOfBookings += 1;
}
}
Any member is saved/restored automatically (@State
is not mandatory).
You can use @NotState
to avoid behaviour.
Transaction boundaries
Declarative
-
@NestedTopLevel
: Defines that the container will create a new top-level transaction for each method invocation. -
@Nested
: Defines that the container will create a new top-level or nested transaction for each method invocation.
Programmatically
AtomicAction aa = new AtomicAction();
aa.begin();
{
try {
flightService.makeBooking("BA123 ...");
taxiService.makeBooking("East Coast Taxis ...");
aa.commit();
} catch (Exception e) {
aa.abort();
}
}
Quartz
Quarkus integrates with Quartz to schedule periodic clustered tasks.
./mvnw quarkus:add-extension
-Dextensions="quartz"
@ApplicationScoped
public class TaskBean {
@Transactional
@Scheduled(every = "10s")
void schedule() {
Task task = new Task();
task.persist();
}
}
To configure in clustered mode vida DataSource:
quarkus.datasource.url=jdbc:postgresql://localhost/quarkus_test
quarkus.datasource.driver=org.postgresql.Driver
# ...
quarkus.quartz.clustered=true
quarkus.quartz.store-type=db
| You need to define the datasource used by clustered mode and also import the database tables following the Quartz schema. |
Quartz can be configured usinf the following properties with quarkus.quartz
prefix:
clustered
-
Enable cluster mode or not.
store-type
-
The type of store to use. Possible values:
ram
,db
(default:ram
) datasource
-
The name of the datasource to use.
table-prefix
-
The prefix for quartz job store tables. (default:
QRTZ_
) trigger-listeners.<name>.class
-
Class name for the trigger.
trigger-listeners.<name>.property-name
-
The properties passed to the class.
job-listeners.<name>.class
-
Class name for the job.
job-listeners.<name>.property-name
-
The properties passed to the class.
plugins.<name>.class
-
Class name for the plugin.
plugins.<name>.property-name
-
The properties passed to the class.
instance-name
-
The name of the Quartz instance. (default:
QuarkusQuartzScheduler
) thread-count
-
The size of scheduler thread pool. (default:
25
) thread-priority
-
Thread priority of worker threads in the pool. (default:
5
) force-start
-
The scheduler will be started even if no scheduled business methods are found.
start-mode
-
Scheduler can be started in different modes:
normal
,forced
orhalted
. (default:normal
)
Qute
Qute is a templating engine designed specifically to meet the Quarkus needs.
Templates should be placed by default at src/main/resources/templates
aand subdirectories.
./mvnw quarkus:add-extension
-Dextensions="quarkus-resteasy-qute"
Templates can be defined in any format, in case of HTML:
<EMAIL_ADDRESS>item}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{item.name}</title>
</head>
<body>
<h1>{item.name ?: 'Unknown'}</h1>
<h2>{str:reverse('Hello')}</h2>
<div>Price: {item.price}</div>
{#if item.price > 100}
<div>Discounted Price: {item.discountedPrice}</div>
{/if}
</body>
</html>
First line is not mandatory but helps on doing property checks at compilation time.
Including templates passing parameters:
<html>
<head>
<meta charset="UTF-8">
<title>Simple Include</title>
</head>
<body>
{#include foo limit=10 /}
</body>
</html>
To render the template:
public class Item {
public String name;
public BigDecimal price;
}
@Inject
io.quarkus.qute.Template item;
@GET
@Path("{id}")
@Produces(MediaType.TEXT_HTML)
public TemplateInstance get(@PathParam("id") Integer id) {
return item.data("item", service.findItem(id));
}
@TemplateExtension
static BigDecimal discountedPrice(Item item) {
return item.price.multiply(new BigDecimal("0.9"));
}
@TemplateExtension(namespace = "str")
public static class StringExtensions {
static String reverse(String val) {
return new StringBuilder(val).reverse().toString();
}
}
If @ResourcePath
is not used in Template
then the name of the field is used as file name.
In this case the file should be src/main/resources/templates/item.{}
.
Extension of the file is not required to be set.
discountedPrice
is not a field of the POJO but a method call.
Method definition must be annotated with @TemplateExtension
and be static method.
First parameter is used to match the base object (Item
).
@TemplateExtension
can be used at class level:
@TemplateExtension
public class MyExtensions {
static BigDecimal discountedPrice(Item item) {
return item.price.multiply(new BigDecimal("0.9"));
}
}
Methods with multiple parameters are supported too:
{item.discountedPrice(2)}
static BigDecimal discountedPrice(Item item, int scale) {
return item.price.multiply(scale);
}
Qute for
syntax supports any instance of Iterable
, Map.EntrySet
, Stream
or Integer
.
{#for i in total}
{i}:
{/for}
The next map methods are supported:
{#for key in map.keySet}
{#for value in map.values}
{map.size}
{#if map.isEmpty}
{map['foo']
The next list methods are supported:
{list[0]}
The next number methods are supported:
{#if counter.mod(5) == 0}
Switch/When
{#switch person.name}
{#case 'John'}
Hey John!
{#case 'Mary'}
Hey Mary!
{/switch}
{#when items.size}
{#is 1} (1)
There is exactly one item!
{#is > 10} (2)
There are more than 10 items!
{#else} (3)
There are 2 -10 items!
{/when}
Following operators can be used either in when
and switch
: not, ne, !=
, gt, >
, ge, >=
, lt, <
, le, <=
, in
, ni, !in
.
eval
{#eval myData.template name='Mia' /}
The result of myData.template
will be used as the template.
Message Bundling
@io.quarkus.qute.i18n.MessageBundle
public interface AppMessages {
@io.quarkus.qute.i18n.Message("Hello {name}!")
String hello_name(String name);
}
There are 3 methods to inject the message:
MessageBundles.get(AppMessages.class).hello_name("Lucie");
or
@Inject AppMessages app;
app.hello_name("Lucie");
or
<p>{msg:hello_name('Lucie')}</p>
Localization
There are two ways to set localized message:
@io.quarkus.qute.i18n.Localized("de")
public interface GermanAppMessages {
@Override
@io.quarkus.qute.i18n.Message("Hallo {name}!")
String hello_name(String name);
}
or
hello_name=Hallo {name}!
You can render programmaticaly the templates too:
// file located at src/main/resources/templates/reports/v1/report_01.{}
@ResourcePath("reports/v1/report_01")
Template report;
String output = report
.data("samples", service.get())
.render();
Value Resolvers
Value resolvers are invoked when evaluating expressions.
void configureEngine(@Observes EngineBuilder builder) {
builder.addValueResolver(ValueResolver.builder()
.appliesTo(ctx -> ctx.getBase() instanceof Long && ctx.getName().equals("tenTimes"))
.resolveSync(ctx -> (Long) ctx.getBase() * 10)
.build());
}
Content Filters
Content filters can be used to modify the template contents before parsing.
void configureEngine(@Observes EngineBuilder builder) {
builder.addParserHook(new ParserHook() {
@Override
public void beforeParsing(ParserHelper parserHelper) {
parserHelper.addContentFilter(contents -> contents.replace("${", "$\\{"));
}
});
}
Reactive and Async
CompletionStage<String> async = report.renderAsync();
Multi<String> publisher = report.createMulti();
Uni<String> content = io.smallrye.mutiny.Uni.createFrom()
.completionStage(() -> report.renderAsync());
Qute Mail Integration
@Inject
MailTemplate hello;
CompletionStage<Void> c =<EMAIL_ADDRESS>.subject("Hello from Qute template")
.data("name", "John")
.send();
INFO: Template located at src/main/resources/templates/hello.[html|txt]
.
Sentry
Quarkus integrates with Sentry for logging errors into an error monitoring system.
./mvnw quarkus:add-extension
-Dextensions="quarkus-logging-sentry"
And the configuration to send all errors occuring in the package org.example
to Sentrty with DSN<EMAIL_ADDRESS>:
quarkus.log.sentry=true
<EMAIL_ADDRESS>quarkus.log.sentry.level=ERROR
quarkus.log.sentry.in-app-packages=org.example
Full list of configuration properties having quarkus.log
as prefix:
sentry.enable
-
Enable the Sentry logging extension (default: false)
sentry.dsn
-
Where to send events.
sentry.level
-
Log level (default:
WARN
) sentry.server-name
-
Sets the server name that will be sent with each event.
sentry.in-app-packages
-
Configure which package prefixes your application uses.
JSch
Quarkus integrates with Jsch for SSH communication.
./mvnw quarkus:add-extension
-Dextensions="quarkus-jsch"
JSch jsch = new JSch();
Session session = jsch.getSession(null, host, port);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
Cache
Quarkus can cache method calls by using as key the tuple (method + arguments).
./mvnw quarkus:add-extension
-Dextensions="cache"
@io.quarkus.cache.CacheResult(cacheName = "weather-cache")
public String getDailyForecast(LocalDate date, String city) {}
@CacheInvalidate
removes the element represented by the calculated cache key from cache.
@CacheInvalidateAll
removes all entries from the cache.
@CacheKey
to specifically set the arguments to be used as key instead of all.
@ApplicationScoped
public class CachedBean {
@CacheResult(cacheName = "foo")
public Object load(Object key) {}
@CacheInvalidate(cacheName = "foo")
public void invalidate(Object key) {}
@CacheInvalidateAll(cacheName = "foo")
public void invalidateAll() {}
}
Programmatic API
@Inject
CacheManager cacheManager;
@Inject
@CacheName("my-cache")
Cache cache;
public Uni<String> getNonBlockingExpensiveValue(Object key) {
return cache.get(key, k -> {
});
}
public String getBlockingExpensiveValue(Object key) {
return cache.get(key, k -> {
}).await().indefinitely(); (4)
}
You can disable the caching system by setting quarkus.cache.enabled
property to false
.
This extension uses Caffeine as its underlying caching provider.
Each cache can be configured individually:
quarkus.cache.caffeine."foo".initial-capacity=10
quarkus.cache.caffeine."foo".maximum-size=20
quarkus.cache.caffeine."foo".expire-after-write
quarkus.cache.caffeine."bar".maximum-size=1000
Full list of configuration properties having quarkus.cache.caffeine.[cache-name]
as prefix:
initial-capacity
-
Minimum total size for the internal data structures.
maximum-size
-
Maximum number of entries the cache may contain.
expire-after-write
-
Specifies that each entry should be automatically removed from the cache once a fixed duration has elapsed after the entry’s creation, or last write.
expire-after-access
-
Specifies that each entry should be automatically removed from the cache once a fixed duration has elapsed after the entry’s creation, or last write.
| You can multiple cache annotations on a single method. |
If you see a javax.enterprise.context.ContextNotActiveException
, you need to add the quarkus-smallrye-context-propagation
extension.
Banner
Banner is printed by default. It is not an extension but placed in the core.
quarkus.banner.path
-
Path is relative to root of the classpath. (default:
default_banner.txt
) quarkus.banner.enabled
-
Enables banner. (default :
true
)
OptaPlanner
Quarkus integrates with OptaPlanner.
./mvnw quarkus:add-extension
-Dextensions="quarkus-optaplanner, quarkus-optaplanner-jackson"
@PlanningSolution
public class TimeTable {
}
@Inject
private SolverManager<TimeTable, UUID> solverManager;
UUID problemId = UUID.randomUUID();
SolverJob<TimeTable, UUID> solverJob = solverManager.solve(problemId, problem);
TimeTable solution = solverJob.getFinalBestSolution();
Possible configuration options prefixed with quarkus.optaplanner
:
solver-config-xml
-
A classpath resource to read the solver configuration XML. Not mandatory.
solver.environment-mode
-
Enable runtime assertions to detect common bugs in your implementation during development. Possible values:
FAST_ASSERT
,FULL_ASSERT
,NON_INTRUSIVE_FULL_ASSERT
,NON_REPRODUCIBLE
,REPRODUCIBLE
. (default:REPRODUCIBLE
) solver.move-thread-count
-
Enable multithreaded solving for a single problem. Possible values:
MOVE_THREAD_COUNT_NONE
,MOVE_THREAD_COUNT_AUTO
, a number or formula based on the available processors. (default:MOVE_THREAD_COUNT_NONE
) solver.termination.spent-limit
-
How long the solver can run. (ie
5s
) solver.termination.unimproved-spent-limit
-
How long the solver can run without finding a new best solution after finding a new best solution. (ie
2h
) solver.termination.best-score-limit
-
Terminates the solver when a specific or higher score has been reached. (ie
0hard/-1000soft
) solver-manager.parallel-solver-count
-
The number of solvers that run in parallel. (default:
PARALLEL_SOLVER_COUNT_AUTO
)
Context Propagation
./mvnw quarkus:add-extension
-Dextensions="quarkus-smallrye-context-propagation"
If using mutiny
extension together you already get context propagation for ArC, RESTEasy and transactions.
With CompletionStage
you need to:
@Inject ThreadContext threadContext;
@Inject ManagedExecutor managedExecutor;
threadContext.withContextCapture(..)
.thenApplyAsync(r -> {}, managedExecutor);
If you are going to use security in a reactive environment you will likely need Smallrye Content Propagation to propagate the identity throughout the reactive callback.
Configuration from HasiCorp Consul
You can read runtime configuration from HashiCorp Consul.
./mvnw quarkus:add-extension
-Dextensions="consul-config"
You need to configure Consul:
quarkus.consul-config.enabled=true
quarkus.consul-config.agent.host-port=localhost:8500
quarkus.consul-config.properties-value-keys=config/consul-test
@ConfigProperty(name = "greeting.message")
String message;
In Consul:
"Key": "config/consul-test",
"Value": "greeting.message=Hello from Consul"
Possible configuration parameters, prefixed with quarkus.consul-config
:
enabled
-
The application will attempt to look up the configuration from Consul. (default:
false
) prefix
-
Common prefix that all keys share when looking up the keys from Consul. The prefix is not included in the keys of the user configuration
- raw-value-keys
-
Keys whose value is a raw string. The keys that end up in the user configuration are the keys specified her with '/' replaced by '.'
properties-value-keys
-
Keys whose value represents a properties-like file conttent.
fail-on-missing-key
-
If the application will not start if any of the configured config sources cannot be located. (default:
true
)
trust-store
-
TrustStore to be used containing the SSL certificate used by Consul agent.
trust-store-password
-
Password of TrustStore to be used containing the SSL certificate used by Consul agent.
key-password
-
Password to recover key from KeyStore for SSL client authentication with Consul agent.
agent.host-port
-
Consul agent host. (default:
localhost:8500
) agent.use-https
-
Use HTTPS when communicating with the agent. (default:
false
) agent.token
-
Consul token to be provided when authentication is enabled.
agent.key-store
-
KeyStore (classpath or filesystem) to be used containing the SSL certificate used by Consul agent.
agent.key-store-password
-
Password of KeyStore.
agent.trust-certs
-
To trust all certificates or not.
agent.connection-timeout
-
Connection timeout. (default:
10S
) agent.read-timeout
-
Reading timeout. (default:
60S
)
Amazon Alexa
You can use Amazon Alexa by adding the extension:
./mvnw quarkus:add-extension
-Dextensions="quarkus-amazon-alexa"
WebJar Locator
To change how you can refer to webjars skipping the version part you can use WebJars locator extension.
./mvnw quarkus:add-extension
-Dextensions="webjars-locator"
Then the JavaScript location is changed from /webjars/jquery/3.1.1/jquery.min.js
to /webjars/jquery/jquery.min.js
in your HTML files.
Amazon SES
mvn quarkus:add-extension
-Dextensions="amazon-ses"
@Inject
software.amazon.awssdk.services.ses.SesClient sesClient;
@Inject
software.amazon.awssdk.services.ses.SesAsyncClient sesClient;
quarkus.ses.endpoint-override=http://localhost:8012
quarkus.ses.aws.region=us-east-1
quarkus.ses.aws.credentials.type=static
quarkus.ses.aws.credentials.static-provider.access-key-id=test-key
quarkus.ses.aws.credentials.static-provider.secret-access-key=test-secret
You need to set a HTTP client either URL Connection
:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
or Apache HTTP:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</dependency>
quarkus.ses.sync-client.type=apache
Or async:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>
Configuration properties are the same as Amazon DynamoDB but changing the prefix from dynamodb
to ses
.
Jbang
Creating an initial script:
jbang scripting/quarkusapp.java
Adding Quarkus dependencies in script:
//DEPS io.quarkus:quarkus-resteasy:{quarkus-version}
Put some Quarkus CLI code:
@Path("/hello")
@ApplicationScoped
public class quarkusapp {
@GET
public String sayHello() {
return "hello";
}
public static void main(String[] args) {
Quarkus.run(args);
}
}
To run the script:
jbang quarkusapp.java
A Maven goal is provided to scaffold a project:
mvn io.quarkus:quarkus-maven-plugin:<version>:create-jbang
Narayana LRA
The LRA (short for Long Running Action) participant extension is useful in microservice based designs where different services can benefit from a relaxed notion of distributed consistency.
The extension integrates with MicroProfile LRA
./mvnw quarkus:add-extension
-Dextensions="narayana-lra"
The only LRA specific property is quarkus.lra.coordinator-url=<url>
which specifies the HTTP endpoint of an external coordinator,
@Path("/")
@ApplicationScoped
public class SimpleLRAParticipant
{
@LRA(LRA.Type.REQUIRES_NEW)
@Path("/work")
@PUT
public void doInNewLongRunningAction(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId)
{
}
@org.eclipse.microprofile.lra.annotation.Complete
@Path("/complete")
@PUT
public Response completeWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId,
String userData)
{
return Response.ok(ParticipantStatus.Completed.name()).build();
}
@org.eclipse.microprofile.lra.annotation.Compensate
@Path("/compensate")
@PUT
public Response compensateWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId,
String userData)
{
return Response.ok(ParticipantStatus.Compensated.name()).build();
}
}
@LRA
can be used in differrent methods, so it’s started in one method and finished in another resource using end
attribute:
@LRA(value = LRA.Type.REQUIRED, // if there is no incoming context a new one is created
cancelOn = {
Response.Status.INTERNAL_SERVER_ERROR // cancel on a 500 code
},
cancelOnFamily = {
Response.Status.Family.CLIENT_ERROR // cancel on any 4xx code
},
end = false) // the LRA will continue to run when the method finishes
@LRA(LRA.Type.MANDATORY, // requires an active context before method can be executed
end = true)
Spring DI
Quarkus provides a compatibility layer for Spring dependency injection.
./mvnw quarkus:add-extension
-Dextensions="quarkus-spring-di"
Some examples of what you can do. Notice that annotations are the Spring original ones.
@Configuration public class AppConfiguration { @Bean(name = "capitalizeFunction") public StringFunction capitalizer() { return String::toUpperCase; } }
Or as a component:
@Component("noopFunction")
public class NoOpSingleStringFunction
implements StringFunction {
}
Also as a service and injection properties from application.properties
.
@Service
public class MessageProducer {
@Value("${greeting.message}")
String message;
}
And you can inject using Autowired
or constructor in a component and in a JAX-RS resource too.
@Component
public class GreeterBean {
private final MessageProducer messageProducer;
@Autowired @Qualifier("noopFunction")
StringFunction noopStringFunction;
public GreeterBean(MessageProducer messageProducer) {
this.messageProducer = messageProducer;
}
}
Spring Boot Configuration
Quarkus provides a compatibility layer for Spring Boot ConfigurationProperties
.
./mvnw quarkus:add-extension
-Dextensions="quarkus-spring-boot-properties"
@ConfigurationProperties("example")
public final class ClassProperties {
private String value;
private AnotherClass anotherClass;
// getters/setters
}
example.value=class-value
example.anotherClass.value=true
Spring Cloud Config Client
Quarkus integrates Spring Cloud Config Client and MicroProfile Config spec.
./mvnw quarkus:add-extension
-Dextensions="quarkus-spring-cloud-config-client"
You need to configure the extension:
quarkus.spring-cloud-config.uri=http://localhost:8089
quarkus.spring-cloud-config.username=user
quarkus.spring-cloud-config.password=pass
quarkus.spring-cloud-config.enabled=true
@ConfigProperty(name = "greeting.message")
String greeting;
Prefix is quarkus.spring-cloud-config
.
uri
-
Base URI where the Spring Cloud Config Server is available. (default:
localhost:8888
) username
-
Username to be used if the Config Server has BASIC Auth enabled.
password
-
Password to be used if the Config Server has BASIC Auth enabled.
enabled
-
Enables read configuration from Spring Cloud Config Server. (default:
false
) fail-fast
-
True to not start application if cannot access to the server. (default:
false
) connection-timeout
-
The amount of time to wait when initially establishing a connection before giving up and timing out. (default:
10S
) read-timeout
-
The amount of time to wait for a read on a socket before an exception is thrown. (default:
60S
) label
-
The label to be used to pull remote configuration properties.
Spring Web
Quarkus provides a compatibility layer for Spring Web.
./mvnw quarkus:add-extension
-Dextensions="quarkus-spring-web"
Specifically supports the REST related features.
Notice that infrastructure things like BeanPostProcessor
will not be executed.
@RestController
@RequestMapping("/greeting")
public class GreetingController {
private final GreetingBean greetingBean;
public GreetingController(GreetingBean greetingBean) {
this.greetingBean = greetingBean;
}
@GetMapping("/{name}")
public Greeting hello(@PathVariable(name = "name")
String name) {
return new Greeting(greetingBean.greet(name));
}
}
Supported annotations are: RestController
, RequestMapping
, GetMapping
, PostMapping
, PutMapping
, DeleteMapping
, PatchMapping
, RequestParam
, RequestHeader
, MatrixVariable
, PathVariable
, CookieValue
, RequestBody
, ResponseStatus
, ExceptionHandler
and RestControllerAdvice
.
If you scaffold the project with spring-web extension, then Spring Web annotations are sed in the generated project. mvn io.quarkus:quarkus-maven-plugin:2.7.0.Final:create … -Dextensions="spring-web" .
|
The next return types are supported: org.springframework.http.ResponseEntity
and java.util.Map
.
The next parameter types are supported: An Exception
argument and ServletRequest
/HttpServletRequest
(adding quarkus-undertow
dependency).
Spring Data JPA
While users are encouraged to use Hibernate ORM with Panache for Relational Database access, Quarkus provides a compatibility layer for Spring Data JPA repositories.
./mvnw quarkus:add-extension
-Dextensions="quarkus-spring-data-jpa"
INFO: Of course you still need to add the JDBC driver, and configure it in application.properties
.
public interface FruitRepository
extends CrudRepository<Fruit, Long> {
List<Fruit> findByColor(String color);
}
And then you can inject it either as shown in Spring DI or in Spring Web.
Interfaces supported:
-
org.springframework.data.repository.Repository
-
org.springframework.data.repository.CrudRepository
-
org.springframework.data.repository.PagingAndSortingRepository
-
org.springframework.data.jpa.repository.JpaRepository
.
INFO: Generated repositories are automatically annotated with @Transactional
.
Repository fragments is also supported:
public interface PersonRepository
extends JpaRepository<Person, Long>, PersonFragment {
void makeNameUpperCase(Person person);
}
User defined queries:
@Query("select m from Movie m where m.rating = ?1")
Iterator<Movie> findByRating(String rating);
@Modifying
@Query("delete from Movie where rating = :rating")
void deleteByRating(@Param("rating") String rating);
@Query(value = "SELECT COUNT(*), publicationYear FROM Book GROUP BY publicationYear")
List<BookCountByYear> findAllByPublicationYear2();
interface BookCountByYear {
int getPublicationYear();
Long getCount();
}
What is currently unsupported:
-
Methods of
org.springframework.data.repository.query.QueryByExampleExecutor
-
QueryDSL support
-
Customizing the base repository
-
java.util.concurrent.Future
as return type -
Native and named queries when using
@Query
Spring Data Rest
While users are encouraged to use REST Data with Panache for the REST data access endpoints generation, Quarkus provides a compatibility layer for Spring Data REST in the form of the spring-data-rest
extension.
./mvnw quarkus:add-extension
-Dextensions="spring-data-rest"
import java.util.Optional;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
@RepositoryRestResource(exported = false, path = "/my-fruits")
public interface FruitsRepository extends CrudRepository<Fruit, Long> {
@RestResource(exported = true)
Optional<Fruit> findById(Long id);
@RestResource(exported = true)
Iterable<Fruit> findAll();
}
The spring-data-jpa
extension will generate an implementation for this repository. Then the spring-data-rest
extension will generate a REST CRUD resource for it.
The following interfaces are supported:
-
org.springframework.data.repository.CrudRepository
-
org.springframework.data.repository.PagingAndSortingRepository
-
org.springframework.data.jpa.repository.JpaRepository
Spring Security
Quarkus provides a compatibility layer for Spring Security.
./mvnw quarkus:add-extension
-Dextensions="spring-security"
You need to choose a security extension to define user, roles, … such as openid-connect
, oauth2
, properties-file
or security-jdbc
as seen at RBAC.
Then you can use Spring Security annotations to protect the methods:
@Secured("admin")
@GetMapping
public String hello() {
return "hello";
}
Quarkus provides support for some of the most used features of Spring Security’s @PreAuthorize
annotation.
Some examples:
hasRole
-
@PreAuthorize("hasRole('admin')")
-
@PreAuthorize("hasRole(@roles.USER)")
whereroles
is a bean defined with@Component
annotation andUSER
is a public field of the class.
hasAnyRole
-
<EMAIL_ADDRESS>'view')")
Permit and Deny All
-
@PreAuthorize("permitAll()")
-
@PreAuthorize("denyAll()")
Anonymous and Authenticated
-
@PreAuthorize("isAnonymous()")
-
@PreAuthorize("isAuthenticated()")
Expressions
-
Checks if the current logged in user is the same as the username method parameter:
@PreAuthorize("#person.name == authentication.principal.username")
public void doSomethingElse(Person person){}
-
Checks if calling a method if user can access:
@PreAuthorize("@personChecker.check(#person, authentication.principal.username)")
public void doSomething(Person person){}
@Component
public class PersonChecker {
public boolean check(Person person, String username) {
return person.getName().equals(username);
}
}
-
Combining expressions:
@PreAuthorize("hasAnyRole('user', 'admin') AND #user == principal.username")
public void allowedForUser(String user) {}
Spring Cache
Quarkus provides a compatibility layer for Spring dependency injection.
./mvnw quarkus:add-extension
-Dextensions="spring-cache"
@org.springframework.cache.annotation.Cacheable("someCache")
public Greeting greet(String name) {}
Quarkus provides compatibility with the following Spring Cache annotations:
-
@Cacheable
-
@CachePut
-
@CacheEvict
Spring Schedule
Quarkus provides a compatibility layer for Spring Scheduled annotation.
./mvnw quarkus:add-extension
-Dextensions="spring-scheduled"
@org.springframework.scheduling.annotation.Scheduled(cron="*/5 * * * * ?")
void cronJob() {
System.out.println("Cron expression hardcoded");
}
@Scheduled(fixedRate = 1000)
@Scheduled(cron = "{cron.expr}")