Spring全家桶之Spring

在这里插入图片描述

Spring全家桶

学习官网:https://spring.io/

第一章 Spring5框架

Spring Framework Documentation

https://docs.spring.io/spring-framework/docs/current/reference/html/index.html

1.1 Spring 框架概述

/*
1、Spring是轻量级的开源的JavaEE框架
2、Spring可以解决企业应用开发的复杂性
3、Spring有两个核心部分:IOC和AOP
(1)IOC:控制反转,把创建对象过程交给Spring进行管理
(2)AOP:面向切面,不修改源代码进行功能增强
4、Spring特点
(1)方便解耦,简化开发
(2)AOP编程支持
(3)方便程序测试
(4)方便和其他框架进行整合
(5)方便进行事务操作
(6)降低API开发难度
*/

入门案例

第一步 下载Spring5,选取最新稳定版—5.3.8

https://repo.spring.io/release/org/springframework/spring/
在这里插入图片描述
第二步 创建java工程,并导入Spring相关JAR包
在这里插入图片描述
第三步 创建类和方法

User.java

public class User {
    public void add(){
        System.out.println("add...");
    }
}

第四步 创建Spring配置文件bean1.xml,并创建对象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置User对象创建-->
    <bean id="user" class="edu.mm.User"></bean>
</beans>

第五步 测试

@Test
public void testAdd(){
    
    
//1.加载spring配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2.获取通过配置文件创建的对象
User user = context.getBean("user", User.class);
System.out.println(user);
user.add();
}

运行截图:
在这里插入图片描述

1. 2 IOC 容器

1.2.1 IOC概念

(1)IOC,控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理。

(2)使用 IOC目的:为了降低耦合度 。

1.2.2 IOC 底层原理

关键字:xml 解析、工厂模式、反射

需求:创建UserService.java和UserDao.java,希望在service层调用dao层的某个方法。

IOC过程

第一步:通过xml配置文件,创建对象。

<bean id="" class=""></bean>

第二步:创建工厂类

class UserFactory{
    
    
    public static UserDao getDao(){
    
    
        String classValue=class属性值;//1.xml解析(基于Dom4j),获取全类名
        Class clazz=Class.forName(classValue);//2.通过反射创建对象
        return (UserDao)clazz.newInstance();
    }
}

第三步:在service层通过工厂模式来创建对象

class UserService{
    
    
    public void excute(){
    
    
        UserDao dao=UserFactory.getDao();
        dao.add();
    }
}

原始方法 new关键字 缺点:耦合度太高

UserDao.java

class UserDao{
    
    
    public void add(){
    
    
        ...
    }
}

UserService.java

class UserService{
    
    
    UserDao userDao=new UserDao();
    userDao.add();
}   

工厂模式 工厂类作为中间件,来降低service层和dao层的耦合度。

UserFactory.java

class UserFactory{
    
    
    public static UserDao getDao(){
    
    
        return new UserDao();
    }
}

UserService.java

class UserService{
    
    
    public void excute(){
    
    
        UserDao dao=UserFactory.getDao();
        dao.add();
    }
}

1.2.3 IOC 接口(BeanFactory)

  • IOC 思想基于 IOC 容器,IOC 容器底层就是对象工厂

  • Spring 提供 IOC 容器的两种方式(两个接口)

    • BeanFactory

      IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
      *加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象 
      
    • ApplicationContext

      BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用 
      *加载配置文件时候就会把在配置文件对象进行创建
      

1.2.4 IOC 操作 Bean管理(基于 xml)

IOC操作Bean管理包括:Spring创建对象和注入属性。

Bean 管理操作有两种方式:xml、注解

  • 基于 xml 方式创建对象

     <bean id="user" class="edu.mm.User"></bean>
    

    【注意】

    (1)在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建

    (2)在 bean 标签有很多属性,常用的属性如下

    ​ id 属性:唯一标识

    ​ class 属性:类全路径(包类路径)

    (3)创建对象时候,默认是执行无参数构造方法完成对象创建

  • 基于 xml 方式注入属性

    /*DI:依赖注入,就是注入属性*/
    
    • 使用 set 方法进行注入

      第一步:创建实体类,定义属性和对应的set方法

      public class User {
              
              
          public String name;
          public String stumum;
          public void setName(String name) {
              
              
              this.name = name;
          }
          public void setStumum(String stumum) {
              
              
              this.stumum = stumum;
          }
      }
      
      

      第二步:在spring配置文件中创建对象,注入属性

       <!--使用property属性注入  name:类里面属性名称  value:向属性注入的值-->
      <bean id="user" class="edu.mm.User">
              <property name="name" value="java"></property>
              <property name="stumum" value="171404050119"></property>
      </bean>
      
    • 使用有参数的构造函数进行注入

      第一步:创建类、属性,创建有参数的构造函数

      public class Book {
              
              
          public String bName;
          public String author;
          public Book(String bName, String author) {
              
              
              this.bName = bName;
              this.author = author;
          }
      }
      
      

      第二步:在 spring 配置文件中进行配置

      <bean id="book" class="edu.mm.Book">
              <constructor-arg name="author" value="屈原"></constructor-arg>
              <constructor-arg name="bName" value="楚辞"></constructor-arg>
      </bean>
      

      第三步:测试

       @Test
      public void testBook(){
              
              
      //1.加载spring配置文件
      ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
      //2.获取通过配置文件创建的对象
      Book book = context.getBean("book", Book.class);
      System.out.println(book.bName);
      }
      
  • 基于xml 注入其他类型属性

    • 注入属性—外部bean

      /*
      (1)创建两个类service类和dao类
      (2)在service调用dao里面的方法
      (3)在spring配置文件中进行配置
      */
      public class UserService {
              
              
          public UserDao userDao;
          public void setUserDao(UserDao userDao) {
              
              
              this.userDao = userDao;
          }
          public void show(){
              
              
              userDao.showInfo();
              System.out.println("I am service");
          }
      }
      
      <!--注入userDao对象  name属性:类里面属性名称  ref属性:创建userDao对象bean标签id值-->
      <bean id="userService" class="edu.mm.service.UserService">
              <property name="userDao" ref="userDao"></property>
      </bean>
      <bean id="userDao" class="edu.mm.dao.UserDao"></bean>
      
    • 注入属性—内部bean

      /*
      一对多关系:部门和员工
      在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
      */
      public class Dept {
              
              
          public String dName;
      
          public void setdName(String dName) {
              
              
              this.dName = dName;
          }
      }
      
      public class Emp {
              
              
          public String empName;
          public String empGender;
          public Dept dept;//员工属于某一个部门,使用对象形式表示
          public void setEmpName(String empName) {
              
              
              this.empName = empName;
          }
          public void setEmpGender(String empGender) {
              
              
              this.empGender = empGender;
          }
          public void setDept(Dept dept) {
              
              
              this.dept = dept;
          }
      }
      
      <bean id="emp" class="edu.mm.bean.Emp">
              <property name="empName" value="李白"></property>
              <property name="empGender" value=""></property>
              <property name="dept">
                  <bean id="dept" class="edu.mm.bean.Dept">
                      <property name="dName" value="保卫科"></property>
                  </bean>
              </property>
      </bean>
      
    • 注入属性—级联赋值

      方式一:

      <bean id="emp" class="edu.mm.bean.Emp">
           <!--设置两个普通属性-->
           <property name="empName" value="李白"></property>
           <property name="empGende" value=""></property>
           <!--级联赋值-->
           <property name="dept" ref="dept"></property>
      </bean>
      <bean id="dept" class="edu.mm.bean.Dept">
           <property name="dName" value="保卫科"></property>
      </bean>
      
      

      方式二:

      <!--前提:Emp实体类要有getDept()-->
      <bean id="emp" class="edu.mm.dao.Emp">
              <property name="empName" value="李白"></property>
              <property name="empGender" value=""></property>
              <property name="dept" ref="dept"></property>
              <property name="dept.dName" value="保卫科"></property>
          </bean>
      <bean id="dept" class="edu.mm.dao.Dept"></bean>
      
    • 注入属性—集合属性

      1、注入数组类型属性

      2、注入 List 集合类型属性

      3、List集合注入对象属性

      4、注入 Map 集合类型属性

      5、注入Set 集合类型属性

      public class Stu {
              
              
       //1 数组类型属性
       private String[] courses;
       //2 List集合类型属性
       private List<String> list;
       //3 List集合注入对象属性
       private List<Course> courseList;
       //4 Map 集合类型属性
       private Map<String,String> maps;
       //5 Set 集合类型属性
       private Set<String> sets;
      
       public void setSets(Set<String> sets) {
              
              
       this.sets = sets;
       }
       public void setCourses(String[] courses) {
              
              
       this.courses = courses;
       }
       public void setList(List<String> list) {
              
              
       this.list = list;
       }
       public void courseList(List<Course> courseList) {
              
              
       this.courseList = courseList;
       }  
       public void setMaps(Map<String, String> maps) {
              
              
       this.maps = maps;
       }
      }
      
      <!--集合类型属性注入-->
      <bean id="stu" class="edu.mm.bean.Stu">
           <!--1.数组类型属性注入-->
           <property name="courses">
              <array>
                  <value>java 课程</value>
                  <value>数据库课程</value>
              </array>
           </property>
           <!--2.list类型属性注入-->
           <property name="list">
              <list>
                 <value>张三</value>
                 <value>小三</value>
              </list>
           </property>
          <!--3.List集合中注入对象属性-->
          <property name="courseList">
             <list>
                <ref bean="course1"></ref>
                <ref bean="course2"></ref>
             </list>
          </property>
           <!--4.map类型属性注入-->
           <property name="maps">
              <map>
                 <entry key="JAVA" value="java"></entry>
                 <entry key="PHP" value="php"></entry>
              </map>
           </property>
           <!--5.set类型属性注入-->
           <property name="sets">
              <set>
                 <value>MySQL</value>
                 <value>Redis</value>
              </set>
           </property>
      </bean>
      <bean id="course1" class="edu.mm.bean.Course">
       <property name="cname" value="Spring5 框架"></property>
      </bean>
      <bean id="course2" class="edu.mm.bean.Course">
       <property name="cname" value="MyBatis 框架"></property>
      </bean>
      
  • FactoryBean

    1、Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)

    2、普通 bean:在配置文件中定义 bean 类型就是返回类型

    3、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样

    ​ 第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean

    ​ 第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型

  • IOC 操作 Bean 管理(bean 作用域)

    /*
    在Spring中,默认情况下,bean 是单实例对象
    
    (1)在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
    (2)scope 属性值
               第一个值 默认值,singleton,表示是单实例对象
               第二个值 prototype,表示是多实例对象
    (3)singleton 和 prototype 区别
        第一,singleton单实例,prototype多实例
        第二,scope=singleton,加载spring配置文件时创建单实例对象
             scope=prototype,在调用getBean方法时创建多实例对象
    */
    
  • IOC 操作 Bean 管理(bean 生命周期)

    /*bean 生命周期:
    (1)通过构造器创建 bean 实例(无参数构造)
    (2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
    (3)调用 bean 的初始化的方法(需要进行配置初始化的方法)
    (4)使用bean(对象获取到了)
    (5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
    */
    
  • IOC 操作 Bean 管理(xml 自动装配)

    根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入

    <!--实现自动装配
     bean标签属性 autowire,配置自动装配
     autowire 属性常用两个值:
     byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样
     byType 根据属性类型注入
    -->
    

1.2.5 IOC 操作 Bean 管理(基于注解)

  • 注解的含义

    (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)

    (2)使用注解,注解作用在类、方法、属性上面

    (3)使用注解目的:简化 xml 配置

  • 针对 Bean 管理中创建对象Spring提供以下注解

    (1)@Component

    (2)@Service

    (3)@Controller

    (4)@Repository

    上面四个注解功能是一样的,都可以用来创建 bean 实例

  • 基于注解方式实现对象创建

    • 第一步:引入依赖 spring-aop-5.3.8.jar

    • 第二步:开启组件扫描

       <!--开启组件扫描 1、如果扫描多个包,多个包使用逗号隔开 ;2、扫描包上层目录-->
      <context:component-scan base-package="edu.mm"></context:component-scan>
      
    • 第三步:创建类,在类上面添加创建对象注解

      /*在注解里面value属性值可以省略不写,默认值是类名称,首字母小写*/
      
  • 基于注解方式实现属性注入

    • @Autowired:根据属性类型进行自动装配

    • @Resource:默认根据类型注入,也可以根据名称注入

    • @Value:注入普通类型属性

    • @Qualifier:根据名称进行注入

      @Qualifier和@Autowired 一起使用

  • 完全注解开发

    第一步:创建配置类,替代 xml 配置文件

    @Configuration
    @ComponentScan(basePackages = "edu.mm")
    public class SpringConfig {
          
          
    ....
    }
    

    第二步:编写测试类

    @Test
    public void testService2() {
          
          
     //加载配置类
     ApplicationContext context
     = new AnnotationConfigApplicationContext(SpringConfig.class);
     UserService userService = context.getBean("userService",UserService.class);
     System.out.println(userService);
     userService.add();
    }
    

1.3 AOP

1.3.1 AOP概念

面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得 业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率,简单来说,就是不通过修改源代码方式,在主干功能里面添加新功能。

1.3.2 AOP底层原理

AOP 底层使用动态代理来实现,包括:JDK动态代理和CGLIB动态代理。

  • JDK 动态代理—有接口
/*创建接口实现类代理对象,增强类的方法*/
  • CGLIB 动态代理—没接口

    /*创建子类的代理对象,增强类的方法*/
    

1.4 JdbcTemplate

Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作。

步骤:

第一步:准备工作

(1)引入相关jar包

  • druid-1.1.9.jar

  • mysql-connector-java-5.1.7-bin.jar

  • spring-jdbc-5.3.8.jar

  • spring-orm-5.3.8.jar

  • spring-tx-5.3.8.jar

(2)创建数据库

/*
Navicat MySQL Data Transfer

Source Server         : hh
Source Server Version : 80023
Source Host           : localhost:3306
Source Database       : school

Target Server Type    : MYSQL
Target Server Version : 80023
File Encoding         : 65001

Date: 2021-07-05 11:59:40
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `sno` char(10) NOT NULL,
  `sname` char(20) DEFAULT NULL,
  `ssex` char(2) DEFAULT NULL,
  `sage` smallint DEFAULT NULL,
  `sdept` char(20) DEFAULT NULL,
  PRIMARY KEY (`sno`),
  UNIQUE KEY `sname` (`sname`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('100256', '刘晨', '男', '19', 'IS');
INSERT INTO `student` VALUES ('1114', '马修', '男', '20', 'CS');
INSERT INTO `student` VALUES ('171145', '屈明明', '男', '15', 'CS');
INSERT INTO `student` VALUES ('1714', '李白', '男', '100', '九三学社');
INSERT INTO `student` VALUES ('178963', '张力', '女', '18', 'MA');

(3)在 spring 配置文件配置数据库连接池

方式一:直接配置数据库连接池

     <!--组件扫描-->
    <context:component-scan base-package="edu.mm"></context:component-scan>
    <!--配置数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql:///school?useUnicode=true&characterEncoding=utf8"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>

方式二:spring.xml读取dbConfig.properties文件来配置数据库连接池

dbConfig.properties

jdbc.user=root
jdbc.password=123456
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8
jdbc.driverClass=com.mysql.jdbc.Driver

spring.xml

    <!--引入外部配置文件-->
    <context:property-placeholder location="classpath:dbConfig.properties">                   </context:property-placeholder>
    <!--组件扫描-->
    <context:component-scan base-package="edu.mm"></context:component-scan>
    <!--配置数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.jdbcUrl}"></property>
        <property name="username" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClassName" value="${jdbc.driverClass}"></property>
    </bean>

(4)配置 JdbcTemplate 对象,注入 DataSource

    <!--创建JdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

第二步:编写代码,使用JdbcTemplate 操作数据库

调用 JdbcTemplate 对象里面 update ()、queryForObject(),实现增、删、改、查操作

以插入一条数据为例:

@Test
    public void test1(){
    
    
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
        //1.创建sql语句
        String sql="insert into student values(?,?,?,?,?)";
        Student student=new Student();
        student.setSno("1714");
        student.setSname("李白");
        student.setSage(100);
        student.setSsex("男");
        student.setSdept("九三学社");
        //2.调用方法实现
        Object[] args={
    
    student.getSno(),student.getSname(),student.getSsex(),student.getSage(),student.getSdept()};
        int ret = jdbcTemplate.update(sql, args);
        System.out.println(ret);
    }

在这里插入图片描述
补充:

/*
param1:sql语句
param2:可变参数,sql语句的值
*/
int update(String sql, @Nullable Object... args);

/*添加一条数据*/
String sql = "insert into t_book values(?,?,?)";
Object[] args = {
    
    book.getUserId(), book.getUsername(), book.getUstatus()};
/*修改一条数据*/
String sql = "update t_book set username=?,ustatus=? where user_id=?";
Object[] args = {
    
    book.getUsername(), book.getUstatus(),book.getUserId()};
/* 删除一条数据*/
String sql = "delete from t_book where user_id=?";


/*
param1:sql语句
param:返回类型Class
*/
String sql = "select count(*) from t_book";//查询表的记录数
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);//查询返回某个值


/*
param1:sql 语句
param2:RowMapper 是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装
param3:sql语句值
*/
String sql = "select * from t_book where user_id=?";//查询返回对象
Book book = jdbcTemplate.queryForObject(sql, new 
BeanPropertyRowMapper<Book>(Book.class), id);//查询返回对象


/*
param1:sql 语句
param2:RowMapper 是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装
*/
String sql = "select * from t_book";//查询返回集合
List<Book> bookList = jdbcTemplate.query(sql, new 
BeanPropertyRowMapper<Book>(Book.class));//查询返回集合

第三步:解决bug
在这里插入图片描述
当你在测试类中使用到@Autowired自动注入时,会报以上错误

解决方案:在测试类上方加上@RunWith(SpringRunner.class)注解

原因:有了@RunWith(SpringRunner.class)这些类才能实例化到spring容器中,自动注入才能生效不然直接一个NullPointerExecption

1.5 事务管理

事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败。

在 Spring 进行事务管理时,使用声明式事务管理,最常用的是基于注解方式,使用@Transactiona注解将事物添加到Service层,底层基于AOP,通过PlatformTransactionManager接口来进行事务管理。

事物的4个特性:原子性、一致性、隔离性、持久性

典型场景:银行转账

1.6 Spring5 新特性

(1)整合日志框架

(2)@Nullable 注解

(3)函数式注册对象

(4)整合 JUnit5 单元测试框架

(5)SpringWebflux 使用

猜你喜欢

转载自blog.csdn.net/weixin_44490884/article/details/118486747