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來幫我們完成。

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