今日内容: AOP 面向切面 代理模式 springmvc 运行原理 拦截器 springmvc异常处理机制
代理模式
为其他对象提供一种代理以控制对这个对象的访问。想在访问一个类时做一些控制是使用。
静态代理
优点:便于理解
缺点:
1.代码冗余:当多个被代理类,多个需增强方法的增强内容一样时,代码重复冗余
2.不易维护:每个被代理类需要专门维护一个代理类,类成倍增加,需增强方法增加时,需要同时维护代理类和被代理类。
动态代理
运行时动态地生成类字节码,加载进JVM。一般配合泛型实现。
1.JDK动态代理(组合,被代理类必须实现接口)
2.CGLIB动态代理(继承,被代理类不能被final修饰)
AOP
AOP (Aspect Orient Programming),直译过来就是 面向切面编程,AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。
面向切面编程,实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术.
AOP作用
AOP 采取横向抽取机制(动态代理),取代了传统纵向继承机制的重复性代码,其应用主要体现在事务处理、日志管理、权限控制、异常处理等方面。
主要作用是分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点或者横切逻辑,减少对业务代码的侵入,增强代码的可读性和可维护性。
简单的说,AOP 的作用就是保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。
Spring AOP的术语
Spring AOP 通知分类
Spring AOP 织入时期
基于AspectJ的SpringAOP
AspectJ是一个基于Java语言的AOP框架,Spring2.0以后新增了对AspectJ切点表达式支持.
添加依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.16</version>
</dependency>
定义切点
通过通过execution函数来定义切点,注解为@Pointcut("execution()")
被定义切点的类之后使用@Autoward注入时会注入此类的代理类(此类的子类,包含代理处理器,处理程序等等),而不是本类,通过动态代理实现。
具体使用方法见:http://t.csdnimg.cn/6T32o (本人太垃圾了真不懂所以直接看别人的吧)
举例使用:
SpringMVC
Spring MVC 使用 MVC 架构模式的思想,将 Web 应用进行职责解构,把一个复杂的 Web 应用划分成模型(Model)、控制器(Contorller)以及视图(View)三层,有效地简化了 Web 应用的开发,降低了出错风险,同时也方便了开发人员之间的分工配合.
Spring MVC @Controller和@RequestMapping注解
@Controller 注解可以将一个普通的 Java 类标识成控制器(Controller)类
@RequestMapping 注解的属性
它通常被标注在控制器方法上,负责将请求与处理请求的控制器方法关联起来,建立映射关系。
修饰方法:value 属性值就表示访问该方法的 URL 地址。
修饰类:value 属性的取值就是这个控制器类中的所有控制器方法 URL 地址的父路径。
各个属性作用:
value 属性:请求映射地址
name 属性:相当于方法的注释,解释用来干什么的
method 属性:没有设置就支持全部请求类型,不然method = "GET/POST/DELETE/PUT ",这玩意真不如@GetMapping来的痛快。
params 属性,headers 属性不常用,我也看不懂,用到了再说。
@Controller和@RestController
package com.easy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class EasyEController {
@RequestMapping("methoda")
public String methoda() {
System.out.println("---------methoda");
//返回地址
//forward:/ 默认 转发:同一个服务器中不同的服务器进行转发(同一个项目)
//转发是request对象执行forward方法
//浏览器发送了一个请求,可以转发到项目中受保护的资源 如:WEB-I
//redirect:/ 重定向:可以在不同的服务之间跳转,浏览器发送两次请求
//重定向是通过response对象通知浏览器重新访问
//可以访问外网
return "redirect:/methodb";
}
@RequestMapping("methodb")
@ResponseBody//返回值直接写入Response对象
public String methodb() {
System.out.println("---------methodb");
return "this is methodb";
}
@RequestMapping("methodc")
public String methodC() {
System.out.println("-----------methodC");
return "index.jsp";
}
}
@RestController:是@Controller与@ResponseBody的组合,表示返回值直接写入Response对象,即返回响应正文;
@Controller:使用 @Controller
的类通常需要返回一个视图名称
返回值修饰:
1.forward: 默认 转发:同一个服务器中不同的服务器进行转发(同一个项目),转发是request对象执行forward方法,浏览器发送了一个请求,可以转发到项目中受保护的资源 如:WEB-I
2.redirect: 重定向:可以在不同的服务之间跳转,浏览器发送两次请求,重定向是通过response对象通知浏览器重新访问,可以访问外网
@PathVariable
@RestController
@RequestMapping("/books")
public class BookController {
@GetMapping("/{bookId}")
public Book getBookById(@PathVariable("bookId") Long bookId) {
// 假设这里调用了服务层来获取书籍信息
return bookService.findById(bookId);
}
}
使用http://localhost:8080/books/123访问,在这个URL中,123
是路径变量bookId
的值,它将被传递给getBookById
方法。
@requestparam
@RequestMapping("search")
public List<User> searchUsers(@RequestParam(value = "name", required = false, defaultValue = "John") String name) {
// 如果请求中没有提供name参数,name变量将默认为"John"
}
在这个例子中如果请求的URL是http://localhost:8080/users/search?name=mike
在这个例子中name就是mike;如果请求的URL是 http://localhost:8080/users/search
(没有name
参数),那么name
变量将自动被赋予默认值 "John"
。
@PathVariable
从URL路径中获取值,@RequestParam
从查询参数中获取值。
springmvc 运行原理
1.用户发送request请求至前端控制器;
2.前端控制器调用处理器映射器查找处理器;
3.处理器映射器返回执行链 至前端控制器;
4.前端控制器调用处理器器适配器去执行处理器;
5.处理器适配器调用处理器;
6.处理器处理完成之后返回ModelAndView至处理器适配器;
7.处理器适配器返回ModelAndView至前端控制器;
8.前端控制器调用视图解析器解析视图;
9.视图解析器解析视图并返回view至前端控制器;
10.前端控制器渲染视图(view);
11.前端控制器向用户响应视图。
Spring MVC拦截器
它可以对用户请求进行拦截,并在请求进入控制器(Controller)之前handler、控制器处理完请求后、甚至是渲染视图后,执行一些指定的操作。它主要用于拦截用户请求并做相应的处理,例如通过拦截器,我们可以执行权限验证、记录请求信息日志、判断用户是否已登录等操作。
使用拦截器的步骤
1.实现拦截器接口:创建一个类实现HandlerInterceptor
接口,并实现其方法。
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 在控制器方法调用之前执行
return true; // 如果返回false,请求将不会继续执行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 在控制器方法调用之后执行
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 请求处理完毕后执行,无论成功或异常
}
}
2.注册拦截器:将拦截器注册到Spring MVC中。
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/api/**") // 指定拦截器应用的路径模式
.excludePathPatterns("/api/public/**"); // 排除不需要拦截的路径
}
}
拦截器的执行流程
1.当请求的路径与拦截器拦截的路径相匹配时,程序会先执行拦截器类(MyInterceptor)的 preHandle() 方法。若该方法返回值为 true,则继续向下执行 Controller(控制器)中的方法,否则将不再向下执行;
2.控制器方法对请求进行处理;
3.调用拦截器的 postHandle() 方法,此时我们可以对请求域中的模型(Model)数据和视图做出进一步的修改;通过 DispatcherServlet 的 render() 方法对视图进行渲染;
4.调用拦截器的 afterCompletion () 方法,完成资源清理、日志记录等工作。
多个拦截器的执行流程
springmvc异常处理机制
在实际的应用开发中,经常会不可避免地遇到各种可预知的、不可预知的异常,此时我们就需要对这些异常处理,以保证程序正常运行。Spring MVC 提供了一个名为 HandlerExceptionResolver 的异常处理器接口,它可以对控制器方法执行过程中出现的各种异常进行处理。
Srping MVC 为 HandlerExceptionResolver 接口提供了多个不同的实现类
Spring MVC的异常处理机制允许开发者捕获和处理Web应用程序中的异常。以下是Spring MVC异常处理的关键点:
1. **@ControllerAdvice**:
- 这是一个类级别的注解,用于定义一个类作为全局异常处理器。它与`@ExceptionHandler`注解结合使用来处理异常。
2. **@ExceptionHandler**:
- 这是一个方法级别的注解,用于声明特定异常的处理方法。它可以与`@ControllerAdvice`结合使用,处理全局异常,或者直接用于控制器类中,处理特定控制器的异常。
3. **异常处理方法**:
- 异常处理方法可以返回一个`ModelAndView`对象,用于渲染特定的视图,或者返回一个`ResponseEntity`对象,用于构造响应状态和正文。
4. **异常类型**:
- 异常处理方法可以声明处理特定类型的异常,也可以使用`Throwable`类型来捕获所有异常。
5. **异常参数**:
- 异常处理方法可以接收异常对象作为参数,以便访问异常信息。
6. **请求和响应对象**:
- 异常处理方法还可以接收`HttpServletRequest`和`HttpServletResponse`对象,以便访问和修改请求和响应的状态。
7. **响应状态**:
- 使用`@ResponseStatus`注解可以为异常处理方法指定HTTP响应状态。
8. **异常处理顺序**:
- 如果有多个异常处理方法可以处理同一个异常,Spring将按照声明它们的顺序来调用。
9. **自定义异常**:
- 开发者可以定义自定义异常类,并使用`@ControllerAdvice`和`@ExceptionHandler`来处理这些异常。
10. **继承和组合**:
- `@ControllerAdvice`类可以继承其他`@ControllerAdvice`类,或者使用`@Inherited`注解来共享异常处理方法。
11. **异常传播**:
- 异常处理方法可以决定是否将异常传播到其他处理器。
12. **RESTful API异常处理**:
- 对于RESTful API,异常处理方法通常返回JSON或XML格式的错误信息,而不是渲染视图。
### 示例:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(SpecificException.class)
public ResponseEntity<String> handleSpecificException(SpecificException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleAllExceptions(Exception ex) {
return new ResponseEntity<>("An unexpected error occurred", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
在这个示例中,`GlobalExceptionHandler`类使用`@ControllerAdvice`注解定义了两个异常处理方法。第一个方法`handleSpecificException`专门处理`SpecificException`类型的异常,而第二个方法`handleAllExceptions`作为一个通用异常处理器,捕获所有未被前面处理器处理的异常。