Spring

一、Spring

  • Spring 是一个轻量级的Ioc容器,并支持AOP,关注点在于组件之间的解耦。
  • Spring是一个开源的Java EE应用程序框架,发起人是Rod Johnson,2003年兴起,为解决企业应用开发的复杂性而创建的,提供了强大的Ioc、AoP等功能。

1.1 Spring 包含

- Spring FrameWork
- Spring 生态系统 
1.1.1 Spring FrameWork 4个基本模块
  • Core 模块,核心,定义了容器,IoC/DI
  • Bean 模块,定义了工厂,自动装配
  • AOP 模块,面向切面编程
  • Context 模块,上下文
1.1.2 Spring FrameWork 的两个重要点
① IoC 控制反转
	IoC:把 程序中 创建组件(Java Bean、POJO)、装配组件依赖的资源的操作(权限),移交 给运行程序的 容器(Spring、Tomcat、WebLogic、WebSphere、JBoss),由容器负责 自动化完成。
	组件:使用 注解标记的普通Java类(POJO)。
	由于上述的描述不太好理解,《重构》作者Matin Flower 重命名为 DI(依赖注入)。
	
	注入的方式:
	- 构造注入
	- set方法注入
	- 接口注入
	
	企业级应用开发 分层:
	- Web、移动端、桌面、第三方接口
	- 控制层 Controller
	- 业务层 Service
	- 数据持久层 Repository
	- 数据库
	
	组件要用 @Component 注解标记,容器才会去自动管理,组件可划分3层架构,可以给组件起名字 @Component("name")
	- @Controller 控制器 :view层
	- @Service 业务逻辑 :service层
	- @Repository 持久层 :dao层
	
	组件 自动加载 @Autowired
	组件 要加载的组件 @Qualifier("name")
	组件 延迟加载 @Lazy
	组件 同类型时首先加载 @Primary
	组件 作用域 @Scope (4个)        
				- singlenton 单例(默认)         
				- prototype 原型
				- request 请求(web 环境中)
				- session 会话(web 环境中)
	  生命周期相关的注解:
	  			- PostConstruct 相当于init-method
	  			- PreDestroy 相当于destroy-method
	
	Spring MVC/Data 依赖关系:
		@Controller --依赖--> @Service --依赖--> @Repository|@Mapper|Dao --依赖--> Entity 和 Table

singlenton 单例模式的介绍请参考我另一篇文章 设计模式之单例模式
IoC的简单实现请参考我的另一篇文章 简单实现IoC

注入方式 简介

class A{
	void run(){
	}
}

class B{
	// B依赖A:例如人 生活 依赖空气、阳光、水、食物
	A a1;
	void work(){
		a1.run();
	}
}

// 非注入的方式
// B构造时,在内部创建A new()
// 需要管理 A 的生命周期
// 缺陷:B 销毁了,a1 也将不复存在,它们的生命周期同步
class B{
	// 在构造函数中初始化也一样
	A a1 = new A();
	B(){
		//a1 = new A();
	}
	void work(){
		a1.run();
	}
}

// 注入方式
// 方案1 构造方法注入
// A 的创建及生命周期与 B 分离
// 缺陷:出生时就指定好了,因为 构造方法 只执行一次
Class B{
	// 例如:伴侣、爱人
	A a1;
	B(A a){
		a1 = a;
	}
	// 例如:结婚
	void work(){
		a1.run();
	}
}

// 方案2 set方法注入
// A 的创建及生命周期与 B 分离
// 缺陷:可以动态改变依赖的对象,set方法可多次执行
class {
	A a1;
	void setA(A a){
		a1 = a;
	}
	void work(){
		a1.run();
	}
}

// 方案3 接口注入
// 早期 EJB 中的资源注入方式
// 侵入式的,让 B 必须实现某个特定的接口,类似棍棒销售,例如想购买某个东西,必须充值办卡
// 尽量避免使用 侵入式 
class B implements Xxx{
	A a1;
	
	@Override
	void other(A a){
		a1 = a;
	}
	
	void work(){
		a1.run();
	}
}
② AOP 面向切面编程
	AOP:把方法中与 核心业务、核心逻辑 无关的 流程化、模板化 的代码 提取 出来定义为 可复用的组件(切面),在 编译时 或 运行时 加入到 方法(切入点) 的 特定位置(通知)。
	
	目的:解耦、提高可复用性、提高开发效率!
	
	AOP 是 基于 动态 代理模式 实现的!
			
	- 切面:把方法中与核心业务、核心逻辑无关的流程化、模板化代码提取出来定义成可复用的组件
	- 切入点:基于注解定义的
	- 通知 [5种特定位置]
		- @Before              前置
		- @After	               后置
		- @Around              环绕
		- @AfterReturning   方法返回后
		- @AfterThrowing    异常抛出后

Java代理模式的介绍请参考我的另一篇文章 Java 三种代理模式

1.2 Java EE 发展

Java EE 规范 - 负责大型的分布式应用开发

Java EE 是一套使用Java进行企业级Web应用开发的工业标准,以前称为J2EE。

其中的核心技术规范有:

  • JDBC:Java数据库连接的API,为访问不同数据库提供统一的途径。

  • JSP:JSP页面由HTML和Java代码组成,当客户端向服务器发出页面请求后,对Java代码进行处理,然后将生成的HTML页面返回给客户端浏览器,将界面表现与业务逻辑分离开。

  • Servlet:小型的Java程序,拓展了Web服务器的功能,类似于JSP,但实现方式有所区别,JSP通常是大多数HTML代码中嵌入少量的Java代码,而Servlet全是Java代码并生成HTML。

  • EJB :一个可复用的类,包含三种类型:

     - 实体 Bean :类似MyBatis/Hibernate,但较复杂
     - 会话 Bean
     - 消息驱动 Bean:EJB容器的调用
    
1.2.1 Java EE 不足
  • Java EE 设计完备,有前瞻性,但缺陷是开发复杂、性能差、成本高,是一套重量级的解决方案。
  • Java1.8之后,官网已不再推动维护JavaEE了,逐渐由社区接手管理。
1.2.2 社区 繁荣发展

2001年左右,社区很繁荣,社区开始推动技术的进化:

  • 由于 JSP/Servlet 没有规范的流程,缺少最佳实践的标准,所以出现了Struts、WebWork

  • 由于 JDBC、EJB 中的实体 Bean 繁琐、低效,所以出现了 MyBatis、Hibernate

  • EJB 容器被Spring Framework 代替了

  • Weblogic、Webshpere、Jboss 服务器(容器),也被 Spring 中的某些特性代替了

  • SSH 集成框架

    • Struts 负责 MVC 视图相关的
    • Spring 负责 业务 解耦
    • Hibernate 负责 数据 存储
  • SSM 集成框架

    • Spring MVC 视图相关
    • Spring 业务相关
    • MyBatis 数据存储
  • Spring Boot [Java服务端开发的一站式框架]

    • Spring MVC
    • Spring Code
    • Spring Data
      • JAP Hibernate
      • MyBatis
    • Spring Security
    • 第三方框架技术

二、Spring Boot

2.1 Spring Boot 概述

Spring Boot 是一个以Spring框架为核心,集成了Spring MVC、Spring Data、Spring Security等Spring全家桶,并自动整合了其他第三方框架、进行Java服务端开发的一站式解决方案

2.2 Spring & Spring Boot

属性SpringSpring Boot
时间约20年约7年
定位IoC 容器一站式框架
范围IoC & AOP以 Spring 为核心

基于Spring Boot 可以开发

  • 单体应用(一个大应用)
  • 微服务(多个服务)

三、Spring Cloud

基于 Spring Boot 的分布式微服务开发架构

微服务把 单体应用 按 业务 切分 为多个独立开发、部署、维护的 小应用。

其主要组件有

- 注册和发现中心(基础设施)
- 负载均衡
- 路由 和 API 网关
- 分布式配置中心
- 断路器
- 日志追踪
- ...

Spring Cloud 将一个业务划分为若干个小的服务,每一个小的服务都是一个小的 Spring Boot 服务,对外提供一个网关统一的接口。

四、整合 MyBatis

ORM 对象关系映射 - 规范

简单来说就是为了不用 JDBC 那一套原始方法操作数据库。

ORM 框架

  • Hibernate 框架 [社区提供的]
  • JPA 规范 :基于Hibernate 定义的规范 [官方提供的] Java Persistent API
  • MyBatis :Java的 SQL 映射框架

对象模型 <-- 映射 --> 关系模型

说到框架,要清楚其两大功能

  • 繁琐操作 自动化
  • 通用流程 规范化

MyBatis 概述

  • SQL 映射框架
  • 早期 基于 xml 映射
  • 后期 基于 注解 映射 [在Java 5.0 注解出现后]

MyBatis 官网

测试 MyBatis

  1. 新建 Spring Starter Project
    在这里插入图片描述
  2. 选择 MySQL 驱动、MyBatis FrameWork 以及 Spring Boot 开发工具,开发工具可以加快程序的部署和更新。
    在这里插入图片描述
  3. 可以在 java 包中新建 一个 实体类 Account 和 一个接口 AccountMapper,一个实体对应一个映射。
import java.math.BigDecimal;

// 实体类Account 
public class Account {

	// 持久化时,数据库中主键字段,无需传入构造方法的参数列表
	int id;

	String name;

	BigDecimal balance;
	
	// 无参构造方法
	public Account() {
	}

	// 构造方法
	public Account(String name, BigDecimal balance) {
		super();
		this.name = name;
		this.balance = balance;
	}
	
	// getter and setter
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public BigDecimal getBalance() {
		return balance;
	}

	public void setBalance(BigDecimal balance) {
		this.balance = balance;
	}

	@Override
	public String toString() {
		return "Account [id=" + id + ", name=" + name + ", balance=" + balance + "]";
	}

}

接口记得加上注解 @Mapper,说明该接口是被 MyBatis 标记的接口,做包扫描时会被找到,其有效期是 RUNTIME。

  • 插入 @Insert("")
  • 查询 @Select("")
  • 更新 @Update("")
  • 删除 @Delete("")
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

// iBatis 原名
// MyBatis 现名

// 一个实体一个映射

@Mapper
public interface AccountMapper {

	// 基于反射获得参数所属类型中的字段 - 读取方式 #{ }
		
	/**
	 * 把 对象 持久化 为 表中的 一条记录
	 * @param account 要持久化的实体对象
	 */
	@Insert("insert into account(name,balance) values(#{name},#{balance})")
	void save(Account account);
	
	// 基于反射 会创建一个返回值类型的对象,使用查询获得的结果集自动去填充对象
	@Select("select id,name,balance from account where id=#{id} order by balance desc")
	Account findById(int id);
	
	@Select("select id,name,balance from account order by balance desc")
	List<Account> findAll();
	
	@Update("update account set balance=#{balance} where id=#{id}")
	void update(Account account);
	
	@Delete("delete from account where id=#{id}")
	void deleteById(int id);
}

4.同理,再新建一个实体类 Dept 和 一个映射接口 DeptMapper。

/**
 * 实体类
 *
	 +-------+----------+------+-----+---------+----------------+
	| Field | Type     | Null | Key | Default | Extra          |
	+-------+----------+------+-----+---------+----------------+
	| id    | int      | NO   | PRI | NULL    | auto_increment |
	| name  | char(16) | YES  |     | NULL    |                |
	| loc   | char(16) | YES  |     | NULL    |                |
	+-------+----------+------+-----+---------+----------------+
 */
public class Dept {

	int id;
	
	String title;  // 对应表中字段 name
	
	String city;   // 对应表中字段 loc
	
	public Dept() {
	}

	public Dept(String title, String city) {
		super();
		this.title = title;
		this.city = city;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	@Override
	public String toString() {
		return "Dept [id=" + id + ", title=" + title + ", city=" + city + "]";
	}

}

如果表中的列名和类中的属性名不一致时,需要进行结果集映射 @Results,用{ }包起多个结果映射 @Rusult,多个方法需要用到映射时,可以将映射提取出来,起个名 id,需要用到映射的地方加上注解@ResultMap(" id ") 即可。

import java.util.List;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface DeptMapper {

	@Insert("insert into dept(name,loc) values(#{title},#{city})")
	void save(Dept dept);

	// 表的列名和类中的属性名不一致,需要通过注解进行映射
	// 映射表中的 列column 与类中的 字段property
	// 重复用到时,可以提取出来,id 就是它的名字
	@Results(
			id = "deptResult", 
			value = { 
					@Result(column = "name", property = "title"),
					@Result(column = "loc", property = "city"), 
					@Result(column = "id", property = "id") 
					})
	@Select("select id,name,loc from dept")
	List<Dept> findAll();

	@Select("select id,name,loc from dept where id=#{id}")
	@ResultMap("deptResult")
	Dept findById(int id);
	
}
  1. 在 resources 包下,打开application配置文件,配置数据源。
# 数据源 - 数据库连接
# URL
spring.datasource.url=jdbc:mysql://ip地址:端口号/数据库?serverTimezone=UTC
# 用户名
spring.datasource.username=用户名
# 密码
spring.datasource.password=密码
# 驱动类的名字,java 8 以上的版本使用 cj
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  1. 在 Application 类中新建一个返回命令行运行CommandLineRunner的方法,记得加注解 @Bean ,声明为一个Bean组件,方法才会被自动调用。
import java.math.BigDecimal;
import java.util.List;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

// Spring Boot 
@SpringBootApplication
public class OrmApplication {

	public static void main(String[] args) {
		SpringApplication.run(OrmApplication.class, args);
	}
	
	// 命令行执行,加上注解Bean!!!
	@Bean
	public CommandLineRunner a(BeanFactory factory) {
		
		return new CommandLineRunner() {
			
			@Override
			public void run(String... args) throws Exception {
				
				// 从组件工厂获得组件,基于工厂模式
				// 工厂模式参考我的另一篇文章 设计模式 会有介绍 
				DeptMapper mapper = factory.getBean(DeptMapper.class);
				
//				mapper.save(new Dept("研发","长沙"));
//				mapper.save(new Dept("测试","湘潭"));
//				mapper.save(new Dept("运维","广州"));
//				System.out.println("save");
				
				List<Dept> list = mapper.findAll();
				for (Dept dept : list) {
					System.out.println(dept);
				}
				
				System.out.println(mapper.findById(1));
				System.out.println(mapper.findById(2));
				
			}
		};
	}
	
	@Bean
	public CommandLineRunner b(BeanFactory factory) {
		return new CommandLineRunner() {
			
			@Override
			public void run(String... args) throws Exception {
				// 从组件工厂获得一个组件
				AccountMapper mapper =  factory.getBean(AccountMapper.class);
				
//				mapper.save(new Account("ORM", BigDecimal.valueOf(100000)));
//				System.out.println("save");
				
				List<Account> list =  mapper.findAll();
				for (Account account : list) {
					System.out.println(account);
				}
				
				Account account = mapper.findById(6);
				System.out.println(account);
				
//				mapper.deleteById(9);
//				System.out.println("delete");
			
			}
		};
	}

}

点击运行,Run As Spring Boot App,查看控制台输出结果
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值