spring-attic / spring-native

Spring Native is now superseded by Spring Boot 3 official native support
https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html
Apache License 2.0
2.74k stars 356 forks source link

Introduce initial caching support #465

Closed sdeleuze closed 1 year ago

sdeleuze commented 3 years ago

We have basic configuration for caching in CachingHints, but EhCache is not supported, and enabling caching support in PetClinic JPA with the following configuration:

@Configuration
@EnableCaching
class CacheConfiguration {

    @Bean
    public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() {
        return cm -> {
            cm.createCache("vets", cacheConfiguration());
        };
    }

    private javax.cache.configuration.Configuration<Object, Object> cacheConfiguration() {
        return new MutableConfiguration<>().setStatisticsEnabled(true);
    }

}

Generates this error that seems to indicate the need for a processor:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'vetController' defined in class path resource [org/springframework/samples/petclinic/vet/VetController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'vetRepository': Post-processing of FactoryBean's singleton object failed; nested exception is com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [interface org.springframework.samples.petclinic.vet.VetRepository, interface org.springframework.data.repository.Repository, interface org.springframework.transaction.interceptor.TransactionalProxy, interface org.springframework.aop.framework.Advised, interface org.springframework.core.DecoratingProxy, interface java.io.Serializable] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles=<comma-separated-config-files> and -H:DynamicProxyConfigurationResources=<comma-separated-config-resources> options.

We should also document what kind of caching is supported (see the list in CacheType) and bring back caching support in the petclinic-jpa sample as configured in https://github.com/spring-projects/spring-petclinic.

sdeleuze commented 3 years ago

As a follow-up of #481, here is my proposal for a more efficient caching support.

First, once https://github.com/spring-projects/spring-boot/pull/25321 is merged, we should configure CacheConfigurations to be initialized at build time to avoid using the cache configuration classes at runtime if they are not useful.

Second, we should update CacheConfigurationImportSelector substitution to add classpath check (based on manual conversion of @ConditionalOnClass to return only the relevant ones.

Third, we should update CacheHints to dynamically add the relevant hints based on a build-time execution of CacheConfigurationImportSelector.

sdeleuze commented 3 years ago

Tentatively scheduled for 0.9.0 since that's an important feature.

snicoll commented 3 years ago

@sdeleuze I can see this is blocked. Anything I can help you with?

sdeleuze commented 3 years ago

Thanks for the offer, I am progressing again on it after the discussion we had on #526.

sdeleuze commented 3 years ago

I gave it another try with Ehcache 3 and JSR 107, and ended up being blocked on unsafe access in ThreadLocalRandomUtil that I was not able to make it work despite what I think is proper unsafe field configuration. This is likely fixable but will require more time.

That issue + the fact that we need a processor for creating dynamically the proxy configuration + the fact that we need time for proper testing, feedback and adding support for other mechanism clearly indicate to me that this is not doable for 0.9.0.

I have pushed my work on https://github.com/sdeleuze/spring-native/commit/caching. Let's get back on this for 0.10.0.

goafabric commented 3 years ago

It would also be nice to have caffeine working. While SimpleCache works btw. out of the box for now, Caffeine needs a lot of Typehints in Version 2.8.x

Following this issue which implicates that Quarkus and Micronaut got it working: https://github.com/ben-manes/caffeine/issues/434 I put a lot of Typehints (see below)

But still more and more Hints would be needed, because of the excessive use of Reflection. Version 3.x uses much less Reflection, but there i also gave up after hours. Would be great to see this supported by Spring

-- cut - not enought to get it working ---

@TypeHint(typeNames = { "com.github.benmanes.caffeine.cache.PSW", "com.github.benmanes.caffeine.cache.PSWMS", "com.github.benmanes.caffeine.cache.SSLA", "com.github.benmanes.caffeine.cache.SSLMSW", "com.github.benmanes.caffeine.cache.SSMSW", "com.github.benmanes.caffeine.cache.SSMSA", "com.github.benmanes.caffeine.cache.BLCHeader$DrainStatusRef" }, access = AccessBits.ALL )

ben-manes commented 3 years ago

Caffeine v3 no longer uses Unsafe, so that might help you get farther if somehow blocked on Ehcache due to that.

The Quarkus folks suggested a compile-time evaluation, but I don't really understand Graal enough to implement and verify the suggestion. Any help making this easier for integrators would be appreciated.

goafabric commented 3 years ago

Caffeine v3 no longer uses Unsafe, so that might help you get farther if somehow blocked on Ehcache due to that.

The Quarkus folks suggested a compile-time evaluation, but I don't really understand Graal enough to implement and verify the suggestion. Any help making this easier for integrators would be appreciated.

Thanks for your reply .. actually thats what i tried out, Caffeine v3 because it uses much less reflection ... unfortunately i still could not get this running, because still a lot of hints needed to be added, that i could not figure out. I might eventually try out v3 again if this seems to be the right choice

goafabric commented 3 years ago

@ben-manes oh sorry .. I got it wrong .. you are actually the developer of caffeine .. so I guess you know better :) first and foremost thx for this awesome piece of software ... but as stated .. even with unsafe gone, from what I also saw in the code, its not working, at least not of the box, because i suspect further things need to be added

Also one of the problems with version 3.x is, that its' compile with java 11. Which is usually not a big deal, but as the standard for graalvm is currently still level 8, graalvm 11 has to be used, which seems to have some drawbacks currently. But I'll try nontheless

.. so I retried V3.x and it basically crashes with the exception below and I am pretty sure that i already invested some time 1 month ago to dig in deeper without finding a solution

Caused by: java.lang.NoSuchFieldException: no such field: com.github.benmanes.caffeine.cache.UnboundedLocalCache.refreshes/java.util.concurrent.ConcurrentMap/getField at java.lang.invoke.MemberName.makeAccessException(MemberName.java:965) ~[na:na] at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1101) ~[na:na] at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:2021) ~[na:na] at java.lang.invoke.MethodHandles$Lookup.findVarHandle(MethodHandles.java:1514) ~[na:na] at com.github.benmanes.caffeine.cache.UnboundedLocalCache.(UnboundedLocalCache.java:88) ~[na:na] ... 31 common frames omitted Caused by: java.lang.NoSuchFieldError: refreshes

ben-manes commented 3 years ago

Thanks for trying to get it all working. I’m not familiar with Graal and I’d be open to suggestions to make Caffeine better at supporting it. Sorry that you have to fight through this.

https://github.com/oracle/graal/issues/3028 sounds like VarHandles are not supported, leading to improper dead code elimination. I guess it is incompatible with 3.x for now.

In 2.x there is a jandex resource that lists all of the reflections. It was removed in v3 as Quarkus decided it wasn’t necessary, but maybe that could help you bootstrap 2.x. Otherwise I’m at a loss as well.

goafabric commented 3 years ago

Thank you for your support. I think your suggestions should be a great help to ger it working. I‘ll give it a spin eventually

sdeleuze commented 3 years ago

Let's try to provide initial caching support for Redis, the new AOT engine from 0.11 should make it much easier.

linghengqian commented 2 years ago

I didn't see any discussion about Spring Native in the Github issue of EhCache. Based on the above discussion, can I assume that Spring Native and JCache (aka JSR107) configured via EhCache are still unavailable?

snicoll commented 2 years ago

The issue is still open, so yes. To a large extent, this is a bout adding the necessary hints on third party libraries though so the fix wouldn't probably come here.

linghengqian commented 2 years ago

We have basic configuration for caching in CachingHints, but EhCache is not supported, and enabling caching support in PetClinic JPA with the following configuration:

@Configuration
@EnableCaching
class CacheConfiguration {

  @Bean
  public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() {
      return cm -> {
          cm.createCache("vets", cacheConfiguration());
      };
  }

  private javax.cache.configuration.Configuration<Object, Object> cacheConfiguration() {
      return new MutableConfiguration<>().setStatisticsEnabled(true);
  }

}

I'm sitting on some related attempts. As in https://www.ehcache.org/blog/2017/03/15/spontaneous-cache-creation.html , it seems that EhCache 3 discourages the adoption of new MutableConfiguration<>(), which is inherently somewhat conflicting with JCacheManagerCustomizer. Can I understand that this is because Spring discourages exposing the API of JCache-implementing components within JCache's operations, or is this an intentional design by EhCache 3? In the URL of https://github.com/ehcache/ehcache3/issues/2997 , I made some attempts to understand why EhCache 3 is configured that way in JCacheManagerCustomizer,but some differences related to it confuse me.

linghengqian commented 1 year ago
sdeleuze commented 1 year ago

Spring Native is now superseded by Spring Boot 3 official native support, see the related reference documentation for more details.

As a consequence, I am closing this issue, and recommend trying your use case with latest Spring Boot 3 version. If you still experience the issue reported here, please open an issue directly on the related Spring project (Spring Framework, Data, Security, Boot, Cloud, etc.) with a reproducer.

Thanks for your contribution on the experimental Spring Native project, we hope you will enjoy the official native support introduced by Spring Boot 3.