【问题标题】:How to get data via springboot JPA at ApplicationScope如何在 ApplicationScoped 通过 Spring Boot JPA 获取数据
【发布时间】:2022-01-18 18:38:55
【问题描述】:

我需要在应用程序启动时获取数据,并且数据将保留在整个应用程序范围内,因为这是将进一步使用的参考数据

这是我的 bean,它在应用程序范围内存储数据
ApplicationBean.java

@Component
@Slf4j
public class ApplicationBean {

    @Getter
    private List<Discounts> discountList = new ArrayList<>();

    @Autowired
    private DiscountService discountService;

    @Bean
    @ApplicationScope
    @EventListener(ApplicationReadyEvent.class)
    public  void getDiscounts(){
    log.info("Inside Application Scope...");
        discountList=discountService.getAllDiscounts();
    }
}

DiscountService.java

@Service
public class DiscountService {

    @Autowired
    private DiscountRepository discountRepository;

   public List<Discounts> getAllDiscounts(){

       return discountRepository.findAll();
    }
    
}

这里是存储库DiscountRepository.java

@Repository
public interface DiscountRepository extends JpaRepository<Discounts,Long> {
    @Override
    List<Discounts> findAll();

    @Override
    List<Discounts> findAllById(Iterable<Long> longs);

}

错误

19:52:27.154 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
19:52:27.169 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.54]
19:52:27.295 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
19:52:27.342 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
19:52:27.717 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
19:52:28.038 [main] INFO  o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
19:52:28.124 [main] INFO  org.hibernate.Version - HHH000412: Hibernate ORM core version 5.4.32.Final
19:52:28.290 [main] INFO  o.h.annotations.common.Version - HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
19:52:28.463 [main] INFO  org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
19:52:29.170 [main] INFO  o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
19:52:29.641 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
19:52:29.657 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
19:52:29.657 [main] INFO  o.a.catalina.core.StandardService - Stopping service [Tomcat]
**19:52:29.688 [main] ERROR o.s.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getDiscounts' defined in BeanDefinition defined in class path resource [com/xyz/bookingservice/config/ApplicationBean.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of void: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class void**
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:628)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:925)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332)
    at com.xyz.bookingservice.BookingserviceApplication.main(BookingserviceApplication.java:10)
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of void: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class void
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:209)
    at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110)
    at org.springframework.aop.scope.ScopedProxyFactoryBean.setBeanFactory(ScopedProxyFactoryBean.java:117)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1826)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1791)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
    ... 15 common frames omitted
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class void
    at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:660)
    at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at org.springframework.cglib.core.ClassLoaderAwareGeneratorStrategy.generate(ClassLoaderAwareGeneratorStrategy.java:57)
    at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:358)
    at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:585)
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:110)
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:108)
    at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
    at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:134)
    at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)
    at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:572)
    at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:419)
    at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:57)
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:206)
    ... 20 common frames omitted

Process finished with exit code 1


我不知道如何做到这一点?我是否必须将 DiscountService 和 DiscountRepository 的范围更改为 ApplicationScope?

【问题讨论】:

  • 为什么你认为必须使用@ApplicationScope?
  • @Bean@ApplicationScope 都不能在 void 方法上工作,而且在这里也毫无用处。 Spring bean 默认情况下是单例的,并且存在于整个应用程序中,因此默认范围就足够了。只需使用@PostConstruct 或更好的ApplicationListener 代替事件监听器(后者将在一切开始并设置后运行)。
  • @SimonMartinelli:无论请求或会话如何,我都希望在应用程序上线或运行之前保留数据。不想每次请求都从数据库中获取这些静态数据

标签: spring-boot jpa spring-data-jpa


【解决方案1】:

只需执行以下操作:

@Component
@Slf4j
public class ApplicationBean implements ApplicationRunner {

    private List<Discounts> discountList = new ArrayList<>();

    private final DiscountService discountService;
    
    public ApplicationBean(DiscountService discountService) {
      this.discountService=discountService;
    }

    public void run(ApplicationArguments args) {
      this.init();
    }

    private void init(){
        log.info("Inside Application Scope...");
        discountList=discountService.getAllDiscounts();
    }

    public List<Discounts> getDiscountList() {
       return Collections.unmodifableList(this.discountList);
    }
}

或者只使用@PostContruct

@Component
@Slf4j
public class ApplicationBean {

    private List<Discounts> discountList = new ArrayList<>();

    private final DiscountService discountService;
    
    public ApplicationBean(DiscountService discountService) {
      this.discountService=discountService;
    }

    @PostConstruct
    public void init(){
        log.info("Inside Application Scope...");
        discountList=discountService.getAllDiscounts();
    }

    public List<Discounts> getDiscountList() {
       return Collections.unmodifableList(this.discountList);
    }
}

我更改为构造函数注入,因为这应该是首选方式,您还希望防止 getter 返回实际列表,而是列表的副本。

最后一点,您甚至可能需要重新考虑这一点,并使用 JPA 提供程序的二级缓存来缓存查询结果。我非常怀疑您永远不会添加折扣,现在您需要重新启动整个应用程序才能刷新该数据。

【讨论】:

    猜你喜欢
    • 2019-08-19
    • 2019-06-03
    • 1970-01-01
    • 1970-01-01
    • 2017-07-15
    • 1970-01-01
    • 2020-01-16
    • 1970-01-01
    • 2017-11-24
    相关资源
    最近更新 更多