Spring和JDK 8:您还在Spring MVC注释中使用@Param和名称/值吗? 那这篇文章是给你的


您好,读者!


在Spring Boot 2上开发培训项目时,我决定在Spring Data JPA查询中使用@Param进行试验,或者说, 在缺少它们的情况下


 @Transactional(readOnly = true) public interface UserRepository extends JpaRepository<User, Integer> { @Query("SELECT u FROM User u WHERE LOWER(u.email) = LOWER(:email)") Optional<User> findByEmailIgnoreCase(@Param("email") String email); List<User> findByLastNameContainingIgnoreCase(@Param("lastname") String lastName); } 

(关于魔术,第二种方法是如何工作的,请参见旧出版物“ Spring Pet Clinic的足迹” )。


@Param删除@Param可以确保没有它们,Spring可以正常工作 。 我听说过编译中的一个参数,该参数使您不能在批注中重复名称,但是我没有做任何特别的事情,因此我决定 深入挖掘 达成协议。


如果您仍然使用文章标题(Spring Boot和JDK 8)中的注释,则要求cat:


更新:仍然经常需要@PathVariable@RequestParam才能使应用程序正常工作。 但是不再需要它们的value/name属性:匹配由变量名查找。


  • 我尝试的第一件事是更改参数的名称( mail而不是email ):


     @Query("SELECT u FROM User u WHERE LOWER(u.email) = LOWER(:email)") Optional<User> findByEmailIgnoreCase(String mail); 

    我得到了接待处和断点的地方:


     Caused by: java.lang.IllegalStateException: Using named parameters for method public abstract java.util.Optional ru.javaops.bootjava.restaurantvoting.repository.UserRepository.findByEmailIgnoreCase(java.lang.String) but parameter 'Optional[mail]' not found in annotated query 'SELECT u FROM User u WHERE LOWER(u.email) = LOWER(:email)'! at org.springframework.data.jpa.repository.query.JpaQueryMethod.assertParameterNamesInAnnotatedQuery(JpaQueryMethod.java:125) ~[spring-data-jpa-2.1.3.RELEASE.jar:2.1.3.RELEASE] 

  • 接下来,我们找到确定方法参数名称的位置:




可以看出,使用了两种策略: StandardReflectionParameterNameDiscovererLocalVariableTableParameterNameDiscoverer 。 第一种使用JDK8 JEP 118:在运行时访问参数名称 。 根据SPR-9643 ,如果无法根据第一种策略确定参数名称,则Spring尝试使用“基于ASM的调试符号分析”。


  • Internet上有关Java 8参数名称的信息很多, -parameters使用-parameters标志进行编译。 我转到IDEA项目的Spring Boot设置:


是的,它确实包含在内...但是,如果我通过Maven构建和运行该项目怎么办?
结果是一样的!


  • 我在Maven设置中打开调试输出,编译项目并查看:


     [DEBUG] Goal: org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) ... <parameters default-value="false">true</parameters> 

    看来maven-compiler-plugin已在spring-boot-starter-parent配置,通过SPRING INITIALIZR生成时,默认情况下将从那里继承spring-boot项目。 我们去那里( 仅针对Spring Boot 2 ),请确保在此处配置了插件:


      <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <parameters>true</parameters> </configuration> </plugin> 

  • 最后,我们可以在项目中重新定义maven-compiler-plugin配置,在此我们将该标志设置为false 。 检查-项目已启动。 当尝试拉出方法时,我们得到:


     Unable to detect parameter names for query method ru.javaops.bootjava.restaurantvoting.repository.UserRepository.findByEmailIgnoreCase! Use @Param or compile with -parameters on JDK 8. 


这意味着:


  1. 我们的推理是真的
  2. 根据第二种ASM策略,我无法获取信息(尽管我是从Debug开始的)

结果:默认情况下,Spring Boot 2中的-parameters标志处于启用状态,因此,如果您从spring-boot-starter-parent继承,则参数名称在@Param中定义,不再需要@PathVariable @Param@RequestParam @Param@RequestParam @PathVariable 。 更少的代码,更少的错误。


对于Spring Boot 1.x,可以强制启用编译标志,请参见上文。


PS:我使用JDK 8,JDK 11和Spring Boot 2.1.1进行研究


更新2:有趣的是,对于@RequestParam@PathVariable第二个基于ASM从字节码接收的信息来工作第二个LocalVariableTableParameterNameDiscoverer策略。 包括用于常规Spring(无Boot)且没有编译选项的。


感谢您的关注!

Source: https://habr.com/ru/post/zh-CN440214/


All Articles