Springboot相关问题

静态资源相关

静态资源目录

其中默认配置的 /** 映射到 /static (或/public、/resources、/META-INF/resources)

其中默认配置的 /webjars/** 映射到 classpath:/META-INF/resources/webjars/

PS:上面的 static、public、resources 等目录都在 classpath: 下面(如 src/main/resources/static)。

优先级顺序为:META/resources > resources > static > public

JPA相关

JPA相关问题

SpringBoot2.0 (Spring-Data-Jpa) findById(findOne())和Optional的使用

1、findOne()方法的替代方法findById()

2.0版本,Spring-Data-Jpa修改findOne()。

  • 1)2.0版本之前
T findOne(ID primaryKey);
  • 2)2.0版本
  Optional<T> findById(ID id);

2、Optional Optional的使用

文档:Optional

container对象,可能包含也可能不包含非null值。如果存在值,则isPresent()将返回true,get()将返回该值。提供依赖于是否存在包含值的其他方法,例如orElse()(如果值不存在则返回默认值)和ifPresent()(如果值存在则执行代码块)。

Optional<T> findById(ID id)

中Optional的一些用法:

  • 1)如果没找到指定实体,则返回一个默认值。
Foo foo = repository.findById(id).orElse(new Foo());

或者

Foo foo = repository.findById(id).orElse(null);

  • 2)如果找到实体返回它,否则抛出异常
return repository.findById(id)
        .orElseThrow(() -> new EntityNotFoundException(id));
  • 3)假设希望根据是否找到实体来应用不同的处理(无需抛出异常)
Optional<Foo> fooOptional = fooRepository.findById(id);
if (fooOptional.isPresent()){
    Foo foo = fooOptional.get();
   // 处理 foo ...
}
else{
   //另一种情况....
}

Spring-Data-Jpa的Sort排序时遇到的问题 has private access in ‘org.springframework.data.domain.Sort’

springboot2.2.1(含)以上的版本Sort已经不能再实例化了,构造方法已经私有

image.png

image.png

改用Sort.by获得Sort对象

image.png

@GetMapping("/test2")
    public String find3() {
        List<Book> book = bookDao.findAll(Sort.by(Sort.Direction.DESC, "bookId"));
        for (Book book1 : book) {
            System.out.println(book1);
        }
        return "success";
    }

Sort.by()可以一个或多个字段排序

bean 相关

idea-使用@Autowired注解警告Field injection is not recommended

参考文章

在使用spring框架中的依赖注入注解@Autowired时,idea报了一个警告

被警告的代码如下:

    @Autowired
    UserDao userDao;

“`警告内容是“`

Field injection is not recommended

意思就是使用变量依赖注入的方式是不被推荐的。
使用idea解决策略是这样的:

Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies
意思就是总是使用构造器的方式强制注入。

依赖注入有三种方式:

  • 变量(filed)注入
  • 构造器注入
  • set方法注入

“`先各自看一下实现方式“`

  • 变量(filed)注入
    @Autowired
    UserDao userDao;
  • 构造器注入
    final
    UserDao userDao;

    @Autowired
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }
  • set方法注入
    private UserDao userDao;

    @Autowired
    public void setUserDao (UserDao userDao) {
        this.userDao = userDao;
    }

相比较而言:

优点:变量方式注入非常简洁,没有任何多余代码,非常有效的提高了java的简洁性。即使再多几个依赖一样能解决掉这个问题。

缺点:不能有效的指明依赖。相信很多人都遇见过一个bug,依赖注入的对象为null,在启动依赖容器时遇到这个问题都是配置的依赖注入少了一个注解什么的,然而这种方式就过于依赖注入容器了,当没有启动整个依赖容器时,这个类就不能运转,在反射时无法提供这个类需要的依赖。
在使用set方式时,这是一种选择注入,可有可无,即使没有注入这个依赖,那么也不会影响整个类的运行。
在使用构造器方式时已经显式注明必须强制注入。通过强制指明依赖注入来保证这个类的运行。

另一个方面:
依赖注入的核心思想之一就是被容器管理的类不应该依赖被容器管理的依赖,换成白话来说就是如果这个类使用了依赖注入的类,那么这个类摆脱了这几个依赖必须也能正常运行。然而使用变量注入的方式是不能保证这点的。
既然使用了依赖注入方式,那么就表明这个类不再对这些依赖负责,这些都由容器管理,那么如何清楚的知道这个类需要哪些依赖呢?它就要使用set方法方式注入或者构造器注入。

总结下:
变量方式注入应该尽量避免,使用set方式注入或者构造器注入,这两种方式的选择就要看这个类是强制依赖的话就用构造器方式,选择依赖的话就用set方法注入。

Spring Bean的循环依赖

参考文章

如果使用构造函数注入,则可能会创建一个无法解析的循环依赖场景。

什么是循环依赖

下面是引文作者所遇到的情况,

代码结构如下:

  • SpringSecurity 配置类:
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
    private final UserDetailsService userDetailsService;

    /**
     * 通过配置类构造函数注入 UserDetailsService
     */
    @Autowired
    public BrowserSecurityConfig(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    /**
     * 在配置类中声明 加密编码器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    ... ...
}

  • UserDetailsService 类:
@Component
public class MyUserDetailService implements UserDetailsService {
    private final PasswordEncoder passwordEncoder;

    private Logger logger = LoggerFactory.getLogger(getClass());

   /**
     * 通过构造函数注入 PasswordEncoder
     */
    @Autowired
    public MyUserDetailService(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }
    ... ...
}
  • 运行之后,Spring抛出了如下错误信息:
Description:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  browserSecurityConfig defined in file [D:\CODE\Java\IdeaProjects\mango-security\mango-security-browser\target\classes\stu\mango\security\browser\BrowserSecurityConfig.class]
↑     ↓
|  myUserDetailService defined in file [D:\CODE\Java\IdeaProjects\mango-security\mango-security-browser\target\classes\stu\mango\security\browser\MyUserDetailService.class]
└─────┘

该例中,BrowserSecurityConfig 通过构造函数注入 UserDetailsService实例,而 UserDetailsService由通过构造函数注入在BrowserSecurityConfig 中声明的PasswordEncoder

总结来说,Spring Bean的循环依赖是指,类A需要通过构造函数注入的类B的实例(或者B中声明的Bean),而类B需要通过构造函数注入的类A的实例(或者A中声明的Bean)。如果将类A和类B的bean配置为相互注入,则Spring IoC容器会在运行时检测到此循环引用,并引发一个BeanCurrentlyInCreationException。与典型情况(没有循环依赖)不同,bean A和bean B之间的循环依赖关系迫使其中一个bean在被完全初始化之前被注入到另一个bean中(这是一个典型的“先有鸡还是先有蛋”场景)。

image.png

解决方案

简明扼要的说,就是——不使用基于构造函数的依赖注入。可通过下面方式解决。

在字段上使用@Autowired注解,让Spring决定在合适的时机注入。【推荐】
基于setter方法的依赖注射取代基于构造函数的依赖注入来解决循环依赖。

分类: 服务器网络

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注