“J.U.C”:Condition (r)

本文通过一个生产者消费者模型的例子,展示了如何使用Condition解决线程同步问题,确保仓库容量不会超出限制且不会出现负数。

在看Condition之前,我们先来看下面这个例子:

工厂类,用来存放、取出商品:

[java]  view plain  copy
 print ?
  1. public class Depot {  
  2.     private int depotSize;     //仓库大小  
  3.     private Lock lock;         //独占锁  
  4.       
  5.     public Depot(){  
  6.         depotSize = 0;  
  7.         lock = new ReentrantLock();  
  8.     }  
  9.       
  10.     /** 
  11.      * 商品入库 
  12.      * @param value 
  13.      */  
  14.     public void put(int value){     //生产
  15.         try {  
  16.             lock.lock();  
  17.             depotSize += value;  
  18.             System.out.println(Thread.currentThread().getName() + " put " + value +" ----> the depotSize: " + depotSize);  
  19.         } finally{  
  20.             lock.unlock();  
  21.         }  
  22.     }  
  23.       
  24.     /** 
  25.      * 商品出库 
  26.      * @param value 
  27.      */  
  28.     public void get(int value){    //消费
  29.         try {  
  30.             lock.lock();  
  31.             depotSize -= value;  
  32.             System.out.println(Thread.currentThread().getName() + " get " + value +" ----> the depotSize: " + depotSize);  
  33.         } finally{  
  34.             lock.unlock();  
  35.         }  
  36.     }  
  37. }  

生产者,生产商品,往仓库里面添加商品:

[java]  view plain  copy
 print ?
  1. public class Producer {  
  2.     private Depot depot;  
  3.       
  4.     public Producer(Depot depot){  
  5.         this.depot = depot;  
  6.     }  
  7.       
  8.     public void produce(final int value){  
  9.         new Thread(){  
  10.             public void run(){  
  11.                 depot.put(value);  
  12.             }  
  13.         }.start();  
  14.     }  
  15. }  

消费者,消费商品,从仓库里面取出商品:

[java]  view plain  copy
 print ?
  1. public class Customer {  
  2.     private Depot depot;  
  3.       
  4.     public Customer(Depot depot){  
  5.         this.depot = depot;  
  6.     }  
  7.       
  8.     public void consume(final int value){  
  9.         new Thread(){  
  10.             public void run(){  
  11.                 depot.get(value);  
  12.             }  
  13.         }.start();  
  14.     }  
  15. }  

测试类:

[java]  view plain  copy
 print ?
  1. public class Test {  
  2.     public static void main(String[] args) {  
  3.         Depot depot = new Depot();  
  4.           
  5.         Producer producer = new Producer(depot);  
  6.         Customer customer = new Customer(depot);  
  7.           
  8.         producer.produce(10);  
  9.         customer.consume(5);  
  10.         producer.produce(20);  
  11.         producer.produce(5);  
  12.         customer.consume(35);  
  13.     }  
  14. }  

运行结果:

[java]  view plain  copy
 print ?
  1. Thread-0 put 10 ----> the depotSize: 10  
  2. Thread-1 get 5 ----> the depotSize: 5  
  3. Thread-2 put 20 ----> the depotSize: 25  
  4. Thread-3 put 5 ----> the depotSize: 30  
  5. Thread-4 get 35 ----> the depotSize: -5  

程序的运行结果是没有错误的,先put10、然后get5、put20、put5、get35。程序运行结果非常正确,但是在现实生活中,这个实例存在两处错误:

第一:仓库的容量是有限的,我们不可能无限制的往仓库里面添加商品。

第二:仓库的容量是不可能为负数的,但是最后的结果为-5,与现实存在冲突。

针对于上面两处错误,怎么解决?这就轮到Condition大显神通了。

Condition

通过前面几篇博客我们知道Lock提供了比synchronized更加强大、灵活的锁机制,它从某种程度上来说替代了synchronized方式的使用。Condition从字面上面理解就是条件。对于线程而言它为线程提供了一个含义,以便在某种状态(条件Condition)可能为true的另一个线程通知它之前,一直挂起该线程。

对于Condition,JDK API中是这样解释的:

Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

条件(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式 释放相关的锁,并挂起当前线程,就像 Object.wait 做的那样。

Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其newCondition() 方法。下面我们通过Condition来解决上面的问题:这里只改仓库Depot的代码:

[html]  view plain  copy
 print ?
  1. public class Depot {  
  2.     private int depotSize;     //仓库大小  
  3.     private Lock lock;         //独占锁      
  4.     private int capaity;       //仓库容量  
  5.       
  6.     private Condition fullCondition;          
  7.     private Condition emptyCondition;  
  8.       
  9.     public Depot(){  
  10.         this.depotSize = 0;  
  11.         this.lock = new ReentrantLock();  
  12.         this.capaity = 15;  
  13.         this.fullCondition = lock.newCondition();  
  14.         this.emptyCondition = lock.newCondition();  
  15.     }  
  16.       
  17.     /**  
  18.      * 商品入库  
  19.      * @param value  
  20.      */  
  21.     public void put(int value){  
  22.         lock.lock();  
  23.         try {  
  24.             int left = value;  
  25.             while(left > 0){  
  26.                 //库存已满时,“生产者”等待“消费者”消费  
  27.                 while(depotSize >= capaity){  
  28.                     fullCondition.await();  //满了,即是可以放(能够生产)这个条件不满足
  29.                 }  
  30.                 //获取实际入库数量:预计库存(仓库现有库存 + 生产数量) > 仓库容量   ? 仓库容量 - 仓库现有库存     :    生产数量  
  31.                 //                  depotSize   left   capaity  capaity - depotSize     left  
  32.                 int inc = depotSize + left > capaity ? capaity - depotSize : left;   
  33.                 depotSize += inc;  //目前能够生产的商品
  34.                 left -inc;  
  35.                 System.out.println(Thread.currentThread().getName() + "----要入库数量: " + value +";;实际入库数量:" + inc + ";;仓库货物数量:" + depotSize + ";;没有入库数量:" + left);  
  36.               
  37.                 //通知消费者可以消费了  
  38.                 emptyCondition.signal();  //可以取(消费)这个条件满足了
  39.             }  
  40.         } catch (InterruptedException e) {  
  41.         } finally{  
  42.             lock.unlock();  
  43.         }  
  44.     }  
  45.       
  46.     /**  
  47.      * 商品出库  
  48.      * @param value  
  49.      */  
  50.     public void get(int value){  
  51.         lock.lock();  
  52.         try {  
  53.             int left = value;  
  54.             while(left > 0){  
  55.                 //仓库已空,“消费者”等待“生产者”生产货物  
  56.                 while(depotSize <= 0){  
  57.                     emptyCondition.await();    //是空的,即是能够拿这个条件不满足
  58.                 }  
  59.                 //实际消费      仓库库存数量     < 要消费的数量     ?   仓库库存数量     : 要消费的数量  
  60.                 int dec = depotSize < left ? depotSize : left;  
  61.                 depotSize -dec;  
  62.                 left -dec;  
  63.                 System.out.println(Thread.currentThread().getName() + "----要消费的数量:" + value +";;实际消费的数量: " + dec + ";;仓库现存数量:" + depotSize + ";;有多少件商品没有消费:" + left);  
  64.               
  65.                 //通知生产者可以生产了  
  66.                 fullCondition.signal();  //能够存放这个条件满足了
  67.             }  
  68.         } catch (InterruptedException e) {  
  69.             e.printStackTrace();  
  70.         } finally{  
  71.             lock.unlock();  
  72.         }  
  73.     }  
  74. }  

test:

[java]  view plain  copy
 print ?
  1. public class Test {  
  2.     public static void main(String[] args) {  
  3.         Depot depot = new Depot();  
  4.           
  5.         Producer producer = new Producer(depot);  
  6.         Customer customer = new Customer(depot);  
  7.           
  8.         producer.produce(10);  
  9.         customer.consume(5);  
  10.         producer.produce(15);  
  11.         customer.consume(10);  
  12.         customer.consume(15);  
  13.         producer.produce(10);  
  14.     }  
  15. }  

运行结果:

[java]  view plain  copy
 print ?
  1. Thread-0----要入库数量: 10;;实际入库数量:10;;仓库货物数量:10;;没有入库数量:0  
  2. Thread-1----要消费的数量:5;;实际消费的数量: 5;;仓库现存数量:5;;有多少件商品没有消费:0  
  3. Thread-4----要消费的数量:15;;实际消费的数量: 5;;仓库现存数量:0;;有多少件商品没有消费:10  
  4. Thread-2----要入库数量: 15;;实际入库数量:15;;仓库货物数量:15;;没有入库数量:0  
  5. Thread-4----要消费的数量:15;;实际消费的数量: 10;;仓库现存数量:5;;有多少件商品没有消费:0  
  6. Thread-5----要入库数量: 10;;实际入库数量:10;;仓库货物数量:15;;没有入库数量:0  
  7. Thread-3----要消费的数量:10;;实际消费的数量: 10;;仓库现存数量:5;;有多少件商品没有消费:0  

在Condition中,用await()替换wait(),用signal()替换 notify(),用signalAll()替换notifyAll(),对于我们以前使用传统的Object方法,Condition都能够给予实现

"C:\Program Files\Java\jdk-17\bin\java.exe" -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-Dmanagement.endpoints.jmx.exposure.include=*" "-javaagent:D:\JAVA\IDEA\IntelliJ IDEA 2024.2.3\lib\idea_rt.jar=52537:D:\JAVA\IDEA\IntelliJ IDEA 2024.2.3\bin" -Dfile.encoding=UTF-8 -classpath D:\JAVA\IDEA\farness-driving-2025\service-reservation\target\classes;D:\JAVA\IDEA\farness-driving-2025\service-common-api\target\classes;D:\repo\io\jsonwebtoken\jjwt-api\0.12.6\jjwt-api-0.12.6.jar;D:\repo\io\jsonwebtoken\jjwt-impl\0.12.6\jjwt-impl-0.12.6.jar;D:\repo\io\jsonwebtoken\jjwt-jackson\0.12.6\jjwt-jackson-0.12.6.jar;D:\repo\com\fasterxml\jackson\core\jackson-databind\2.15.4\jackson-databind-2.15.4.jar;D:\repo\com\fasterxml\jackson\core\jackson-annotations\2.15.4\jackson-annotations-2.15.4.jar;D:\repo\com\fasterxml\jackson\core\jackson-core\2.15.4\jackson-core-2.15.4.jar;D:\repo\com\alibaba\druid-spring-boot-3-starter\1.2.20\druid-spring-boot-3-starter-1.2.20.jar;D:\repo\com\alibaba\druid\1.2.20\druid-1.2.20.jar;D:\repo\org\slf4j\slf4j-api\2.0.13\slf4j-api-2.0.13.jar;D:\repo\org\springframework\boot\spring-boot-autoconfigure\3.2.8\spring-boot-autoconfigure-3.2.8.jar;D:\repo\com\baomidou\mybatis-plus-boot-starter\3.5.7\mybatis-plus-boot-starter-3.5.7.jar;D:\repo\com\baomidou\mybatis-plus\3.5.7\mybatis-plus-3.5.7.jar;D:\repo\com\baomidou\mybatis-plus-core\3.5.7\mybatis-plus-core-3.5.7.jar;D:\repo\com\baomidou\mybatis-plus-annotation\3.5.7\mybatis-plus-annotation-3.5.7.jar;D:\repo\com\baomidou\mybatis-plus-extension\3.5.7\mybatis-plus-extension-3.5.7.jar;D:\repo\org\mybatis\mybatis\3.5.16\mybatis-3.5.16.jar;D:\repo\com\github\jsqlparser\jsqlparser\4.9\jsqlparser-4.9.jar;D:\repo\org\mybatis\mybatis-spring\2.1.2\mybatis-spring-2.1.2.jar;D:\repo\com\baomidou\mybatis-plus-spring-boot-autoconfigure\3.5.7\mybatis-plus-spring-boot-autoconfigure-3.5.7.jar;D:\repo\org\springframework\boot\spring-boot-starter-jdbc\3.2.8\spring-boot-starter-jdbc-3.2.8.jar;D:\repo\com\zaxxer\HikariCP\5.0.1\HikariCP-5.0.1.jar;D:\repo\org\springframework\spring-jdbc\6.1.11\spring-jdbc-6.1.11.jar;D:\repo\com\alibaba\fastjson2\fastjson2\2.0.43\fastjson2-2.0.43.jar;D:\repo\org\springdoc\springdoc-openapi-starter-webmvc-ui\2.2.0\springdoc-openapi-starter-webmvc-ui-2.2.0.jar;D:\repo\org\springdoc\springdoc-openapi-starter-webmvc-api\2.2.0\springdoc-openapi-starter-webmvc-api-2.2.0.jar;D:\repo\org\springdoc\springdoc-openapi-starter-common\2.2.0\springdoc-openapi-starter-common-2.2.0.jar;D:\repo\io\swagger\core\v3\swagger-core-jakarta\2.2.15\swagger-core-jakarta-2.2.15.jar;D:\repo\org\apache\commons\commons-lang3\3.13.0\commons-lang3-3.13.0.jar;D:\repo\io\swagger\core\v3\swagger-annotations-jakarta\2.2.15\swagger-annotations-jakarta-2.2.15.jar;D:\repo\io\swagger\core\v3\swagger-models-jakarta\2.2.15\swagger-models-jakarta-2.2.15.jar;D:\repo\jakarta\validation\jakarta.validation-api\3.0.2\jakarta.validation-api-3.0.2.jar;D:\repo\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.15.4\jackson-dataformat-yaml-2.15.4.jar;D:\repo\org\webjars\swagger-ui\5.2.0\swagger-ui-5.2.0.jar;D:\repo\cn\hutool\hutool-all\5.8.22\hutool-all-5.8.22.jar;D:\repo\org\springframework\boot\spring-boot-starter\3.2.8\spring-boot-starter-3.2.8.jar;D:\repo\org\springframework\boot\spring-boot\3.2.8\spring-boot-3.2.8.jar;D:\repo\org\springframework\spring-context\6.1.11\spring-context-6.1.11.jar;D:\repo\org\springframework\boot\spring-boot-starter-logging\3.2.8\spring-boot-starter-logging-3.2.8.jar;D:\repo\ch\qos\logback\logback-classic\1.4.14\logback-classic-1.4.14.jar;D:\repo\ch\qos\logback\logback-core\1.4.14\logback-core-1.4.14.jar;D:\repo\org\apache\logging\log4j\log4j-to-slf4j\2.21.1\log4j-to-slf4j-2.21.1.jar;D:\repo\org\apache\logging\log4j\log4j-api\2.21.1\log4j-api-2.21.1.jar;D:\repo\org\slf4j\jul-to-slf4j\2.0.13\jul-to-slf4j-2.0.13.jar;D:\repo\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar;D:\repo\org\springframework\spring-core\6.1.11\spring-core-6.1.11.jar;D:\repo\org\springframework\spring-jcl\6.1.11\spring-jcl-6.1.11.jar;D:\repo\org\yaml\snakeyaml\2.2\snakeyaml-2.2.jar;D:\repo\jakarta\xml\bind\jakarta.xml.bind-api\4.0.2\jakarta.xml.bind-api-4.0.2.jar;D:\repo\jakarta\activation\jakarta.activation-api\2.1.3\jakarta.activation-api-2.1.3.jar;D:\repo\org\projectlombok\lombok\1.18.34\lombok-1.18.34.jar;D:\repo\org\springframework\boot\spring-boot-starter-web\3.2.8\spring-boot-starter-web-3.2.8.jar;D:\repo\org\springframework\boot\spring-boot-starter-json\3.2.8\spring-boot-starter-json-3.2.8.jar;D:\repo\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.15.4\jackson-datatype-jdk8-2.15.4.jar;D:\repo\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.15.4\jackson-datatype-jsr310-2.15.4.jar;D:\repo\com\fasterxml\jackson\module\jackson-module-parameter-names\2.15.4\jackson-module-parameter-names-2.15.4.jar;D:\repo\org\springframework\boot\spring-boot-starter-tomcat\3.2.8\spring-boot-starter-tomcat-3.2.8.jar;D:\repo\org\apache\tomcat\embed\tomcat-embed-core\10.1.26\tomcat-embed-core-10.1.26.jar;D:\repo\org\apache\tomcat\embed\tomcat-embed-el\10.1.26\tomcat-embed-el-10.1.26.jar;D:\repo\org\apache\tomcat\embed\tomcat-embed-websocket\10.1.26\tomcat-embed-websocket-10.1.26.jar;D:\repo\org\springframework\spring-web\6.1.11\spring-web-6.1.11.jar;D:\repo\org\springframework\spring-beans\6.1.11\spring-beans-6.1.11.jar;D:\repo\io\micrometer\micrometer-observation\1.12.8\micrometer-observation-1.12.8.jar;D:\repo\io\micrometer\micrometer-commons\1.12.8\micrometer-commons-1.12.8.jar;D:\repo\org\springframework\spring-webmvc\6.1.11\spring-webmvc-6.1.11.jar;D:\repo\org\springframework\spring-aop\6.1.11\spring-aop-6.1.11.jar;D:\repo\org\springframework\spring-expression\6.1.11\spring-expression-6.1.11.jar;D:\repo\org\springframework\boot\spring-boot-starter-data-redis\3.2.8\spring-boot-starter-data-redis-3.2.8.jar;D:\repo\io\lettuce\lettuce-core\6.3.2.RELEASE\lettuce-core-6.3.2.RELEASE.jar;D:\repo\io\netty\netty-common\4.1.111.Final\netty-common-4.1.111.Final.jar;D:\repo\io\netty\netty-handler\4.1.111.Final\netty-handler-4.1.111.Final.jar;D:\repo\io\netty\netty-resolver\4.1.111.Final\netty-resolver-4.1.111.Final.jar;D:\repo\io\netty\netty-buffer\4.1.111.Final\netty-buffer-4.1.111.Final.jar;D:\repo\io\netty\netty-transport-native-unix-common\4.1.111.Final\netty-transport-native-unix-common-4.1.111.Final.jar;D:\repo\io\netty\netty-codec\4.1.111.Final\netty-codec-4.1.111.Final.jar;D:\repo\io\netty\netty-transport\4.1.111.Final\netty-transport-4.1.111.Final.jar;D:\repo\io\projectreactor\reactor-core\3.6.8\reactor-core-3.6.8.jar;D:\repo\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;D:\repo\org\springframework\data\spring-data-redis\3.2.8\spring-data-redis-3.2.8.jar;D:\repo\org\springframework\data\spring-data-keyvalue\3.2.8\spring-data-keyvalue-3.2.8.jar;D:\repo\org\springframework\data\spring-data-commons\3.2.8\spring-data-commons-3.2.8.jar;D:\repo\org\springframework\spring-tx\6.1.11\spring-tx-6.1.11.jar;D:\repo\org\springframework\spring-oxm\6.1.11\spring-oxm-6.1.11.jar;D:\repo\org\springframework\spring-context-support\6.1.11\spring-context-support-6.1.11.jar;D:\repo\com\mysql\mysql-connector-j\8.3.0\mysql-connector-j-8.3.0.jar;D:\repo\org\springframework\boot\spring-boot-starter-websocket\3.2.8\spring-boot-starter-websocket-3.2.8.jar;D:\repo\org\springframework\spring-messaging\6.1.11\spring-messaging-6.1.11.jar;D:\repo\org\springframework\spring-websocket\6.1.11\spring-websocket-6.1.11.jar com.hulmos.servicereservation.ServiceReservationApplication . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.2.8) 2025-10-11T09:08:33.502+08:00 INFO 35244 --- [service-reservation] [ main] c.h.s.ServiceReservationApplication : Starting ServiceReservationApplication using Java 17.0.12 with PID 35244 (D:\JAVA\IDEA\farness-driving-2025\service-reservation\target\classes started by hh150 in D:\JAVA\IDEA\farness-driving-2025) 2025-10-11T09:08:33.504+08:00 INFO 35244 --- [service-reservation] [ main] c.h.s.ServiceReservationApplication : No active profile set, falling back to 1 default profile: "default" 2025-10-11T09:08:34.044+08:00 INFO 35244 --- [service-reservation] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode 2025-10-11T09:08:34.046+08:00 INFO 35244 --- [service-reservation] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode. 2025-10-11T09:08:34.065+08:00 INFO 35244 --- [service-reservation] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 8 ms. Found 0 Redis repository interfaces. 2025-10-11T09:08:34.220+08:00 WARN 35244 --- [service-reservation] [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'announcementMapper' defined in file [D:\JAVA\IDEA\farness-driving-2025\service-reservation\target\classes\com\hulmos\servicereservation\mapper\AnnouncementMapper.class]: Invalid value type for attribute 'factoryBeanObjectType': java.lang.String 2025-10-11T09:08:34.227+08:00 INFO 35244 --- [service-reservation] [ main] .s.b.a.l.ConditionEvaluationReportLogger : Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. 2025-10-11T09:08:34.243+08:00 ERROR 35244 --- [service-reservation] [ main] o.s.boot.SpringApplication : Application run failed org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'announcementMapper' defined in file [D:\JAVA\IDEA\farness-driving-2025\service-reservation\target\classes\com\hulmos\servicereservation\mapper\AnnouncementMapper.class]: Invalid value type for attribute 'factoryBeanObjectType': java.lang.String at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryBean(AbstractAutowireCapableBeanFactory.java:857) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.AbstractBeanFactory.getType(AbstractBeanFactory.java:743) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAnnotationOnBean(DefaultListableBeanFactory.java:735) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.boot.sql.init.dependency.AnnotationDependsOnDatabaseInitializationDetector.detect(AnnotationDependsOnDatabaseInitializationDetector.java:36) ~[spring-boot-3.2.8.jar:3.2.8] at org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer$DependsOnDatabaseInitializationPostProcessor.detectDependsOnInitializationBeanNames(DatabaseInitializationDependencyConfigurer.java:152) ~[spring-boot-3.2.8.jar:3.2.8] at org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer$DependsOnDatabaseInitializationPostProcessor.postProcessBeanFactory(DatabaseInitializationDependencyConfigurer.java:115) ~[spring-boot-3.2.8.jar:3.2.8] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:363) ~[spring-context-6.1.11.jar:6.1.11] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:197) ~[spring-context-6.1.11.jar:6.1.11] at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:789) ~[spring-context-6.1.11.jar:6.1.11] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:607) ~[spring-context-6.1.11.jar:6.1.11] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.2.8.jar:3.2.8] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.2.8.jar:3.2.8] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.2.8.jar:3.2.8] at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.2.8.jar:3.2.8] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.2.8.jar:3.2.8] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.2.8.jar:3.2.8] at com.hulmos.servicereservation.ServiceReservationApplication.main(ServiceReservationApplication.java:14) ~[classes/:na]
最新发布
10-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值