当前位置: 首页 > article >正文

温故--javaweb

Maven

Maven是一款管理和构建java项目的工具

基于项目对象模型(Project Object Model , 简称: POM)的概念

作用

依赖管理

pox.xml文件配置依赖

统一项目结构

项目构建

Maven模型

Maven仓库

  • 本地仓库:自己计算机上的一个目录(用来存储jar包)
  • 中央仓库:由Maven团队维护的全球唯一的。仓库地址:Central Repository:
  • 远程仓库(私服):一般由公司团队搭建的私有仓库

POM配置详解

POM (Project Object Model) :指的是项目对象模型,用来描述当前的maven项目。

  • 使用pom.xml文件来实现

pom.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <!-- POM模型版本 -->
  <modelVersion>4.0.0</modelVersion>

  <!-- 当前项目坐标 -->
  <groupId>com.itheima</groupId>
  <artifactId>maven_project1</artifactId>
  <version>1.0-SNAPSHOT</version>

  <!-- 打包方式 -->
  <packaging>jar</packaging>

</project>

pom文件详解:

  • <project> :pom文件的根标签,表示当前maven项目
  • <modelVersion> :声明项目描述遵循哪一个POM模型版本
    • 虽然模型本身的版本很少改变,但它仍然是必不可少的。目前POM模型版本是4.0.0
  • 坐标 :<groupId>、<artifactId>、<version>
    • 定位项目在本地仓库中的位置,由以上三个标签组成一个坐标
  • <packaging> :maven项目的打包方式,通常设置为jar或war(默认值:jar)

Maven坐标详解

什么是坐标?

  • Maven中的坐标是==资源的唯一标识== , 通过该坐标可以唯一定位资源位置
  • 使用坐标来定义项目或引入项目中需要的依赖

Maven坐标主要组成

  • groupId:定义当前Maven项目隶属组织名称(通常是域名反写,例如:com.itheima)
  • artifactId:定义当前Maven项目名称(通常是模块名称,例如 order-service、goods-service)
  • version:定义当前项目版本号

注意:

  • 上面所说的资源可以是插件、依赖、当前项目。
  • 我们的项目如果被其他的项目依赖时,也是需要坐标来引入的。

生命周期

• clean:移除上一次构建生成的文件

• compile:编译项目源代码

• test:使用合适的单元测试框架运行测试(junit)

• package:将编译后的文件打包,如:jar、war等

• install:安装项目到本地仓库

Spring

Spring Boot 可以帮助我们非常快速的构建应用程序、简化开发、提高效率 。

tomcat

Web服务器是一个应用程序(软件),对HTTP协议的操作进行封装,使得程序员不必直接对协议进行操作(不用程序员自己写代码去解析http协议规则),让Web开发更加便捷。主要功能是"提供网上信息浏览服务"

Web服务器是安装在服务器端的一款软件,将来我们把自己写的Web项目部署到Tomcat服务器软件中,当Web服务器软件启动后,部署在Web服务器软件中的页面就可以直接通过浏览器来访问了。

因为Tomcat支持Servlet/JSP规范,所以Tomcat也被称为Web容器、Servlet容器。JavaWeb程序需要依赖Tomcat才能运行。

Tomcat是一个Servlet容器,是支持Serlvet规范的,所以呢,在tomcat中是可以识别 Servlet程序的

springbootweb

在SpringBoot进行web程序开发时,它内置了一个核心的Servlet程序 DispatcherServlet,称之为 核心控制器。 DispatcherServlet 负责接收页面发送的请求,然后根据执行的规则,将请求再转发给后面的请求处理器Controller,请求处理器处理完请求之后,最终再由DispatcherServlet给浏览器响应数据。

那将来浏览器发送请求,会携带请求数据,包括:请求行、请求头;请求到达tomcat之后,tomcat会负责解析这些请求数据,然后呢将解析后的请求数据会传递给Servlet程序的HttpServletRequest对象,那也就意味着 HttpServletRequest 对象就可以获取到请求数据。 而Tomcat,还给Servlet程序传递了一个参数 HttpServletResponse,通过这个对象,我们就可以给浏览器设置响应数据 。

请求

在原始的Web程序当中,需要通过Servlet中提供的API:HttpServletRequest(请求对象),获取请求的相关信息。比如获取请求参数:

Tomcat接收到http请求时:把请求的相关信息封装到HttpServletRequest对象中

在Controller中,我们要想获取Request对象,可以直接在方法的形参中声明 HttpServletRequest 对象。然后就可以通过该对象来获取请求信息:

//根据指定的参数名获取请求参数的数据值
String  request.getParameter("参数名")

问题:

请求参数名和controller方法中的形参名不相同

可以使用Spring提供的@RequestParam注解完成映射

在方法形参前面加上 @RequestParam 然后通过value属性执行请求参数名,从而完成映射

@RestController
public class RequestController {
    // http://localhost:8080/simpleParam?name=Tom&age=20
    // 请求参数名:name

    //springboot方式
    @RequestMapping("/simpleParam")
    public String simpleParam(@RequestParam("name") String username , Integer age ){
        System.out.println(username+"  :  "+age);
        return "OK";
    }
}

响应

使用@ResponseBody注解将响应数据返回给前端;

@RestController = @Controller + @ResponseBody

  • 类上有@RestController注解或@ResponseBody注解时:表示当前类下所有的方法返回值做为响应数据
  • 方法的返回值,如果是一个POJO对象或集合时,会先转换为JSON格式,在响应给浏览器

IOC

详解

  • 控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。

对象的创建权由程序员主动创建转移到容器(由容器创建、管理对象)。这个容器称为:IOC容器或Spring容器

  • 依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。

程序运行时需要某个资源,此时容器就为其提供这个资源。

例:EmpController程序运行时需要EmpService对象,Spring容器就为其提供并注入EmpService对象

IOC容器中创建、管理的对象,称之为:bean对象

@Component ,就可以实现类交给IOC容器管理

@Autowired ,就可以实现程序运行时IOC容器自动注入需要的依赖对象

Spring框架为了更好的标识web应用程序开发当中,bean对象到底归属于哪一层,又提供了@Component的衍生注解:

  • @Controller (标注在控制层类上)
  • @Service (标注在业务层类上)
  • @Repository (标注在数据访问层类上)

注意事项:

  • 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
  • 使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。

组件扫描

bean想要生效,还需要被组件扫描

  • 将我们定义的controller,service,dao这些包呢,都放在引导类所在包com.itheima的子包下,这样我们定义的bean就会被自动的扫描到

使用@Resource注解:是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。

面试题 : @Autowird 与 @Resource的区别

  • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
  • @Autowired 默认是按照类型注入,而@Resource是按照名称注入

Mybatis

MyBatis是一款优秀的 持久层框架,用于简化JDBC的开发。

在springboot项目中,可以编写application.properties文件,配置数据库连接信息。我们要连接数据库,就需要配置数据库连接的基本信息,包括:driver-class-name、url 、username,password。

java语言操作数据库呢,只能通过一种方式:使用sun公司提供的 JDBC 规范。

Mybatis框架,就是对原始的JDBC程序的封装。

mybatis中,使用了数据库连接池技术,避免频繁的创建连接、销毁连接而带来的资源浪费。

数据库连接池

数据库连接池是个容器,负责分配、管理数据库连接(Connection)

  • 程序在启动时,会在数据库连接池(容器)中,创建一定数量的Connection对象

允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个

  • 客户端在执行SQL时,先从连接池中获取一个Connection对象,然后在执行SQL语句,SQL语句执行完之后,释放Connection时就会把Connection对象归还给连接池(Connection对象可以复用)

释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏

  • 客户端获取到Connection对象了,但是Connection对象并没有去访问数据库(处于空闲),数据库连接池发现Connection对象的空闲时间 > 连接池中预设的最大空闲时间,此时数据库连接池就会自动释放掉这个连接对象


Hikari、Druid (性能更优越)

Hikari (springboot默认)

日志输入

  1. 打开application.properties文件
  2. 开启mybatis的日志,并指定输出到控制台
#指定mybatis输出日志的位置, 输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

预编译SQL

(防止SQL注入)

SQL注入:是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。

由于没有对用户输入进行充分检查,而SQL又是拼接而成,在用户输入参数时,在参数中添加一些SQL关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击。

开启驼峰命名

# 在application.properties中添加:
mybatis.configuration.map-underscore-to-camel-case=true

XML配置文件规范

  1. XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)
  2. XML映射文件的namespace属性为Mapper接口全限定名一致
  3. XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致。

参数配置化

参数配置在配置文件application.properties中;

application.properties是springboot项目默认的配置文件,所以springboot程序在启动时会默认读取application.properties配置文件,而我们可以使用一个现成的注解:@Value,获取配置文件中的数据。

@Value 注解通常用于外部配置的属性注入,具体用法为: @Value("${配置文件中的key}")

在Spring中给我们提供了一种简化方式,可以直接将配置文件中配置项的值自动的注入到对象的属性中。

@ConfigurationProperties

  1. 需要创建一个实现类,且实体类中的属性名和配置文件当中key的名字必须要一致

比如:配置文件当中叫endpoints,实体类当中的属性也得叫endpoints,另外实体类当中的属性还需要提供 getter / setter方法

  1. 需要将实体类交给Spring的IOC容器管理,成为IOC容器当中的bean对象
  2. 在实体类上添加@ConfigurationProperties注解,并通过perfect属性来指定配置参数项的前缀


然后使用就可以

@Component //当前类对象由Spring创建和管理

//注入配置参数实体类对象
@Autowired
private AliOSSProperties aliOSSProperties;

yml配置文件

语法:

  • 大小写敏感
  • 数值前边必须有空格,作为分隔符
  • 使用缩进表示层级关系,缩进时,不允许使用Tab键,只能用空格(idea中会自动将Tab转换为空格)
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
  • #表示注释,从这个字符一直到行尾,都会被解析器忽略

会话技术

在web开发当中,会话指的就是浏览器与服务器之间的一次连接,我们就称为一次会话。

会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。

服务器会接收很多的请求,但是服务器是需要识别出这些请求是不是同一个浏览器发出来的。比如:1和2这两个请求是不是同一个浏览器发出来的,3和5这两个请求不是同一个浏览器发出来的。如果是同一个浏览器发出来的,就说明是同一个会话。如果是不同的浏览器发出来的,就说明是不同的会话。而识别多次请求是否来自于同一浏览器的过程,我们就称为会话跟踪。

我们使用会话跟踪技术就是要完成在同一个会话中,多个请求之间进行共享数据。

为什么要共享数据呢?

由于HTTP是无状态协议,在后面请求中怎么拿到前一次请求生成的数据呢?此时就需要在一次会话的多次请求之间进行数据共享

会话跟踪技术

  1. Cookie(客户端会话跟踪技术)
    • 数据存储在客户端浏览器当中
  1. Session(服务端会话跟踪技术)
    • 数据存储在储在服务端
  1. 令牌技术

Cookie

通过使用Cookie,可以在用户的浏览器上保存一些信息,如认证状态。

当用户首次成功登录后,服务器会在响应中设置一个Cookie,其中包含用于识别用户的数据。浏览器自动保存此Cookie,并在后续每次向同一服务器发送请求时附带该Cookie。

服务器可以通过读取这些Cookie来识别用户是否已登录,从而实现会话跟踪和数据共享。

简而言之,Cookie帮助维持了用户与服务器之间的状态信息,确保了会话的一致性。

  • 服务器会 自动 的将 cookie 响应给浏览器。
  • 浏览器接收到响应回来的数据之后,会 自动 的将 cookie 存储在浏览器本地。
  • 在后续的请求当中,浏览器会 自动 的将 cookie 携带到服务器端。

自动化

cookie 它是 HTP 协议当中所支持的技术,而各大浏览器厂商都支持了这一标准

HTTP 协议官方给我们提供了一个响应头和请求头:

  • 响应头 Set-Cookie :设置Cookie数据的
  • 请求头 Cookie:携带Cookie数据的

缺点

  • 移动端APP(Android、IOS)中无法使用Cookie
  • 不安全,用户可以自己禁用Cookie
  • Cookie不能跨域

跨域


 

Session

服务器端会话跟踪技术,所以它是存储在服务器端的

使用Session进行会话跟踪时,服务器会为每个用户创建一个唯一的会话标识符,即Session ID。首次访问时,若无现有会话,则服务器创建一个新的Session,并通过Set-Cookie响应头将Session ID作为名为JSESSIONID的Cookie发送给浏览器。浏览器保存此Cookie,并在后续请求中自动包含它。服务器通过读取JSESSIONID来识别特定的Session,从而在多次请求间保持状态并共享数据。这就是基于Session的会话跟踪机制的基本流程。

缺点

  • 服务器集群环境下无法直接使用Session
  • 移动端APP(Android、IOS)中无法使用Cookie
  • 用户可以自己禁用Cookie
  • Cookie不能跨域

在服务器集群环境中,由于用户请求可能被负载均衡器分配到不同的服务器上,这导致基于单点服务器的Session机制失效,因为各服务器间的Session数据默认是不共享的,这就可能导致Session信息无法同步,进而影响会话跟踪。

####令牌技术####

使用令牌技术进行会话跟踪时,用户登录成功后生成一个令牌作为身份验证凭据,并将其返回给前端。前端可将令牌存储于Cookie或localStorage等存储空间中。在后续请求中,前端需携带此令牌,服务器则验证令牌有效性以确认用户身份。有效令牌表明用户已登录,反之则未登录。通过令牌,可在会话期间跨多个请求共享数据。

JWT令牌

JSON Web Token

简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。

自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。

简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。

JWT是如何将原始的JSON格式数据,转变为字符串的呢?

其实在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码

Base64:是一种基于64个可打印的字符来表示二进制数据的编码方式。既然能编码,那也就意味着也能解码。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。任何数据经过base64编码之后,最终就会通过这64个字符来表示。当然还有一个符号,那就是等号。等号它是一个补位的符号

需要注意的是Base64是编码方式,而不是加密方式。

生成和校验

要想使用JWT令牌,需要先引入JWT的依赖:

<!-- JWT依赖-->
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt</artifactId>
  <version>0.9.1</version>
</dependency>

生成

校验

服务器响应的JWT令牌存储在本地浏览器哪里了呢?

  • 在当前案例中,JWT令牌存储在浏览器的本地存储空间local storage中了。 local storage是浏览器的本地存储,在移动端也是支持的。

过滤器Filter

统一拦截到所有的请求校验令牌的有效性

使用

  • 第1步,定义过滤器 :1.定义一个类,实现 Filter 接口,并重写其所有方法。
  • 第2步,配置过滤器:Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet组件支持。

执行流程

在调用doFilter()这个方法之前所编写的代码属于放行之前的逻辑。

在放行后访问完 web 资源之后还会回到过滤器当中,

放行之后的逻辑我们写在doFilter()这行代码之后。

过滤器链

过滤器链指的是在一个web应用程序当中,可以配置多个过滤器,多个过滤器就形成了一个过滤器链。

以注解方式配置的Filter过滤器,它的执行优先级是按时过滤器类名的自动排序确定的,类名排名越靠前,优先级越高。

校验

@Slf4j
@WebFilter(urlPatterns = "/*") //拦截所有请求
public class LoginCheckFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        //前置:强制转换为http协议的请求对象、响应对象 (转换原因:要使用子类中特有方法)
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        //1.获取请求url
        String url = request.getRequestURL().toString();
        log.info("请求路径:{}", url); //请求路径:http://localhost:8080/login


        //2.判断请求url中是否包含login,如果包含,说明是登录操作,放行
        if(url.contains("/login")){
            chain.doFilter(request, response);//放行请求
            return;//结束当前方法的执行
        }


        //3.获取请求头中的令牌(token)
        String token = request.getHeader("token");
        log.info("从请求头中获取的令牌:{}",token);


        //4.判断令牌是否存在,如果不存在,返回错误结果(未登录)
        if(!StringUtils.hasLength(token)){
            log.info("Token不存在");

            Result responseResult = Result.error("NOT_LOGIN");
            //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
            String json = JSONObject.toJSONString(responseResult);
            response.setContentType("application/json;charset=utf-8");
            //响应
            response.getWriter().write(json);

            return;
        }

        //5.解析token,如果解析失败,返回错误结果(未登录)
        try {
            JwtUtils.parseJWT(token);
        }catch (Exception e){
            log.info("令牌解析失败!");

            Result responseResult = Result.error("NOT_LOGIN");
            //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
            String json = JSONObject.toJSONString(responseResult);
            response.setContentType("application/json;charset=utf-8");
            //响应
            response.getWriter().write(json);

            return;
        }


        //6.放行
        chain.doFilter(request, response);

    }
}

拦截器Interceptor

是一种动态拦截方法调用的机制,类似于过滤器。

拦截器是Spring框架中提供的,用来动态拦截控制器方法的执行

拦截器的作用:

  • 拦截请求,在指定方法调用前后,根据业务需要执行预先设定的代码。

在拦截器当中,我们通常也是做一些通用性的操作,比如:我们可以通过拦截器来拦截前端发起的请求,将登录校验的逻辑全部编写在拦截器当中。在校验的过程当中,如发现用户登录了(携带JWT令牌且是合法令牌),就可以直接放行,去访问spring当中的资源。如果校验时发现并没有登录或是非法令牌,就可以直接给前端响应未登录的错误信息。

使用

自定义拦截器

实现HandlerInterceptor接口,并重写其所有方法

//自定义拦截器
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
    //目标资源方法执行前执行。 返回true:放行    返回false:不放行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle .... ");
        
        return true; //true表示放行
    }

    //目标资源方法执行后执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle ... ");
    }

    //视图渲染完毕后执行,最后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion .... ");
    }
}

preHandle方法:目标资源方法执行前执行。 返回true:放行 返回false:不放行

postHandle方法:目标资源方法执行后执行

afterCompletion方法:视图渲染完毕后执行,最后执行

注册配置拦截器:实现WebMvcConfigurer接口,并重写addInterceptors方法

@Configuration  
public class WebConfig implements WebMvcConfigurer {

    //自定义的拦截器对象
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;

    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       //注册自定义拦截器对象
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");//设置拦截器拦截的请求路径( /** 表示拦截所有请求)
    }
}

执行流程

  • 接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。
  • 拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。

异常处理

全局异常处理器

  • 定义全局异常处理器非常简单,就是定义一个类,在类上加上一个注解@RestControllerAdvice,加上这个注解就代表我们定义了一个全局异常处理器。
  • 在全局异常处理器当中,需要定义一个方法来捕获异常,在这个方法上需要加上注解@ExceptionHandler。通过@ExceptionHandler注解当中的value属性来指定我们要捕获的是哪一类型的异常。

@RestControllerAdvice = @ControllerAdvice + @ResponseBody

@RestControllerAdvice
public class GlobalExceptionHandler {

    //处理异常
    @ExceptionHandler(Exception.class) //指定能够处理的异常类型
    public Result ex(Exception e){
        e.printStackTrace();//打印堆栈中的异常信息

        //捕获到异常之后,响应一个标准的Result
        return Result.error("对不起,操作失败,请联系管理员");
    }
}
  • @RestControllerAdvice //表示当前类为全局异常处理器
  • @ExceptionHandler //指定可以捕获哪种类型的异常进行处理

事务

Transactional注解

@Transactional作用:就是在当前这个方法执行开始之前来开启事务,方法执行完毕之后提交事务。如果在这个方法执行的过程当中出现了异常,就会进行事务的回滚操作。

@Transactional注解:我们一般会在业务层当中来控制事务,因为在业务层当中,一个业务功能可能会包含多个数据访问的操作。在业务层来控制事务,我们就可以将多个数据访问操作控制在一个事务范围内。

默认情况下,只有出现RuntimeException(运行时异常)才会回滚事务

rollbackfor

想让所有的异常都回滚,需要来配置@Transactional注解当中的rollbackFor属性

propagation

propagation,这个属性是用来配置事务的传播行为的。

  • 就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。

REQUIRED

【默认值】需要事务,有则加入,无则创建新事务

REQUIRES_NEW

需要新事务,无论有无,总是创建新事务

AOP

AOP的作用:在程序运行期间在不修改源代码的基础上对已有方法进行增强(无侵入性: 解耦)

AOP底层是基于动态代理技术来实现的,也就是说在程序运行的时候,会自动的基于动态代理技术为目标对象生成一个对应的代理对象。在代理对象当中就会对目标对象当中的原始方法进行功能的增强。

使用

引入依赖

pom.xml

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

切面类

核心

连接点:JoinPoint

可以被AOP控制的方法(暗含方法执行时的相关信息)

通知:Advice

指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)

切入点:PointCut

匹配连接点的条件,通知仅会在切入点方法执行时被应用

切面:Aspect

通知切入点的对应关系(通知+切入点)

切面所在的类,我们一般称为切面类(被@Aspect注解标识的类)

目标对象:Target

通知所应用的对象

通知类型

  • @Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
  • @Before:前置通知,此注解标注的通知方法在目标方法前被执行
  • @After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
  • @AfterReturning : 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
  • @AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行

执行的顺序是:

异常通知就会在返回通知处,且通知中的环绕后的代码逻辑也不会在执行了;

注意:

  • @Around环绕通知需要自己调用 ProceedingJoinPoint.proceed() 来让原始方法执行,其他通知不需要考虑目标方法执行
  • @Around环绕通知方法的返回值,必须指定为Object,来接收原始方法的返回值,否则原始方法执行完毕,是获取不到返回值的。

怎么来解决这个切入点表达式重复的问题? 答案就是:抽取

@PointCut注解

切入点表达式

execution

  • * :单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
  • .. :多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数

@annotation

匹配多个无规则的方法

实现步骤:

  1. 编写自定义注解
  2. 在业务类要做为连接点的方法上添加自定义注解

连接点

对于@Around通知,获取连接点信息只能使用ProceedingJoinPoint类型

对于其他四种通知,获取连接点信息只能使用JoinPoint,它是ProceedingJoinPoint的父类型

springBoot原理篇

配置优先级

  • application.properties
  • application.yml
  • application.yaml
  • Java系统属性配置 (格式: -Dkey=value)

-Dserver.port=9000

  • 命令行参数 (格式:--key=value)

--server.port=10010

优先级: 命令行参数 > 系统属性参数 > properties参数 > yml参数 > yaml参数

Bean管理

获取Bean

获取到IOC容器,直接将IOC容器对象注入进来就可以了

IOC容器当中的bean对象只有一个(默认情况下,IOC中的bean对象是单例)

第三方Bean

在pom.xml文件中,引入dom4j:

<!--Dom4j-->
<dependency>
  <groupId>org.dom4j</groupId>
  <artifactId>dom4j</artifactId>
  <version>2.1.3</version>
</dependency>

dom4j就是第三方组织提供的。 dom4j中的SAXReader类就是第三方编写的。


要管理的bean对象来自于第三方(不是自定义的),是无法用@Component 及衍生注解声明bean的,就需要用到@Bean注解。

在配置类中定义@Bean标识的方法

需要定义第三方Bean时, 通常会单独定义一个配置类

  • 如果是在项目当中我们自己定义的类,想将这些类交给IOC容器管理,我们直接使用@Component以及它的衍生注解来声明就可以。
  • 如果这个类它不是我们自己定义的,而是引入的第三方依赖当中提供的类,而且我们还想将这个类交给IOC容器管理。此时我们就需要在配置类中定义一个方法,在方法上加上一个@Bean注解,通过这种方式来声明第三方的bean对象。

SpringBoot原理

解析自动配置的原理

SpringBoot项目当中,我们引入对应的依赖之后,是如何将依赖jar包当中所提供的bean以及配置类直接加载到当前项目的SpringIOC容器当中的。

引入进来的第三方依赖当中的bean以及配置类为什么没有生效?

  • 原因在我们之前讲解IOC的时候有提到过,在类上添加@Component注解来声明bean对象时,还需要保证@Component注解能被Spring的组件扫描到。
  • SpringBoot项目中的@SpringBootApplication注解,具有包扫描的作用,但是它只会扫描启动类所在的当前包以及子包。
  • 当前包:com.itheima, 第三方依赖中提供的包:com.example(扫描不到)

解决

在启动类中用@Import导入

我们不用自己指定要导入哪些bean对象和配置类了,让第三方依赖它自己来指定

原理分析

小结

外界俗称的SSM,就是由:SpringMVC、Spring Framework、Mybatis三块组成。

maven高级

分模块

继承与聚合

继承关系

版本锁定

版本集中管理之后,我们要想修改依赖的版本,就只需要在父工程中自定义属性的位置,修改对应的属性值即可。


聚合

  • 聚合工程:一个不具有业务功能的“空”工程(有且仅有一个pom文件) 【PS:一般来说,继承关系中的父工程与聚合关系中的聚合工程是同一个】

私服

私服其实就是架设在公司局域网内部的一台服务器,就是一种特殊的远程仓库。


http://www.kler.cn/news/310788.html

相关文章:

  • MySQL行锁的实践
  • Gitee丝滑版本:成功在新电脑添加新文件
  • WebGL中的纹理映射:为虚拟世界穿上华丽的外衣
  • KNN算法与实战案例详解
  • 基于51单片机的自动清洗系统(自动洗衣机)
  • 【QT】系统-上
  • ​补​充​元​象​二​面​
  • Hexo框架学习——从安装到配置
  • SpringBoot:解析excel
  • PowerBI 关于FILTERS函数和VALUES函数
  • Spring模块详解Ⅳ(Spring ORM和Spring Transaction)
  • RedisTemplate混用带来的序列化问题
  • json.dumps 中的参数
  • 预警提醒并生成日志,便于后期追溯的智慧地产开源了
  • 让IT部门弄一个炫酷的数字驾驶舱就是数字化转型成功?
  • Vue 3 中动态赋值 ref 的应用
  • windows下使用 vscode 远程X11服务GUI显示的三种方法
  • 从种草到销售:家居品牌构建O2O私域运营的完整闭环
  • 考研数学精解【3】
  • 四、(JS)JS中常见的加载事件
  • 软考(中级-软件设计师)(0919)
  • 百度Android IM SDK组件能力建设及应用
  • Golang、Python、C语言、Java的圆桌会议
  • https和http区别
  • 【网络】TCP/IP 五层网络模型:网络层
  • 计算机专业毕设-校园新闻网站
  • vue实现二维码生成器应用
  • 【ARM】Cache深度解读
  • redis 在企业开发实践中注意事项
  • MATLAB中的无线通信系统部署和优化工具有哪些