Spring中11个最常用的扩展点分享1

电子说

1.3w人已加入

描述

前言

在使用spring的过程中,我们有没有发现它的扩展能力很强呢?由于这个优势的存在,使得spring具有很强的包容性,所以很多第三方应用或者框架可以很容易的投入到spring的怀抱中。今天我们主要来学习Spring中很常用的11个扩展点,你用过几个呢?

1. 类型转换器

如果接口中接收参数的实体对象中,有一个字段类型为Date,但实际传递的参数是字符串类型:2022-12-15 10:20:15,该如何处理?

Spring提供了一个扩展点,类型转换器Type Converter,具体分为3类:

  • Converter: 将类型 S 的对象转换为类型 T 的对象
  • ConverterFactory: 将 S 类型对象转换为 R 类型或其子类对象
  • GenericConverter:它支持多种源和目标类型的转换,还提供了源和目标类型的上下文。此上下文允许您根据注释或属性信息执行类型转换。

还是不明白的话,我们举个例子吧。

  1. 定义一个用户对象
@Data
public class User {
    private Long id;
    private String name;
    private Date registerDate;
}
  1. 实现Converter接口
public class DateConverter implements Converter
  1. 将新定义的类型转换器注入到Spring容器中
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new DateConverter());
    }
}
  1. 调用接口测试
@RequestMapping("/user")
    @RestController
    public class UserController {
        @RequestMapping("/save")
        public String save(@RequestBody User user) {
            return "success";
        }
    }

请求接口时,前端传入的日期字符串,会自动转换成Date类型。

2. 获取容器Bean

在我们日常开发中,经常需要从Spring容器中获取bean,但是你知道如何获取Spring容器对象吗?

2.1 BeanFactoryAware

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

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

    public void add() {
        Person person = (Person) beanFactory.getBean("person");
    }
}

实现BeanFactoryAware接口,然后重写setBeanFactory方法,可以从方法中获取spring容器对象。

2.2 ApplicationContextAware

@Service
public class PersonService2 implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void add() {
        Person person = (Person) applicationContext.getBean("person");
    }
}

实现ApplicationContextAware接口,然后重写setApplicationContext方法,也可以通过该方法获取spring容器对象。

2.3 ApplicationListener

@Service
public class PersonService3 implements ApplicationListener<ContextRefreshedEvent> {
    private ApplicationContext applicationContext;
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        applicationContext = event.getApplicationContext();
    }

    public void add() {
        Person person = (Person) applicationContext.getBean("person");
    }
}

3. 全局异常处理

以往我们在开发界面的时候,如果出现异常,要给用户更友好的提示,例如:

@RequestMapping("/test")
@RestController
public class TestController {

    @GetMapping("/add")
    public String add() {
        int a = 10 / 0;
        return "su";
    }
}

如果不对请求添加接口结果做任何处理,会直接报错:

用户可以直接看到错误信息吗?

这种交互给用户带来的体验非常差。为了解决这个问题,我们通常在接口中捕获异常:

@GetMapping("/add")
public String add() {
    String result = "success";
    try {
        int a = 10 / 0;
    } catch (Exception e) {
        result = "error";
    }
    return result;
}

界面修改后,出现异常时会提示:“数据异常”,更加人性化。

看起来不错,但是有一个问题。

如果只是一个接口还好,但是如果项目中有成百上千个接口,还得加异常捕获代码吗?

答案是否定的,这就是全局异常处理派上用场的地方:RestControllerAdvice

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public String handleException(Exception e) {
        if (e instanceof ArithmeticException) {
            return "data error";
        }
        if (e instanceof Exception) {
            return "service error";
        }
        retur null;
    }
}

方法中处理异常只需要handleException,在业务接口中就可以安心使用,不再需要捕获异常(统一有人处理)。

4. 自定义拦截器

Spring MVC拦截器,它可以获得HttpServletRequestHttpServletResponse等web对象实例。

Spring MVC拦截器的顶层接口是HandlerInterceptor,它包含三个方法:

  • preHandle 在目标方法执行之前执行
  • 执行目标方法后执行的postHandle
  • afterCompletion 在请求完成时执行

为了方便,我们一般继承HandlerInterceptorAdapter,它实现了HandlerInterceptor

如果有授权鉴权、日志、统计等场景,可以使用该拦截器,我们来演示下吧。

  1. 写一个类继承HandlerInterceptorAdapter
public class AuthInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {
        String requestUrl = request.getRequestURI();
        if (checkAuth(requestUrl)) {
            return true;
        }
        return false;
    }
    private boolean checkAuth(String requestUrl) {
        return true;
    }
}
  1. 将拦截器注册到spring容器中
@Configuration
public class WebAuthConfig extends WebMvcConfigurerAdapter {

    @Bean
    public AuthInterceptor getAuthInterceptor() {
        return new AuthInterceptor();
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthInterceptor());
    }
}
  1. Spring MVC在请求接口时可以自动拦截接口,并通过拦截器验证权限。

5. 导入配置

有时我们需要在某个配置类中引入其他的类,引入的类也加入到Spring容器中。这时候可以使用注解@Import来完成这个功能。

如果你查看它的源代码,你会发现导入的类支持三种不同的类型。

但是我觉得最好把普通类的配置类和@Configuration注解分开解释,所以列出了四种不同的类型:

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分