springboot 基础学习一

微服务以前也在用,但是没有深入去学习,今年面试时候很多公司都在问会不会使用微服务架构,微服务架构面试问题回答的不好,所以现在记录下springboot框架基础学习。
一、基础学习
1,首先建立一个springboot项目,使用intellij idea 来快速创建一个springboot项目
在这里插入图片描述
2、点击下一步
在这里插入图片描述
3、在下一步,这里使用的是springboot 2.1.4版本。点击next就创建好一个springboot项目了。
在这里插入图片描述4、我这里创建后项目结构如下,并添加了多个子模块。
在这里插入图片描述
先看看父类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">
	<modelVersion>4.0.0</modelVersion>
	<groupId>org.learn</groupId>
	<artifactId>learn</artifactId>
	<version>1.0-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>learn</name>

	<modules>
		<module>learn_spring_boot_demo</module>
		<module>learn_spring_boot_drools</module>
		<module>learn_spring_boot_mybatis_demo</module>
		<module>learn_spring_boot_mybatis_datasource</module>
	</modules>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.4.RELEASE</version>
	</parent>


	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<jdk.version>1.8</jdk.version>
		<spring.version>5.1.6.RELEASE</spring.version>
		<mysql.version>8.0.11</mysql.version>
		<thymeleaf.layout.version>2.4.1</thymeleaf.layout.version>
		<lombok.version>1.18.2</lombok.version>
		<drools.version>7.20.0.Final</drools.version>
		<kie.version>7.20.0.Final</kie.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
		<!--核心模块,包括自动配置支持、日志和YAML-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<!--Web模块 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!--测试模块,包括JUnit、Hamcrest、Mockito-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

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

		<!--thymeleaf 框架-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<!--springBoot 2.0 将布局单独提取出来,需要单独引入依赖-->
		<dependency>
			<groupId>nz.net.ultraq.thymeleaf</groupId>
			<artifactId>thymeleaf-layout-dialect</artifactId>
			<version>${thymeleaf.layout.version}</version>
		</dependency>
		<!--修改html后自动发布-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>
		<!--自动配置-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>

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


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


		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.version}</version>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>${lombok.version}</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.drools</groupId>
			<artifactId>drools-compiler</artifactId>
			<version>${drools.version}</version>
		</dependency>

		<dependency>
			<groupId>org.kie</groupId>
			<artifactId>kie-spring</artifactId>
			<version>${kie.version}</version>
		</dependency>


	</dependencies>

	<build>
		<plugins>
			<plugin>
				<!--在添加了该插件之后,当运行“mvn package”进行打包时,
				会打包成一个可以直接运行的 JAR 文件,使用“java -jar”命令就可以直接运行。
				这在很大程度上简化了应用的部署,只需要安装了 JRE 就可以运行。-->
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>

			<plugin>
				<!-- 指定maven编译的jdk版本,如果不指定,maven3默认用jdk 1.5 maven2默认用jdk1.3 -->
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.0</version>
				<configuration>
					<!-- 一般而言,target与source是保持一致的,但是,
					有时候为了让程序能在其他版本的jdk中运行(对于低版本目标jdk,
					源代码中不能使用低版本jdk中不支持的语法),会存在target不同于source的情况 -->
					<source>1.8</source> <!-- 源代码使用的JDK版本 -->
					<target>1.8</target> <!-- 需要生成的目标class文件的编译版本 -->
					<encoding>UTF-8</encoding> <!-- 字符集编码 -->
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

5、第一个子模块leran_spring_boot_demo启动类
在这里插入图片描述
该模块的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">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.learn</groupId>
		<artifactId>learn</artifactId>
		<version>1.0-SNAPSHOT</version>
		<!--这里是指向父类pom文件-->
		<relativePath> <!-- lookup parent from repository -->
		 ../pom.xml
		</relativePath>
	</parent>

	<artifactId>learn_spring_boot_demo</artifactId>

	<dependencies>
		<!--核心模块,包括自动配置支持、日志和YAML-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<!--Web模块 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!--测试模块,包括JUnit、Hamcrest、Mockito-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

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

		<!--自动配置-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>



	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
			<plugin>
				<!--Maven通过Maven Surefire Plugin插件执行单元测试。
				(通过Maven Failsafe Plugin插件执行集成测试)
				 在pom.xml中配置JUnit,TestNG测试框架的依赖,即可自动识别和运行src/test目录下利用该框架编写的测试用例。
                 surefire也能识别和执行符合一定命名约定的普通类中的测试方法(POJO测试)。
                 生命周期中test阶段默认绑定的插件目标就是surefire中的test目标,无需额外配置,直接运行mvn test就可以。-->
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>2.22.1</version>
				<configuration>
					<skipTests>true</skipTests>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

6、resources目录下结构
在这里插入图片描述
7、application.properties配置文件

server.port=8081
spring.banner.charset=UTF-8
server.tomcat.uri-encoding=UTF-8
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.messages.encoding=UTF-8
spring.jpa.show-sql=true
logging.level.org.springframework.data=debug
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/lin?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true
spring.datasource.username=root
spring.datasource.password=123
# 这个必须依赖了mysql 才行
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.thymeleaf.cache=false
# 定位模板的目录
spring.mvc.view.prefix=classpath:/templates/
# 给返回的页面添加后缀名
spring.mvc.view.suffix=.html

org.learn.boot.demo.name="林"
org.learn.boot.demo.wish="你要加油呀"


8、运行后,控制台打印的日志,端口为8081在这里插入图片描述9、在浏览器中访问这个http://localhost:8081/地址,便可以看到以下页面(Spring Boot默认错误页面)
在这里插入图片描述
10、现在通过子模块learn_spring_boot_demo来做一下简单增删改查。

创建两个实体类
在这里插入图片描述
在这里插入图片描述
11、UserRepository 接口类,这里通过实现JpaRepository类来进行数据增、删、改、查操作

package org.learn.boot.demo.model;

import org.learn.boot.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

/**
 * ClassName: UserDao
 * Description: 数据访问层
 * Date:     2019/3/20 15:25
 * History:
 * <version> 1.0
 * @author lin
 */
public interface UserRepository extends JpaRepository<User,Long> {

     /**
      * @Description 根据ID查询
      * @param id
      * @return com.boot.demo.entity.User
      * @author lin
      * @Date 15:42 2019/3/20
      **/
     @Query(value = "select u from User u where u.id=:id")
     User findById(@Param("id") int id);

     /**
      * @Description 根据姓名查询
      * @param name
      * @return java.util.List<com.boot.demo.entity.User>
      * @author lin
      * @Date 15:43 2019/3/20
      **/
     @Query(value ="select u from User u where u.name=:name")
     List<User> findByName(@Param(value = "name") String name);

     /**
      * @Description 添加用户
      * @param name
      * @param age
      *
      * @return com.boot.demo.entity.User
      * @author lin
      * @Date 16:40 2019/3/20
      **/
     @Modifying
     @Query(value = "insert into c_user(name,age) values(?1,?2)",nativeQuery = true)
     int saveUser(String name, Integer age);


     /**
      * @Description 修改
      * @param id
      * @param name
      * @param age
      * @return com.boot.demo.entity.User
      * @exception   
      * @author lin
      * @Date 11:43 2019/3/21
      **/
     @Modifying
     @Query(value = "update  User u set u.name=?2 , u.age=?3 where u.id=?1")
     int update(Integer id, String name, Integer age);

     /**
      * @Description 删除(使用原生sql)
      * @param id
      * @return void
      * @exception   
      * @author lin
      * @Date 11:50 2019/3/21
      **/
     @Modifying
     @Query(value = "delete from c_user  WHERE id=?1",nativeQuery = true)
     void deleteById(Integer id);
}

12、UserService接口类

package org.learn.boot.demo.service;


import org.learn.boot.demo.entity.User;

import java.util.List;

/**
 * ClassName: UserService
 * Description: 接口类
 * Author:   lin
 * Date:     2019/3/20 16:23
 * History:
 * <version> 1.0
 */
public interface UserService {

    /**
     * @Description 根据ID查询
     * @param id
     * @return com.boot.demo.entity.User
     * @author lin
     * @Date 15:42 2019/3/20
     **/
    User findById(int id);
    /**
     * @Description 根据姓名查询
     * @param name
     * @return java.util.List<com.boot.demo.entity.User>
     * @author lin
     * @Date 15:43 2019/3/20
     **/
    List<User> findByName(String name);
    /**
     * @Description 添加用户
     * @param name
     * @param age
     *
     * @return int
     * @author lin
     * @Date 16:40 2019/3/20
     **/
    int saveUser(String name, Integer age);

    /**
     * @Description 查询全部
     * @return java.util.List<com.boot.demo.entity.User>
     * @author lin
     * @Date 18:55 2019/3/20
     **/
    List<User> finAll();

    /**
     * @Description 更新
     * @param id
     * @param name
     * @param age
     * @return com.boot.demo.entity.User
     * @exception   
     * @author lin
     * @Date 11:38 2019/3/21
     **/
    int update(Integer id, String name, Integer age);

    /**
     * @Description 删除
     * @param id
     * @return void
     * @exception   
     * @author lin
     * @Date 11:51 2019/3/21
     **/
    void delete(Integer id);
    /**
     * @Description 添加用户信息
     * @param user
     * @return User
     * @exception
     * @author lin
     * @Date 12:50 2019/3/21
     **/
    User addUser(User user);
}

13、UserServiceImpl实现类

package org.learn.boot.demo.service.impl;

import org.learn.boot.demo.entity.User;
import org.learn.boot.demo.model.UserRepository;
import org.learn.boot.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * ClassName: UserServiceImpl
 * Description: 实现类
 * Date:     2019/3/20 16:41
 * History:
 * <version> 1.0
 * @author lin
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;


    @Override
    public User findById(int id) {
        return userRepository.findById(id);
    }

    @Override
    public List<User> findByName(String name) {
        return userRepository.findByName(name);
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = {RuntimeException.class})
    public int saveUser(String name, Integer age) {
        return userRepository.saveUser(name, age);
    }

    @Override
    public List<User> finAll() {
        return userRepository.findAll();
    }

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = {RuntimeException.class})
    @Override
    public int update(Integer id, String name, Integer age) {
        return userRepository.update(id,name,age);
    }

    /**
     * @param id
     * @return void
     * @throws
     * @Description 删除
     * @author lin
     * @Date 11:51 2019/3/21
     **/
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = {RuntimeException.class})
    @Override
    public void delete(Integer id) {
        userRepository.deleteById(id);
    }

    /**
     * @param user
     * @return int
     * @throws
     * @Description 添加用户信息
     * @author lin
     * @Date 12:50 2019/3/21
     **/
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = {RuntimeException.class})
    @Override
    public User addUser(User user) {
        return userRepository.save(user);
    }


}

14、UserRedirectController 类

package org.learn.boot.demo.controller;

import org.learn.boot.demo.entity.User;
import org.learn.boot.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

/**
 * ClassName: UserRedirectController
 * Description: 重定向
 * Date:     2019/3/21 0:18
 * History:
 * <version> 1.0
 * @author lin
 */
@Controller
public class UserRedirectController {

    @Autowired
    private UserService userService;



    @RequestMapping("/indexRedirect")
    public String index() {
        return "redirect:/list";
    }

    @RequestMapping("/list")
    public String list(Model model){
        List<User> users = userService.finAll();
        model.addAttribute("users",users);
        return "user/list";
    }
    //return "user/userEdit"; 代表会直接去 resources 目录下找相关的文件。
    //return "redirect:/list"; 代表转发到对应的 Controller,这个示例就相当于删除内容之后自动调整到 list 请求,然后再输出到页面。


    @RequestMapping("/toAdd")
    public String toAdd(){
        return "user/userAdd";
    }

    @RequestMapping("/add")
    public String add(User user) {
        userService.addUser(user);
        return "redirect:/list";
    }


    @RequestMapping("/toEdit")
    public String toEdit(Model model, Integer id) {
        User user=userService.findById(id);
        model.addAttribute("user", user);
        return "user/userEdit";
    }

    @RequestMapping("/edit")
    public String edit(Integer id, String userName, Integer age) {
        userService.update(id, userName, age);
        return "redirect:/list";
    }


    @RequestMapping("/delete")
    public String delete(Integer id) {
        userService.delete(id);
        return "redirect:/list";
    }
}

15、访问http://localhost:8081/indexRedirect 地址会重新定向到http://localhost:8081/list 地址,然后就是list.html页面,在这里就可以进行简单的增删查改操作。
在这里插入图片描述
二、springboot 源码分析
1、在程序的入口类中有个注解@SpringBootApplication ,该注解的作用是什么呢?
在这里插入图片描述
2、进入springBootApplication注解类中,可以看到有@springBootConfiguration 注解,@EnableAutoConfiguration注解。
@springBootConfiguration:表示的是spring Boot的配置类。进入该类就可以知道这个类是有注解@Configuration 注解,这就是我们在使用spring 的一个 配置时的一种方式(spring 配置方式 有 xml方式、基于注解的方式、基于java 的配置方式)。
https://blog.csdn.net/icarus_wang/article/details/51649635(spring Bean配置的三种方式)
在这里插入图片描述
3、在进入配置类里面,我们可以看到@Component 注解,这就表示这个类也是容器中的一个组件。
在这里插入图片描述
4、@EnableAutoConfiguration注解
该注解就是开启自动装配功能,在springBoot 应用中我们没有做任何配置,那springmvc 也启动起来了整个应用也能用了,包扫面也扫进去了。这些功能是怎么做的呢? 就是通过@EnableAutoConfiguration注解 来实现。
以前spring 需要配置的东西,springBoot帮我们自动配置,@EnableAutoConfiguration 告诉springBoot 开启自动配置功能。这样自动配置功能才能生效。
在进入 @EnableAutoConfiguration 注解类中,我们可以看到@AutoConfigurationPakage 注解 ,表示自动配置包
在这里插入图片描述
5、进入@AutoConfigurationPakage 注解类中,它是通过@Import 注解来实现,这个注解是属于spring 的底层注解。它的作用就是给容器导入一个组件;导入的组件由 AutoConfigurationPakages.Registras.class 这个class类
在这里插入图片描述
6、我们进入registar 这个内部类。这个类有个方法,就是注册一些bean定义信息,这是给容器导组件
在这里插入图片描述
7、组件主要是 New PackageImport(metadata).getPackageName(); 这个metadata 就是这个注解标注的原信息。然后同getPackageName() 去拿去包名。通过debug的方式可以拿到 这个包名。所以这个@AutoConfigurationPakage 注解 将主配置类(@springbootApplication 标注的类)的所在包及下面所有子包里面的所有组件扫描到spring 容器; 所有我们能扫面到controller ,因为他是在主配置类的子包下。
在这里插入图片描述
8、按照上面的想法,一旦换包了或者在目录java 下再建立一个包并创建一个类用来验证。
在这里插入图片描述
在这里插入图片描述
9、这个时候再启动,并访问 localhost:8080/index 就会报404。
在这里插入图片描述
所以在创建项目包的时候要将包和有@SpringBootApplication注解的类放在 的子包下或者同一级下。

10、在@EnableAutoConfiguration注解类中 还有 @Import(AutoConfigurationImportSelector.class) 注解,这个注解是给容器导入注解,该import导入的是AutoConfigurationImportSelector组件。进入该组件类中 一个方法是selectImports
在这里插入图片描述
11、selectImports 方法 中会去调用getAutoConfigurationEntry()方法,进入该方法
在这里插入图片描述
autoConfigurationMetadata主要是自动配置的元数据,
在这里插入图片描述
annotationMetadata 是注解的元数据。
在这里插入图片描述
12、在 方法中 list configurations 这个list 中包含很多的自动配置类(xxxAutoConfiguration). 就是给容器导入这个场景所需要的所有组件,并配置好这些组件。
如果要Aop的功能,那么呢Aop的自动配置类就帮我配置好了,如果我们要做批处理功能,那么批处理Batch 就会帮我们配置好。如果要做Mongodb功能 ,mongodb配置类就会帮我配置好。
在这里插入图片描述
13、有了自动配置类,免去了我们手动编写配置注入功能组件等的工作。通过自动配置类帮我处理。
那么自动配置类怎么扫描到这些呢,从哪儿得到的呢。 它是通过 getCandidateConfigurations 候选配置文件。主要调用了SpringFactoriesLoader.loadFactoryNames()。他有两个参数一个是 EnableAutoConfiguration.class, 另一个是getBeanClassLoader() 类加载器机制。
在这里插入图片描述
14、在loadFactoryNames方法中调用loadSpringFactories方法, 并通过该方法中参数classloader 类加载器来获取资源,获取资源后会把这个资源当成一个 properties配置文件,从这个配置文件中获取这个工厂的name。
在这里插入图片描述
15、获取的地方就是这个META-INF/spring.factories中获取 EnableAutoConfiguration指定的值
在这里插入图片描述
在autoConfigure中 spring.factories中 有EnableAutoConfiguration的信息,这里配置信息就是我们导入自动配置类。
在这里插入图片描述
总结下:springboot启动时候会去类路径下的META-INF/spring.factories中获取 EnableAutoConfiguration指定的值,并将这些值作为自动配置类导入到容器中去。这些自动配置类就生效了 就能帮我们进行自动配置工作。 相比我们在使用spring时需要进行xml的配置或者注解的配置。springboot中它把spring需要进行xml形式的配置简化了。所有的配置都由springboot来帮我们完成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章