Spring让人眼前一亮的11个小技巧( 二 )


答案是否定的,这时全局异常处理就派上用场了:RestControllerAdvice
@RestControllerAdvicepublic class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public String handleException(Exception e) {if (e instanceof ArithmeticException) {return "数据异常";}if (e instanceof Exception) {return "服务器内部异常";}retur nnull;}}只需在handleException方法中处理异常情况,业务接口中可以放心使用,不再需要捕获异常(有人统一处理了) 。真是爽歪歪 。
4.类型转换器spring目前支持3中类型转换器:

  • Converter<S,T>:将 S 类型对象转为 T 类型对象
  • ConverterFactory<S, R>:将 S 类型对象转为 R 类型及子类对象
  • GenericConverter:它支持多个source和目标类型的转化,同时还提供了source和目标类型的上下文,这个上下文能让你实现基于属性上的注解或信息来进行类型转换 。
这3种类型转换器使用的场景不一样,我们以Converter<S,T>为例 。假如:接口中接收参数的实体对象中,有个字段的类型是Date,但是实际传参的是字符串类型:2021-01-03 10:20:15 , 要如何处理呢?
第一步,定义一个实体User:
@Datapublic class User {private Long id;private String name;private Date registerDate;}第二步,实现Converter接口:
public class DateConverter implements Converter<String, Date> {private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");@Overridepublic Date convert(String source) {if (source != null && !"".equals(source)) {try {simpleDateFormat.parse(source);} catch (ParseException e) {e.printStackTrace();}}return null;}}第三步,将新定义的类型转换器注入到spring容器中:
@Configurationpublic class WebConfig extends WebMvcConfigurerAdapter {@Overridepublic void addFormatters(FormatterRegistry registry) {registry.addConverter(new DateConverter());}}第四步 , 调用接口
@RequestMapping("/user")@RestControllerpublic class UserController {@RequestMapping("/save")public String save(@RequestBody User user) {return "success";}}请求接口时User对象中registerDate字段会被自动转换成Date类型 。
5.导入配置有时我们需要在某个配置类中引入另外一些类,被引入的类也加到spring容器中 。这时可以使用@Import注解完成这个功能 。
如果你看过它的源码会发现,引入的类支持三种不同类型 。
但是我认为最好将普通类和@Configuration注解的配置类分开讲解 , 所以列了四种不同类型:
Spring让人眼前一亮的11个小技巧

文章插图
5.1 普通类这种引入方式是最简单的,被引入的类会被实例化bean对象 。
public class A {}@Import(A.class)@Configurationpublic class TestConfiguration {}通过@Import注解引入A类,spring就能自动实例化A对象,然后在需要使用的地方通过@Autowired注解注入即可:
@Autowiredprivate A a;是不是挺让人意外的?不用加@Bean注解也能实例化bean 。
5.2 配置类这种引入方式是最复杂的,因为@Configuration注解还支持多种组合注解,比如:
  • @Import
  • @ImportResource
  • @PropertySource等 。
public class A {}public class B {}@Import(B.class)@Configurationpublic class AConfiguration {@Beanpublic A a() {return new A();}}@Import(AConfiguration.class)@Configurationpublic class TestConfiguration {}通过@Import注解引入@Configuration注解的配置类,会把该配置类相关@Import@ImportResource@PropertySource等注解引入的类进行递归,一次性全部引入 。
5.3 ImportSelector这种引入方式需要实现ImportSelector接口:
public class AImportSelector implements ImportSelector {private static final String CLASS_NAME = "com.sue.cache.service.test13.A"; public String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{CLASS_NAME};}}@Import(AImportSelector.class)@Configurationpublic class TestConfiguration {}这种方式的好处是selectImports方法返回的是数组,意味着可以同时引入多个类,还是非常方便的 。
5.4 ImportBeanDefinitionRegistrar这种引入方式需要实现ImportBeanDefinitionRegistrar接口:
public class AImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(A.class);registry.registerBeanDefinition("a", rootBeanDefinition);}}@Import(AImportBeanDefinitionRegistrar.class)@Configurationpublic class TestConfiguration {}

推荐阅读