Spring Boot原理分析之简单示例

Spring Boot背景

Spring每集成一个开源软件,就需要增加一些基础配置,随着开发项目的逐渐庞大,往往需要集成很多开源软件。后期使用 Spring 开发大型项目需要引入很多配置文件,导致配置工作难以维护和理解,在集成开源软件的同时,maven pom xml中引入不同版本的jar包,还会存在版本冲突的情况。
Spring Boot的目标之一就是实现免 XML 配置的开发体验。
Spring 最初核心的两大核心功能 Spring IoC 和 Spring Aop 成就了 Spring,Spring 在这两大核心功能上不断地发展,才有了 Spring 事务、Spring MVC 等一系列伟大的产品,最终成就了 Spring 帝国,Spring Boot 是在强大的 Spring 帝国生态基础上面发展而来,发明 Spring Boot 不是为了取代 Spring,是为了让人们更容易的使用 Spring。

Spring Ioc/Aop > Spring > Spring Boot

本文使用spring和mybatis整合为例,分别使用两种配置,一种是传统的xml文件和属性文件配置项目,一种是spring boot自动配置项目的方式,两种方式进行对比,从项目配置上看看差别。

项目文件

不管是xml配置项目,还是自动配置,和业务相关的文件,是不变的。

表结构

CREATE TABLE `t_auth_user` (
  `id` bigint(16) NOT NULL AUTO_INCREMENT,
  `user_account` varchar(64) NOT NULL COMMENT '账号',
  `password` varchar(255) NOT NULL COMMENT '密码',
  `is_delete` tinyint(1) DEFAULT '0' COMMENT '删除标识0:未删除,1:已删除',
  `nickname` varchar(64) DEFAULT NULL COMMENT '昵称',
  `remark` varchar(64) DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

mapper xml

mybatis映射文件spring-boot-source-read/src/main/resources/mappers/AuthUserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.spboot.read.mapper.AuthUserMapper">
    <resultMap id="BaseResultMap" type="com.spboot.read.beans.AuthUser">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <result column="user_account" property="userAccount" jdbcType="VARCHAR"/>
        <result column="password" property="password" jdbcType="VARCHAR"/>
        <result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
        <result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
        <result column="is_delete" property="isDelete" jdbcType="TINYINT"/>
    </resultMap>
    <sql id="Base_Column_List">
        id, user_account, password, create_time, update_time, is_delete
    </sql>
    <select id="query" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from t_auth_user
        where user_account = #{userAccount}
    </select>
</mapper>

AuthUserMapper.java

接口AuthUserMapper.java

package com.spboot.read.mapper;

import com.spboot.read.beans.AuthUser;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface AuthUserMapper {
    List<AuthUser> query(String userAccount);
}

AuthUser

实体类AuthUser.java

package com.spboot.read.beans;

import java.util.Date;
public class AuthUser {
    private Long id;
    private String userAccount;
    private String password;
    private Date createTime;
    private Date updateTime;
    private Byte isDelete;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getUserAccount() {
        return userAccount;
    }
    public void setUserAccount(String userAccount) {
        this.userAccount = userAccount == null ? null : userAccount.trim();
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }
    public Date getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    public Date getUpdateTime() {
        return updateTime;
    }
    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
    public Byte getIsDelete() {
        return isDelete;
    }
    public void setIsDelete(Byte isDelete) {
        this.isDelete = isDelete;
    }
}

服务类

package com.spboot.read.service;

import com.spboot.read.beans.AuthUser;
import java.util.List;
public interface IAuthUserService {
	List<AuthUser> query(String userAccount);
}

package com.spboot.read.service.impl;

import com.spboot.read.beans.AuthUser;
import com.spboot.read.mapper.AuthUserMapper;
import com.spboot.read.service.IAuthUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.*;
@Service
public class AuthUserServiceImpl implements IAuthUserService {
	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	@Resource
	private AuthUserMapper authUserMapper;
	public AuthUserServiceImpl(){
		logger.info("创建 com.test.bean.AuthUserServiceImpl");
	}
	@Override
	public List<AuthUser> query(String userAccount) {
		if(StringUtils.isEmpty(userAccount)){
			return null;
		}
		return authUserMapper.query(userAccount);
	}
}

Spring+XML配置

先看看项目的整体目录结构
在这里插入图片描述

pom文件

<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>com.sp.source.read</groupId>
	<artifactId>spring-souce-read</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<spring.version>4.2.0.RELEASE</spring.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.8.6</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.6</version>
		</dependency>
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.9.2</version>
			<exclusions>
				<exclusion>
					<artifactId>commons-logging</artifactId>
					<groupId>commons-logging</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>1.10</version>
		</dependency>
		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>3.2.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.2.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.0.27</version>
		</dependency>
		<!-- mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.2.5</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.38</version>
		</dependency>
		<!-- mybatis-spring 整合 -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.2.2</version>
		</dependency>
		<!-- Spring Jdbc 的支持 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>4.2.0.RELEASE</version>
		</dependency>
		<!-- logger -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-api</artifactId>
			<version>2.5</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>2.5</version>
		</dependency>
		<!-- 格式化对象,方便输出日志 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.16</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

属性配置

application.properties,存放在resources目录下

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=utf8&amp;allowMultiQueries=true
jdbc.username=****
jdbc.password=****
jdbc.validationQuery=SELECT 1

bean配置

spring-config.xml,存放在resources目录下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 加载配置文件 -->
    <context:property-placeholder location="classpath:application.properties"/>
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <context:component-scan base-package="com.sp.source.read"/>
    <bean id="dbCommProperty" abstract="true">
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="5"/>
        <!-- 连接池最大使用连接数量 -->
        <property name="maxActive" value="5"/>
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="5"/>
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="60000"/>
        <property name="validationQuery" value="${jdbc.validationQuery}"/>
        <property name="testOnBorrow" value="false"/>
        <property name="testOnReturn" value="false"/>
        <property name="testWhileIdle" value="true"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="25200000"/>
        <!-- 打开removeAbandoned功能 -->
        <property name="removeAbandoned" value="true"/>
        <!-- 1800秒,也就是30分钟 -->
        <property name="removeAbandonedTimeout" value="1800"/>
        <!-- 关闭abanded连接时输出错误日志 -->
        <property name="logAbandoned" value="true"/>
    </bean>
    <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close" parent="dbCommProperty">
        <property name="url"
                  value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
    </bean>
    <!-- 配置 SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 加载数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath*:mappers/*Mapper.xml"/>
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 指定扫描的包,如果存在多个包使用(逗号,)分割 -->
        <property name="basePackage" value="com.sp.source.read"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>
    <!-- 配置事物管理器 TransactionManager -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <tx:advice id="interceptorAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
            <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="query*" propagation="SUPPORTS"/>
        </tx:attributes>
    </tx:advice>
    <!-- 配置切面 aop -->
    <aop:config>
        <aop:pointcut id="transactionPointcut" expression="execution(* com.test.service.*.*(..))"/>
        <aop:advisor pointcut-ref="transactionPointcut" advice-ref="interceptorAdvice"/>
    </aop:config>
</beans>

日志配置

log4j.xml,存放在resources目录下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration>
    <!-- 控制台的日志记录 -->
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%p][%d{yyyy-MM-dd HH\:mm\:ss}][%c][%m]%n" />
        </layout>
    </appender>
    <root>
        <priority value="debug" />
        <appender-ref ref="console" />
    </root>
</log4j:configuration>

测试类

创建一个测试类,测试spring和mybatis整合

package com.sp.source.read.service;

import com.alibaba.fastjson.JSON;
import com.sp.source.read.bean.AuthUser;
import com.sp.source.read.service.impl.AuthUserServiceImpl;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AuthUserServiceImplTest {
    private static Logger logger = Logger.getLogger(AuthUserServiceImplTest.class);
    
    public static void main(String[] args){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
        IAuthUserService authUserServiceImpl = ctx.getBean(AuthUserServiceImpl.class);
        Map<String,Object> params = new HashMap<>();
        params.put("userAccount","user002");
        AuthUser authUser = new AuthUser();
        authUser.setUserAccount("user002");
        authUser.setId((long) 4);
        List<AuthUser> authUserList = authUserServiceImpl.query(params);
        logger.info("执行结果:"+ JSON.toJSONString(authUserList));
    }
}

执行结果:

[INFO][2020-07-07 20:26:33][AuthUserServiceImplTest][执行结果:[
{
    "createTime":1548162759000,
    "id":4,
    "isDelete":0,
    "password":"dd9b254be95d548383d9616307f9c73f",
    "updateTime":1556876038000,
    "userAccount":"user002"
}
]]

Spring Boot自动配置

先看看项目的整体目录结构
在这里插入图片描述

pom文件

<?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>spring-boot-source-read</groupId>
    <artifactId>com.spboot.read</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>Spring Boot 源码研读项目</name>
    <description>Spring Boot 源码研究</description>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

spring-boot-starter-xxx是官方提供的starter,xxx-spring-boot-starter是第三方提供的starter。

属性配置

application.yml,放到resources目录下

spring:
  profiles:
    active: dev

application-dev.yml,放到resources目录下

server:
  port: 8080

spring:
  datasource:
    username: ****
    password: ****
    url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
    driver-class-name: com.mysql.jdbc.Driver

mybatis:
  mapper-locations: classpath:mappers/*Mapper.xml
  type-aliases-package: com.spboot.read.beans

#日志
logging:
  config: classpath:logback-spring.xml
  level:
    root: info

日志配置

logback-spring.xml,放到resources目录下

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
    <contextName>logback</contextName>
    <!--输出到控制台-->
    <appender name="stdoutAppender" class="ch.qos.logback.core.ConsoleAppender">
        <target>System.out</target>
        <encoder>
            <pattern>[%p][%d{yyyy-MM-dd HH:mm:ss}][%c %L][%m]%n</pattern>
        </encoder>
    </appender>
    <root>
        <appender-ref ref="stdoutAppender" />
    </root>
</configuration>

项目入口类

package com.spboot.read;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 项目启动入口
 */
@MapperScan("com.spboot.read.mapper")
@SpringBootApplication
public class SpBootReadApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpBootReadApplication.class, args);
    }
}

Controller

控制类,提供一个http地址,查询数据库表中记录

package com.spboot.read.controller;
import com.spboot.read.beans.AuthUser;
import com.spboot.read.service.IAuthUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/authUser/")
public class UserController {
    private static Logger logger = LoggerFactory.getLogger(UserController.class);
    @Resource
    private IAuthUserService authUserService;
    @RequestMapping("query/{userAccount}")
    public List<AuthUser> query(@PathVariable String userAccount) {
        logger.info("请求参数userAccount:{}", userAccount);
        Assert.notNull(userAccount, "账号不能为空");
        List<AuthUser> userList = authUserService.query(userAccount);
        return userList;
    }
}

IDEA启动配置

创建一个spring boot项目启动配置,Main class选择项目的入口类
在这里插入图片描述
浏览器访问地址:

http://localhost:8080/authUser/query/user002

返回结果:

[
    {
        "id":4,
        "userAccount":"user002",
        "password":"dd9b254be95d548383d9616307f9c73f",
        "createTime":"2019-01-22T13:12:39.000+00:00",
        "updateTime":"2019-05-03T09:33:58.000+00:00",
        "isDelete":0
    }]

参考
Spring Boot 产生的背景和它的设计理念

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值