-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AOT Optimizations #868
AOT Optimizations #868
Conversation
...-aot/src/main/java/io/micronaut/security/aot/OpenIdProviderMetadataFetcherCodeGenerator.java
Outdated
Show resolved
Hide resolved
...-aot/src/main/java/io/micronaut/security/aot/OpenIdProviderMetadataFetcherCodeGenerator.java
Outdated
Show resolved
Hide resolved
The approach we used during the pairing session will not work. After thinking about this while having lunch, we are generating source code which is a bean. However that bean won't be processed by Micronaut annotation processors, so bean definitions won't be generated (AOT runs after that phase). Even if we made it so that it can generate such beans, then they wouldn't be used in any case if the "service loading" optimization is enabled, because we would scan for available beans before this class is generated, so it would never appear in the final list of beans. There is, however, a different approach we can use, which is the one which is most used in core itself. There's a class called public class DefaultOpenIdProviderMetadataFetcher implements OpenIdProviderMetadataFetcher {
private static final Logger LOG = LoggerFactory.getLogger(DefaultOpenIdProviderMetadataFetcher.class);
private final static Optimizations OPTIMIZATIONS = StaticOptimizations.get(Optimizations.class).orElse(new Optimizations(Collections.emptyMap()));
private final HttpClient client;
private final ObjectMapper objectMapper;
private final OpenIdClientConfiguration openIdClientConfiguration;
public static class Optimizations {
private final Map<String, Supplier<DefaultOpenIdProviderMetadata>> suppliers;
public Optimizations(Map<String, Supplier<DefaultOpenIdProviderMetadata>> suppliers) {
this.suppliers = suppliers;
}
public Optional<Supplier<DefaultOpenIdProviderMetadata>> findMetadata(String name) {
return Optional.ofNullable(suppliers.get(name));
}
}
public DefaultOpenIdProviderMetadataFetcher(OpenIdClientConfiguration openIdClientConfiguration,
ObjectMapper objectMapper,
@Client HttpClient client) {
this.openIdClientConfiguration = openIdClientConfiguration;
this.objectMapper = objectMapper;
this.client = client;
}
@Override
@NonNull
public DefaultOpenIdProviderMetadata fetch() {
return OPTIMIZATIONS.findMetadata(openIdClientConfiguration.getName())
.map(Supplier::get)
.orElseGet(() -> openIdClientConfiguration.getIssuer()
.map(issuer -> {
try {
URL configurationUrl = new URL(issuer, StringUtils.prependUri(issuer.getPath(), openIdClientConfiguration.getConfigurationPath()));
if (LOG.isDebugEnabled()) {
LOG.debug("Sending request for OpenID configuration for provider [{}] to URL [{}]", openIdClientConfiguration.getName(), configurationUrl);
}
//TODO this returns ReadTimeoutException - return issuerClient.toBlocking().retrieve(configurationUrl.toString(), DefaultOpenIdProviderMetadata.class);
String json = client.toBlocking().retrieve(configurationUrl.toString(), String.class);
return objectMapper.readValue(json, DefaultOpenIdProviderMetadata.class);
} catch (MalformedURLException e) {
throw new BeanInstantiationException("Failure parsing issuer URL " + issuer.toString(), e);
} catch (HttpClientResponseException e) {
throw new BeanInstantiationException("Failed to retrieve OpenID configuration for " + openIdClientConfiguration.getName(), e);
} catch (JsonProcessingException e) {
throw new BeanInstantiationException("JSON Processing Exception parsing issuer URL returned JSON " + issuer.toString(), e);
}
}).orElse(new DefaultOpenIdProviderMetadata())
);
}
} then our code generator needs to create the injection of metadata via |
This addresses a couple problems: - AOT cannot generate new beans, because they wouldn't be processed by Micronaut annotation processors - new beans wouldn't be visible to other optimizations, in particular the one which preloads services As a consequence, we rework the code generator so that it uses the static optimizations facility instead.
I have pushed changes showing what I mean by using |
This fixes the issue with the environment bean not available.
...-aot/src/main/java/io/micronaut/security/aot/OpenIdProviderMetadataFetcherCodeGenerator.java
Outdated
Show resolved
Hide resolved
.../src/main/java/io/micronaut/security/oauth2/client/DefaultOpenIdProviderMetadataFetcher.java
Outdated
Show resolved
Hide resolved
.../src/main/java/io/micronaut/security/oauth2/client/OpenIdProviderMetadataFetcherFactory.java
Outdated
Show resolved
Hide resolved
This commit introduces a new project, `test-suite-aot`, aimed at testing that the AOT module works properly. Currently it doesn't do much except making sure that the AOT code generator is called.
In Micronaut AOT 1.0.0-M6, loading the static optimizations has been reworked and needs to be done using a dedicated API. This is what this commit fixes. The API change was needed to make sure that the optimizations are set _before_ they are actually read. There was a possibility that the optimizations are set after, typically in AWS functions.
4f4d20e
to
fd9de39
Compare
For a controller such as: package example.micronaut;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Status;
import io.micronaut.security.oauth2.client.DefaultOpenIdProviderMetadata;
import io.micronaut.security.oauth2.client.OpenIdProviderMetadataFetcher;
import io.micronaut.security.token.jwt.signature.jwks.JwkSetFetcher;
import jakarta.annotation.security.PermitAll;
@Controller
public class HomeController {
public HomeController(OpenIdProviderMetadataFetcher openIdProviderMetadataFetcher, JwkSetFetcher jwkSetFetcher) {
DefaultOpenIdProviderMetadata metadata = openIdProviderMetadataFetcher.fetch();
jwkSetFetcher.fetch(metadata.getJwksUri());
}
@PermitAll
@Get
@Status(HttpStatus.OK)
void index() {
}
} which exercise every Micronaut Security AOT Optimization, we get 1s improvement.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spotted we're publishing the test-suite-utils module to maven, I'll raise a separate PR
...later... #1137
Co-authored-by: Tim Yates <[email protected]>
dependencies { | ||
... | ||
.. | ||
aotPlugins("io.micronaut.security:micronaut-security-aot") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you will need a version here too, because I think we don't apply the Micronaut BOM to all configurations, but I may be wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a version and a link to releases 7bcfa42
https://micronaut-projects.github.io/micronaut-aot/latest/guide/[Micronaut AOT] is a framework which implements ahead-of-time (AOT) optimizations for Micronaut application and libraries. Those optimizations consist of computing at build time things which would normally be done at runtime] | ||
____ | ||
|
||
Micronaut Security offers several ahead-of-time optimizations. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⭕ Maybe clarify the tradeoffs of using AOT: you will save requests at the application startup, which can save a few seconds, at the cost of having a binary which is bound to a specific configuration version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a asciidoc warning callout e420598
SonarCloud Quality Gate failed. |
No description provided.