SpringBoot项目开发中常用的一些技巧总结

2024年 1月 30日 85.3k 0

环境:SpringBoot2.7.16

1. Bean初始化及销毁

如你希望Bean对象被创建过程中执行以下初始化动作,你可以通过实现InitializingBean接口或者使用@PostConstruct注解。

@Component
public class InitDataToRedis implements InitializingBean {
  public void afterPropertiesSet() throws Exception {
    // 初始化
  }
}


@Component
public class PersonService {
  @PostConstruct
  public void init() {
    // 初始化
  }
}

如希望在容器关闭时执行资源释放或者其它一些动作可以实现DisposableBean接口或者使用@PreDestroy注解。

public class Person implements DisposableBean {
  public void destroy() {
    // 销毁动作
  }
}
@Component
public class PersonService {
  @PreDestroy
  public void destroy() {
    // 销毁
  }
}

2. 单例Bean注入多例Bean

// 多例Bean
@Component
@Scope("prototype")
public class PersonService {
}
// 默认单例Bean
@Controller
public class PersonController {}

如上如何在PersonController中注入PersonService呢?通过如下方法

方法1:

@Lazy
private PersonService personService ;

方法2:

@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PersonService {}

方法3:

public class PersonController {
  @Resource
  private ApplicationContext context ;
  
  public Object index() {
    PersonService ps = this.context.getBean(PersonService.class) ;
  }
}

3. BeanPostProcessor接口

如需要Bean在初始化前后执行相关的动作,可以通过实现该接口。

public class PackBeanPostProcessor implements BeanPostProcessor {
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // 初始化前执行
  }
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    // 初始化后执行
  }
}

4. BeanFactoryPostProcessor接口

如你希望在创建Bean对象之前修改BeanDefinition的相关属性可以通过实现该接口

public PackBeanFactoryPostProcessor implements BeanFactoryPostProcessor {


  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    BeanDefinition definition = beanFactory.getBeanDefinition("person") ;
    // 修改了作用域
    definition.setScope("prototype") ;
  }  
}

5. 动态注册Bean

如需要根据添加动态注册Bean,比如通过扫描包下的类符合条件的类注册为Bean对象,则可以通过如下的方式。

public class RepositoryBeanDefinitionRegister implements BeanDefinitionRegistryPostProcessor {
  @Override
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    // 动态注册person
    registry.registerBeanDefinition("person", BeanDefinitionBuilder.genericBeanDefinition(Person.class).getBeanDefinition());
  }
}

6.导入配置类

详细查看《想成为Spring专家?了解@Import注解的三种用法是必备的!》

7. *Runner接口

如需要在应用程序成功启动以后,执行一些任务,可以通过实现ApplicationRunner或者CommandLineRunner接口。

public class App implements CommandLineRunner {
  public void run(String... args) throws Exception {
    // 执行任务
  }
}
// 或
public class App implements ApplicationRunner {
  public void run(ApplicationArguments args) throws Exception {
    // 执行任务
  }
}

8. 全局异常处理

当应用发生异常时可以通过注册全局异常处理,统一处理异常信息

@RestControllerAdvice
public class GlobalControllerAdvice {


  @ExceptionHandler({Exception.class})
  public Object handle(Exception e) {
    // 其它处理
    return R.failure(R.ResultCode.FAILURE, e.getMessage()) ;
  }
  
}

10 全局类型转换

自定义类型转换

public class CustomGenericConverter implements GenericConverter {


  @Override
  public Set getConvertibleTypes() {
    ConvertiblePair teacherPair = new ConvertiblePair(String.class, Teacher.class) ;
    ConvertiblePair studentPair = new ConvertiblePair(String.class, Student.class) ;
    Set pairs = new HashSet() ;
    pairs.add(teacherPair) ;
    pairs.add(studentPair) ;
    return pairs ;
  }


  @Override
  public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
    String str = null ;
    if (sourceType.getObjectType() == String.class) {
      str = (String) source ; 
    }
    if (targetType.getObjectType() == Teacher.class) {
      String[] t = str.split("\\|") ;
      return new Teacher(t[0], Integer.valueOf(t[1])) ;
    }
    if (targetType.getObjectType() == Student.class) {
      String[] t = str.split("\\|") ;
      return new Student(t[0], t[1]) ;
    }
    return null ;
  }


}

注册类型转换器

@Component
public class WebConfig implements WebMvcConfigurer {


  @Override
  public void addFormatters(FormatterRegistry registry) {
    registry.addConverter(new CustomGenericConverter()) ;
  }
  
}

以上示例注册了一个,将字符串转换为Teacher和Student。

11. 获取BeanFactory对象

如果你希望在Bean中获取BeanFactory,可以通过实现BeanFactoryAware接口

@Service
public class PersonService implements BeanFactoryAware {
  private BeanFactory beanFactory;


  @Override
  public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
      this.beanFactory = beanFactory;
  }
}

相关的*Aware接口,还有很多,如:ApplicationContextAware,ServletContextAware,BeanNameAware,EnvironmentAware等。

12. Web拦截器

如你需要对某些接口进行鉴权或者其它一些处理,你可以注册自定义拦截器

@Component
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
      registry.addInterceptor(new HandlerInterceptor() {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
          System.out.println("preHandle method invoke...") ;
          return true;
        }
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
          System.out.println("postHandle method invoke...") ;
        }
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) throws Exception {
          System.out.println("afterCompletion method invoke...") ;
        }
      }).addPathPatterns("/**") ;
    }
  }
}

13. 默认AOP切面实现

BeanNameAutoProxyCreator

@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
  BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
  beanNameAutoProxyCreator.setBeanNames("*Service") ;
  beanNameAutoProxyCreator.setInterceptorNames("tokenInterceptor");
  return beanNameAutoProxyCreator ;
}

上面的BeanNameAutoProxyCreator 是处理器类,只要beanName的后缀是Service结尾的都会被创建代理,然后通过以tokenInterceptor为beanName的拦截器增强。

以上是在SpringBoot项目开发中常用的一些技巧,希望本文对你有帮助。

完毕!!!

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论