Spring的学习

一、框架 = jar包+配置文件

广义的 Spring:Spring 技术栈(全家桶)是指以 Spring Framework 为基础的 Spring 技术栈。经过十多年的发展,Spring 已经不再是一个单纯的应用框架,而是逐渐发展成为一个由多个不同子项目(模块)组成的成熟技术,例如 Spring Framework、Spring MVC、SpringBoot、Spring Cloud、Spring Data、Spring Security 等,其中 Spring Framework 是其他子项目的基础。

狭义的 Spring:Spring Framework(基础框架)

狭义的 Spring 特指 Spring Framework,通常我们将它称为 Spring 框架。

Spring Framework是一个开源的应用程序框架,提供了很多功能,例如:依赖注入(Dependency Injection)、面向切面编程(AOP)、声明式事务管理(TX)等。其主要目标是使企业级应用程序的开发变得更加简单和快速,并且Spring框架被广泛应用于Java企业开发领域。

Spring全家桶的其他框架都是以SpringFramework框架为基础!

对比理解:

QQ 和 腾讯

腾讯 = Spring

QQ = SpringFramework

功能模块功能介绍
Core Container核心容器,在 Spring 环境下使用任何功能都必须基于 IOC 容器。
AOP&Aspects面向切面编程
TX声明式事务管理。
Spring MVC提供了面向Web应用程序的集成功能。

 二、Spring loC 容器与核心概念

2.1组件

组件即可以复用的java对象

 组件可以完全交给Spring 框架进行管理,Spring框架替代了程序员原有的new对象和对象属性赋值动作等!

Spring IoC 容器:负责实例化、配置和组装 bean(组件)。容器通过读取配置元数据来获取有关要实例化、配置和组装组件的指令。配置元数据以 XML、Java 注解或 Java 代码形式表现。它允许表达组成应用程序的组件以及这些组件之间丰富的相互依赖关系。

2.2、SpingloC容器具体接口和实现类

 BeanFactory---->ApplicationContext    如下表格

类型名简介
ClassPathXmlApplicationContext通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
FileSystemXmlApplicationContext通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象
AnnotationConfigApplicationContext通过读取Java配置类创建 IOC 容器对象
WebApplicationContext专门为 Web 应用准备,基于 Web 环境创建 IOC 容器对象,并将对象引入存入 ServletContext 域中。

2.3、SpringIoC容器管理配置方式

  Spring IoC 容器使用多种形式的配置元数据。此配置元数据表示作为应用程序开发人员如何告诉 Spring 容器实例化、配置和组装应用程序中的对象。

  Spring框架提供了多种配置方式:XML配置方式、注解方式和Java配置类方式

  1. XML配置方式:是Spring框架最早的配置方式之一,通过在XML文件中定义Bean及其依赖关系、Bean的作用域等信息,让Spring IoC容器来管理Bean之间的依赖关系。该方式从Spring框架的第一版开始提供支持。
  2. 注解方式:从Spring 2.5版本开始提供支持,可以通过在Bean类上使用注解来代替XML配置文件中的配置信息。通过在Bean类上加上相应的注解(如@Component, @Service, @Autowired等),将Bean注册到Spring IoC容器中,这样Spring IoC容器就可以管理这些Bean之间的依赖关系。
  3. Java配置类方式(主流):从Spring 3.0版本开始提供支持,通过Java类来定义Bean、Bean之间的依赖关系和配置信息,从而代替XML配置文件的方式。Java配置类是一种使用Java编写配置信息的方式,通过@Configuration、@Bean等注解来实现Bean和依赖关系的配置。

2.4总结
2.4.1、IoC容器

  Spring IoC 容器,负责实例化、配置和组装 bean(组件)核心容器。容器通过读取配置元数据来获取有关要实例化、配置和组装组件的指令。

2.4.2、IoC(Inversion of Control)控制反转

  IoC 主要是针对对象的创建和调用控制而言的,当程序需要使用一个对象时,由 IoC 容器来创建和管理,即控制权由应用程序转移到 IoC 容器中,也就是“反转”了控制权。这种方式基本上是通过依赖查找的方式来实现的,即 IoC 容器维护着构成应用程序的对象,并负责创建对象。

2.4.3、DI (Dependency Injection) 依赖注入

  DI 是指在组件之间传递依赖关系的过程中,将依赖关系在容器内部进行处理,这样就不必在应用程序代码中硬编码对象之间的依赖关系,实现了对象之间的解耦合。在 Spring 中,DI 是通过 XML 配置文件或注解的方式实现的。它提供了三种形式的依赖注入:构造函数注入、Setter 方法注入和接口注入。

三、Spring loC的实践和应用

3.1.Spring loC/DI实现步骤
  • 1.编写配置文件(组件类信息,组件之间的引用关系)
  • 2.实例化ioc容器对象(指定配置信息)
  • 3.在java代码中获取组件、使用组件对象
 3.2基于XML配置方式组件管理
3.2.1组件(Bean)信息声明配置
1.目标

Spring IoC 容器管理一个或多个 bean。这些 Bean 是使用容器的配置元数据创建的(例如,以 XML <bean/> 定义的形式),通过定义XML配置文件,声明组件类信息,交给 Spring 的 IoC 容器进行组件管理。

2.思路 

3. 准备项目
    1. 创建maven工程(spring-ioc-xml-01)
    2. 导入SpringIoC相关依赖  pom.xml
​
    <dependencies>
        <!--spring context依赖-->
        <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.6</version>
        </dependency>
        <!--junit5测试-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.3.1</version>
        </dependency>
    </dependencies>

​
4.. 基于无参数构造函数

    > 当通过构造函数方法创建一个 bean(组件对象) 时,所有普通类都可以由 Spring 使用并与之兼容。也就是说,正在开发的类不需要实现任何特定的接口或以特定的方式进行编码。只需指定 Bean 类信息就足够了。但是,默认情况下,我们需要一个默认(空)构造函数。

    1. 准备组件类


package com.atguigu.ioc;


public class HappyComponent {

    //默认包含无参数构造函数

    public void doWork() {
        System.out.println("HappyComponent.doWork");
    }
}

​


    2. xml配置文件编写

        创建携带spring约束的xml配置文件

使用编译工具一键编译

        编写配置文件:

        文件:resources/spring-bean-01.xml

<!-- 实验一 [重要]创建bean -->
        <bean id="happyComponent1" class="com.chb.ioc_01.HappyComponent" />
      <bean id="happyComponent2" class="com.chb.ioc_01.HappyComponent"/>
  •         - bean标签:通过配置bean标签告诉IOC容器需要创建对象的组件信息
  •         - id属性:bean的唯一标识,方便后期获取Bean!
  •         - class属性:组件类的全限定符!
  •         - 注意:要求当前组件类必须包含无参数构造函数!
  •         - 将一个组件类声明两个组件信息-[默认是单例对象]-会实例化两个对象  new new
5.基于静态工厂方法实例化

     除了使用构造函数实例化对象,还有一类是通过工厂模式实例化对象

    1. 准备组件类

public class ClientService {
  private static ClientService clientService = new ClientService();
  private ClientService() {}

  public static ClientService createInstance() {
  
    return clientService;
  }
}


    2. xml配置文件编写

        文件:resources/spring-bean-01.xml

<bean id="clientService"
  class="examples.ClientService"
  factory-method="createInstance"/>
  •         - class属性:指定工厂类的全限定符!
  •         - factory-method: 指定静态工厂方法,注意,该方法必须是static方法。
6. 基于实例工厂方法实例化

如何定义使用实例工厂方法创建Bean的配置

    1. 准备组建类

public class DefaultServiceLocator {

  private static ClientServiceImpl clientService = new ClientServiceImpl();

  public ClientService createClientServiceInstance() {
    return clientService;
  }
}


    2. xml配置文件编写

        文件:resources/spring-bean-01.xml


<!-- 将工厂类进行ioc配置 -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator"/>

<!-- 根据工厂对象的实例工厂方法进行实例化组件对象 -->
<bean id="clientService"
  factory-bean="serviceLocator"
  factory-method="createClientServiceInstance"/>
  •         - factory-bean属性:指定当前容器中工厂Bean 的名称。
  •         - factory-method:  指定实例工厂方法名。注意,实例方法必须是非static的!
3.2.2 组件(bean)依赖注入配置(DI)
1. 目标

    通过配置文件,实现IoC容器中Bean之间的引用(依赖注入DI配置)。

    主要涉及注入场景:基于构造函数的依赖注入和基于 Setter 的依赖注入。

2. 思路


3. 基于构造函数的依赖注入(单个构造参数)
    1. 介绍

        基于构造函数的 DI 是通过容器调用具有多个参数的构造函数来完成的,每个参数表示一个依赖项。

        下面的示例演示一个只能通过构造函数注入进行依赖项注入的类!
    2. 准备组件类

public class UserDao {
}


public class UserService {
    
    private UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
}


    3. 编写配置文件

        文件:resources/spring-02.xml

<beans>
  <!-- 引用类bean声明 -->
  <bean id="userService" class="x.y.UserService">
   <!-- 构造函数引用 -->
    <constructor-arg ref="userDao"/>
  </bean>
  <!-- 被引用类bean声明 -->
  <bean id="userDao" class="x.y.UserDao"/>
</beans>

        constructor-arg标签:可以引用构造参数 ref引用其他bean的标识。


4. 基于构造函数的依赖注入(多构造参数解析)
    1. 介绍

        基于构造函数的 DI 是通过容器调用具有多个参数的构造函数来完成的,每个参数表示一个依赖项。

        下面的示例演示通过构造函数注入多个参数,参数包含其他bean和基本数据类型!
    2. 准备组件类

public class UserDao {
}


public class UserService {
    
    private UserDao userDao;
    
    private int age;
    
    private String name;

    public UserService(int age , String name ,UserDao userDao) {
        this.userDao = userDao;
        this.age = age;
        this.name = name;
    }
}


    3. 编写配置文件

             <!--引用和被引用的组件 必须都在ioc容器里面!-->
    <!--单个构造函数引入-->
<!-- 将他们都在ioc容器里面  -->
 <!--<constructor-arg value="直接属性值"  String name="chb" int age=18
                       ref="引用其他的id (bean)"/>-->
<!-- 场景1: 多参数,可以按照相应构造函数的顺序注入数据 -->
<beans>
  <bean id="userService" class="x.y.UserService">
    <!-- value直接注入基本类型值 -->
    <constructor-arg  value="18"/>
    <constructor-arg  value="赵伟风"/>
    
    <constructor-arg  ref="userDao"/>
  </bean>
  <!-- 被引用类bean声明 -->
  <bean id="userDao" class="x.y.UserDao"/>
</beans>


<!-- 场景2: 多参数,可以按照相应构造函数的名称注入数据 -->
<beans>
  <bean id="userService" class="x.y.UserService">
    <!-- value直接注入基本类型值 -->
    <constructor-arg name="name" value="赵伟风"/>
    <constructor-arg name="userDao" ref="userDao"/>
    <constructor-arg name="age"  value="18"/>
  </bean>
  <!-- 被引用类bean声明 -->
  <bean id="userDao" class="x.y.UserDao"/>
</beans>

<!-- 场景2: 多参数,可以按照相应构造函数的角标注入数据 
           index从0开始 构造函数(0,1,2....)
-->
<beans>
    <bean id="userService" class="x.y.UserService">
    <!-- value直接注入基本类型值 -->
    <constructor-arg index="1" value="赵伟风"/>
    <constructor-arg index="2" ref="userDao"/>
    <constructor-arg index="0"  value="18"/>
  </bean>
  <!-- 被引用类bean声明 -->
  <bean id="userDao" class="x.y.UserDao"/>
</beans>

 constructor-arg标签:指定构造参数和对应的值
        

constructor-arg标签:name属性指定参数名、index属性指定参数角标、value属性指定普通属性值


5. 基于Setter方法依赖注入
    1. 介绍

        开发中,除了构造函数注入(DI)更多的使用的Setter方法进行注入!

        下面的示例演示一个只能使用纯 setter 注入进行依赖项注入的类。
    2. 准备组件类

public Class MovieFinder{

}

public class SimpleMovieLister {

  private MovieFinder movieFinder;
  
  private String movieName;

  public void setMovieFinder(MovieFinder movieFinder) {
    this.movieFinder = movieFinder;
  }
  
  public void setMovieName(String movieName){
    this.movieName = movieName;
  }

  // business logic that actually uses the injected MovieFinder is omitted...
}


    3. 编写配置文件

<bean id="simpleMovieLister" class="examples.SimpleMovieLister">
  <!-- setter方法,注入movieFinder对象的标识id
       name = 属性名  ref = 引用bean的id值
   -->
  <property name="movieFinder" ref="movieFinder" />

  <!-- setter方法,注入基本数据类型movieName
       name = 属性名 value= 基本类型值
   -->
  <property name="movieName" value="消失的她"/>
</bean>

<bean id="movieFinder" class="examples.MovieFinder"/>

       property标签: 可以给setter方法对应的属性赋值
        property 标签: name属性代表set方法标识、ref代表引用bean的标识id、value属性代表基本属性值
 

依赖注入(DI)包含引用类型和基本数据类型,同时注入的方式也有多种!主流的注入方式为setter方法注入和构造函数注入,两种注入语法都需要掌握!需要特别注意:引用其他bean,使用ref属性。直接注入基本类型值,使用value属性。

3.2.3. IoC容器创建和使用

  1. 介绍

      上面讲解了如何在XML格式的配置文件编写IoC和DI配置!

      如图:

      想要配置文件中声明组件类信息真正的进行实例化成Bean对象和形成Bean之间的引用关系,我们需要声明IoC容器对象,读取配置文件,实例化组件和关系维护的过程都是在IoC容器中实现的!


  2. 容器实例化
//方式1:实例化并且指定配置文件
//参数:String...locations 传入一个或者多个配置文件
ApplicationContext context = 
           new ClassPathXmlApplicationContext("services.xml", "daos.xml");
           
//方式2:先实例化,再指定配置文件,最后刷新容器触发Bean实例化动作 [springmvc源码和contextLoadListener源码方式]  
ClassPathXmlApplicationContext context1 = 
           new ClassPathXmlApplicationContext();   
//设置配置配置文件,方法参数为可变参数,可以设置一个或者多个配置
context1.setConfigLocations("services.xml", "daos.xml");
//后配置的文件,需要调用refresh方法,触发刷新配置
context1.refresh();   

  3. Bean对象读取
//方式1: 根据id获取
//没有指定类型,返回为Object,需要类型转化!
HappyComponent happyComponent = 
        (HappyComponent) iocContainer.getBean("bean的id标识");
        
//使用组件对象        
happyComponent.doWork();

//方式2: 根据类型获取
//根据类型获取,但是要求,同类型(当前类,或者之类,或者接口的实现类)只能有一个对象交给IoC容器管理
//配置两个或者以上出现: org.springframework.beans.factory.NoUniqueBeanDefinitionException 问题
HappyComponent happyComponent = iocContainer.getBean(HappyComponent.class);
happyComponent.doWork();

//方式3: 根据id和类型获取
HappyComponent happyComponent = iocContainer.getBean("bean的id标识", HappyComponent.class);
happyComponent.doWork();
//根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看:『对象 instanceof 指定的类型』的返
//回结果,只要返回的是true就可以认定为和类型匹配,能够获取到。

3.2.4高级特性:组件(Bean)作用域和周期方法配置
  1. 组件周期方法配置


      1. 周期方法概念

          我们可以在组件类中定义方法,然后当IoC容器实例化和销毁组件对象的时候进行调用!这两个方法我们成为生命周期方法!

          类似于Servlet的init/destroy方法,我们可以在周期方法完成初始化和释放资源等工作。
      2. 周期方法声明

public class BeanOne {

  //周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
  public void init() {
    // 初始化逻辑
  }
}

public class BeanTwo {

  public void cleanup() {
    // 释放资源逻辑
  }
}


      3. 周期方法配置

    <!--init-method 指定初始化方法名
        destroy-method  指定销毁方法名
        spring就会在相应的周期回调方法,
    -->
<beans>
  <bean id="beanOne" class="examples.BeanOne" init-method="init" />
  <bean id="beanTwo" class="examples.BeanTwo" destroy-method="cleanup" />
</beans>

  2. 组件作用域配置
      1. Bean作用域概念

          <bean 标签声明Bean,只是将Bean的信息配置给SpringIoC容器!

          在IoC容器中,这些 <bean 标签对应的信息转成Spring内部 BeanDefinition 对象,BeanDefinition 对象内,包含定义的信息(id,class,属性等等)!

          这意味着,BeanDefinition 与类概念一样,SpringIoC容器可以可以根据 BeanDefinition 对象反射创建多个Bean对象实例。

          具体创建多少个Bean的实例对象,由Bean的作用域Scope属性指定!
      2. 作用域可选值

取值含义创建对象的时机默认值
singleton在 IOC 容器中,这个 bean 的对象始终为单实例IOC 容器初始化时
prototype这个 bean 在 IOC 容器中有多个实例获取 bean 时

如果是在WebApplicationContext环境下还会有另外两个作用域(但不常用):

取值含义创建对象的时机默认值
request请求范围内有效的实例每次请求
session会话范围内有效的实例每次会话

      3. 作用域配置

          配置scope范围

<!--bean的作用域 
    准备两个引用关系的组件类即可!!
-->
<!-- scope属性:取值singleton(默认值),bean在IOC容器中只有一个实例,IOC容器初始化时创建对象 -->
<!-- scope属性:取值prototype,bean在IOC容器中可以有多个实例,getBean()时创建对象 -->
<bean id="happyMachine8" scope="prototype" class="com.atguigu.ioc.HappyMachine">
    <property name="machineName" value="happyMachine"/>
</bean>

<bean id="happyComponent8" scope="singleton" class="com.atguigu.ioc.HappyComponent">
    <property name="componentName" value="happyComponent"/>
</bean>


      4. 作用域测试

@Test
public void testExperiment08()  {
    ApplicationContext iocContainer = new ClassPathXmlApplicationContext("配置文件名");

    HappyMachine bean = iocContainer.getBean(HappyMachine.class);
    HappyMachine bean1 = iocContainer.getBean(HappyMachine.class);
    //多例对比 false
    System.out.println(bean == bean1);

    HappyComponent bean2 = iocContainer.getBean(HappyComponent.class);
    HappyComponent bean3 = iocContainer.getBean(HappyComponent.class);
    //单例对比 true
    System.out.println(bean2 == bean3);
}
3.2.5高级特性FactoryBean特性和使用
1.FactoryBean简介

FactoryBean 接口是Spring IoC容器实例化逻辑的可插拔性点。用于配置复杂的Bean对象,可以将创建过程存储在FactoryBean的getObject方法!FactoryBean<T>接口提供三种方法:

方法

简介

T getObject()返回此工厂创建的对象的实例。该返回值会被存储到IoC容器!
boolean isSingleton()

如果 FactoryBean 返回单例,则返回 true ,否则返回 false 。此方法的

默认实现返回 true (注意,lombok插件使用,可能影响效果)。

Class<?> getObjectType()返回 getObject() 返回的对象类型,如果事先不知道类型,则返回 null 。

2. FactoryBean使用场景


    1. 代理类的创建           2. 第三方框架整合        3. 复杂对象实例化等

3. Factorybean应用


    1. 准备FactoryBean实现类

package com.chb.ioc_05;

import org.springframework.beans.factory.FactoryBean;

/**
 * ClassName: JavaBeanFactoryBean
 * Description:
 *
 * @Author achb
 * @Create 2023/9/8 15:31
 * @Version 1.0
 * 步骤
 *  1.实现factorybean接口
 */
public class JavaBeanFactoryBean implements FactoryBean<JavaBean> {

private String value;

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public JavaBean getObject() throws Exception {
        //使用自己的方法实例化对象
        JavaBean javaBean=new JavaBean();
        javaBean.setName(value);
        return javaBean;
    }

    @Override
    public Class<?> getObjectType() {
        return JavaBean.class;
    }
}


    2. 配置FactoryBean实现类

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--    id:->getObject方法返回的标识
        class ->factoryBean的标准化工厂类-->
<bean id="javaBean" class="com.chb.ioc_05.JavaBeanFactoryBean">
 <!-- property标签仍然可以用来通过setXxx()方法给属性赋值 -->
<property name="value" value="二狗子"/>
</bean>

</beans>


    3. 测试读取FactoryBean和FactoryBean.getObject对象

    @Test
    public void test_05(){
        //创建ioc容器对组件进行实例化
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-05.xml");
        com.chb.ioc_05.JavaBean javaBean=applicationContext.getBean("javaBean",com.chb.ioc_05.JavaBean.class);
//注意: 直接根据声明FactoryBean的id,获取的是getObject方法返回的对象
        System.out.println("javaBean--" + javaBean);
//如果想要获取FactoryBean对象, 直接在id前添加&符号即可!  &javaBean 这是一种固定的约束
        Object bean = applicationContext.getBean("&javaBean");

        System.out.println(bean);

                //2.正常结束ioc容器
        applicationContext.close();
    }
3.2.6 . 基于XML方式整合三层架构组件(实践)
  1. 需求分析

      搭建一个三层架构案例,模拟查询全部学生(学生表)信息,持久层使用JdbcTemplate和Druid技术,使用XML方式进行组件管理!

      2. 数据库准备

create database studb;

use studb;

CREATE TABLE students (
  id INT PRIMARY KEY,
  name VARCHAR(50) NOT NULL,
  gender VARCHAR(10) NOT NULL,
  age INT,
  class VARCHAR(50)
);

INSERT INTO students (id, name, gender, age, class)
VALUES
  (1, '张三', '男', 20, '高中一班'),
  (2, '李四', '男', 19, '高中二班'),
  (3, '王五', '女', 18, '高中一班'),
  (4, '赵六', '女', 20, '高中三班'),
  (5, '刘七', '男', 19, '高中二班'),
  (6, '陈八', '女', 18, '高中一班'),
  (7, '杨九', '男', 20, '高中三班'),
  (8, '吴十', '男', 19, '高中二班');
  3. 项目准备

           1. 项目创建

                 spring-xml-practice-02
           2. 依赖导入

<?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>com.chb</groupId>
        <artifactId>ssm-spring-part</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>spring-ioc-xml-practice-02</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
<dependencies>
        <!--spring context依赖-->
        <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.6</version>
        </dependency>
        <!--junit5测试-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.3.1</version>
        </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.25</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.8</version>
    </dependency>

    <!-- spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>6.0.6</version>
    </dependency>
</dependencies>
</project>


      3. 实体类准备
public class Student {

    private Integer id;
    private String name;
    private String gender;
    private Integer age;
    private String classes;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getClasses() {
        return classes;
    }

    public void setClasses(String classes) {
        this.classes = classes;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", classes='" + classes + '\'' +
                '}';
    }
}

  4. JdbcTemplate技术讲解

         为了在特定领域帮助我们简化代码,Spring 封装了很多 『Template』形式的模板类。例如:RedisTemplate、RestTemplate 等等,包括我们今天要学习的 JdbcTemplate。

      提取数据库连接信息     (命名) jdbc.properties

chb.url=jdbc:mysql://localhost:3306/studb
chb.driver=com.mysql.cj.jdbc.Driver
chb.username=root
chb.password=

      springioc配置文件

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

    <!--    读取外部配置文件。properties=》在标签中的value可以使用value="${}"
            多个外部配置文件可以用逗号隔开在其后添加"classpath:****"
            但是只能是.properties后缀文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${chb.url}"/>
        <property name="driverClassName" value="${chb.driver}"/>
        <property name="username" value="${chb.username}"/>
        <property name="password" value="${chb.password}"/>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

      基于jdbcTemplate的CRUD使用

package com.chb.jdbc;

import com.alibaba.druid.pool.DruidDataSource;
import com.chb.pojo.Student;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * ClassName: jdbcTemplateTest
 * Description:
 *
 * @Author 陈海斌
 * @Create 2023/9/8 16:48
 * @Version 1.0
 */
public class jdbcTemplateTest {
    public void testForJava(){

        /*JdbcTempalte 简化数据库的crud 不提供基础连接池
        需要再两个对象之间创建链接
        DruidDateSource 负责链接和数据库驱动的注册
        0.创建一个连接池对象
        * */
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl("jdbc:mysql:///studb");
        druidDataSource.setDriverClassName("com.nysql.cj.jdbc.Driver");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("");

        //1.实例化对象
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(druidDataSource);
        //2.调用方法
        //jdbcTemplate.update()DDL DML DCL --非查询语句
        //jdbcTemplate.queryForObject() DQL查询单个对象
        //jdbcTemplate.query()DQL 查询集合

    }

    @Test
    public void testForIoC(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-01.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean(JdbcTemplate.class);
        String sql = "insert into students(id,name,gender,age,class) values(?,?,?,?,?)";
        /** 参数1: String sql 可以带占位符 ?  ?只能替代值 不能替代关键字和容器名
         * 参数2: Object...param 传入占位符的值 顺序 从左开始对象
         * 返回值: int  影响函数*/
        int rows = jdbcTemplate.update(sql, 22,"chb", "男", 18, "三年级二班");
        System.out.println("rows:"+rows);
        sql = "select * from students where id = ? ;";
        Student student1 = jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
         /*   rs 结果集         rowNum 行数        rs结果集中获取列的值 赋值给实体类对象即可*/
                    Student student = new Student();
                    student.setId(rs.getInt("id"));
                    student.setName(rs.getString("name"));
                    student.setAge(rs.getInt("age"));
                    student.setGender(rs.getString("gender"));
                    student.setClasses(rs.getString("class"));
                    return student;
                }
                , 1);
        System.out.println("student1 = " + student1);
        //3.3 查询所有学生数据
        sql = "select id , name ,gender , age , class as classes from students ;";

        //TODO: BeanPropertyRowMapper帮助我们自动映射列和属性值!要求列名和属性名一致!不一致 起别名!
        List<Student> studentList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Student>(Student.class));
        System.out.println("studentList = " + studentList);
    }




}

  5. 三层架构搭建和实现


      1. 持久层

接口

public interface StudentDao {

    /**
     * 查询全部学生数据
     * @return
     */
    List<Student> queryAll();
}

//实现类

public class StudentDaoImpl implements StudentDao {
    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public List<Student> queryAll() {
       String sql = "select id , name ,gender , age , class as classes from students ;";
        List<Student> students = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Student.class));
        System.out.println(students);

        return students;
    }

}


      2. 业务层

接口

public interface StudentService {
    List<Student> findAll();


}

 实现类

public class StudentServeImpl implements StudentService {
    private StudentDao studentDao;

    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
    }

    @Override
    public List<Student> findAll() {
        List<Student> studentList = studentDao.queryAll();
        System.out.println("studentSercice:" + studentList);

        return studentList;
    }
}


      3. 表述层

public class StudentController {
    
    private StudentService studentService;

    public void setStudentService(StudentService studentService) {
        this.studentService = studentService;
    }
    
    public void  findAll(){
       List<Student> studentList =  studentService.findAll();
        System.out.println("studentList = " + studentList);
    }
}

  6. 三层架构IoC配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${chb.url}"/>
        <property name="driverClassName" value="${chb.driver}"/>
        <property name="username" value="${chb.username}"/>
        <property name="password" value="${chb.password}"/>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <bean id="studentDao" class="com.chb.dao.impl.StudentDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
    <bean id="studentServe" class="com.chb.service.impl.StudentServeImpl">
        <property name="studentDao" ref="studentDao"/>
    </bean>
    <bean id="studentController" class="com.chb.controller.StudentController">
        <property name="studentService" ref="studentServe"/>
    </bean>
</beans>

  7. 运行测试
public class ControllerTest {

    @Test
    public  void testRun(){
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("spring-ioc.xml");
        StudentController studentController = applicationContext.getBean(StudentController.class);
        studentController.findAll();
    }
}

  8. XMLIoC方式问题总结

      1. 注入的属性必须添加setter方法、代码结构乱!
      2. 配置文件和Java代码分离、编写不是很方便!
      3. XML配置文件解析效率低

3.3.基于 注解 方式管理Bean
        3.3.1. Bean注解标记和扫描 (IoC)

  1.注解理解

     注解是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作,本质是所有一切的操作都是 Java 代码来完成的,XML 和注解只是告诉框架中的 Java 代码如何执行。


  2. 扫描理解

      Spring 为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后根据注解进行后续操作。


  3. 准备Spring项目和组件


      1. 准备项目pom.xml

<dependencies>
    <!--spring context依赖-->
    <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.0.6</version>
    </dependency>

    <!--junit5测试-->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.3.1</version>
    </dependency>
</dependencies>


      2. 准备组件类

          普通组件

/**
 * projectName: com.atguigu.components
 *
 * description: 普通的组件
 */
public class CommonComponent {
}

          Controller组件

/**
 * projectName: com.atguigu.components
 *
 * description: controller类型组件
 */
public class XxxController {
}

          Service组件

/**
 * projectName: com.atguigu.components
 *
 * description: service类型组件
 */
public class XxxService {
}

          Dao组件

/**
 * projectName: com.atguigu.components
 *
 * description: dao类型组件
 */
public class XxxDao {
}

  4. 组件添加标记注解


      1. 组件标记注解和区别

          Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。

注解说明
@Component该注解用于描述 Spring 中的 Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如 Service 层、Dao 层等。 使用时只需将该注解标注在相应类上即可。
@Repository该注解用于将数据访问层(Dao 层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
@Service该注解通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
@Controller该注解通常作用在控制层(如SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

          通过查看源码我们得知,@Controller、@Service、@Repository这三个注解只是在@Component注解的基础上起了三个新的名字。

          对于Spring使用IOC容器管理这些组件来说没有区别,也就是语法层面没有区别。所以@Controller、@Service、@Repository这三个注解只是给开发人员看的,让我们能够便于分辨组件的作用。

          注意:虽然它们本质上一样,但是为了代码的可读性、程序结构严谨!我们肯定不能随便胡乱标记。
      2. 使用注解标记

          普通组件

/**
 * projectName: com.atguigu.components
 *
 * description: 普通的组件
 */
@Component
public class CommonComponent {
}

          Controller组件

/**
 * projectName: com.atguigu.components
 *
 * description: controller类型组件
 */
@Controller
public class XxxController {
}

          Service组件

/**
 * projectName: com.atguigu.components
 *
 * description: service类型组件
 */
@Service
public class XxxService {
}

          Dao组件

/**
 * projectName: com.atguigu.components
 *
 * description: dao类型组件
 */
@Repository
public class XxxDao {
}

  5. 配置文件确定扫描范围

      情况1:基本扫描配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--1. 普通配置包扫描
         base-package 指定ioc容器去哪些包下查找注解类 -> ioc容器
         一个包或者多个包  com.ahb,com.chb.xxx 包,包
         指定包,相当于指定了子包内的所有类
  -->
    <context:component-scan base-package="com.chb.pojo"/>

    <!-- 2.指定包,但是排除注解 -->

<!--        <context:component-scan base-package="com.chb" >
            &lt;!&ndash; 排除包下的注解&ndash;&gt;
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>-->
    <!--3.指定包,指定包含注解 -->
    <!-- basePackage包下的所有注解都生效!!  use-default-filters="false" 指定包的所有注解先不生效! -->
<!--    <context:component-scan base-package="com.chb" use-default-filters="false">
        &lt;!&ndash; 只扫描包下的注解 &ndash;&gt;
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>-->
</beans>

      情况2:指定排除组件

<!-- 情况三:指定不扫描的组件 -->
<context:component-scan base-package="com.atguigu.components">
    
    <!-- context:exclude-filter标签:指定排除规则 -->
    <!-- type属性:指定根据什么来进行排除,annotation取值表示根据注解来排除 -->
    <!-- expression属性:指定排除规则的表达式,对于注解来说指定全类名即可 -->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

      情况3:指定扫描组件

<!-- 情况四:仅扫描指定的组件 -->
<!-- 仅扫描 = 关闭默认规则 + 追加规则 -->
<!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
<context:component-scan base-package="com.atguigu.ioc.components" use-default-filters="false">
    
    <!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
  6. 组件BeanName问题

      在我们使用 XML 方式管理 bean 的时候,每个 bean 都有一个唯一标识——id 属性的值,便于在其他地方引用。现在使用注解后,每个组件仍然应该有一个唯一标识。

      默认情况:

      类名首字母小写就是 bean 的 id。例如:SoldierController 类对应的 bean 的 id 就是 soldierController。

      使用value属性指定:

@Controller(value = "tianDog")
public class SoldierController {
}

      当注解中只设置一个属性时,value属性的属性名可以省略:

@Service("smallDog")
public class SoldierService {
}

  7. 总结

      1. 注解方式IoC只是标记哪些类要被Spring管理
      2. 最终,我们还需要XML方式或者后面讲解Java配置类方式指定注解生效的包
      3. 现阶段配置方式为 注解 (标记)+ XML(扫描)

3.3. 2. 组件(Bean)作用域和周期方法注解 

  1. 组件周期方法配置


      1. 周期方法概念

          我们可以在组件类中定义方法,然后当IoC容器实例化和销毁组件对象的时候进行调用!这两个方法我们成为生命周期方法! 类似于Servlet的init/destroy方法,我们可以在周期方法完成初始化和释放资源等工作。

 
      2. 周期方法声明

public class BeanOne {

  //周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
  @PostConstruct  //注解制指定初始化方法
  public void init() {
    // 初始化逻辑
  }
}

public class BeanTwo {
  
  @PreDestroy //注解指定销毁方法
  public void cleanup() {
    // 释放资源逻辑
  }
}

  2. 组件作用域配置


      1. Bean作用域概念

          `<bean` 标签声明Bean,只是将Bean的信息配置给SpringIoC容器!

          在IoC容器中,这些`<bean`标签对应的信息转成Spring内部 `BeanDefinition` 对象,`BeanDefinition` 对象内,包含定义的信息(id,class,属性等等)!

          这意味着,`BeanDefinition`与`类`概念一样,SpringIoC容器可以可以根据`BeanDefinition`对象反射创建多个Bean对象实例, 具体创建多少个Bean的实例对象,由Bean的作用域Scope属性指定!

    2. 作用域可选值 

取值含义创建对象的时机默认值
singleton在 IOC 容器中,这个 bean 的对象始终为单实例IOC 容器初始化时
prototype这个 bean 在 IOC 容器中有多个实例获取 bean 时


          如果是在WebApplicationContext环境下还会有另外两个作用域(但不常用):

取值含义创建对象的时机默认值
request请求范围内有效的实例每次请求
session会话范围内有效的实例每次会话

      3. 作用域配置

@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) //单例,默认值
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //多例  二选一
public class BeanOne {

  //周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
  @PostConstruct  //注解制指定初始化方法
  public void init() {
    // 初始化逻辑
  }
}
3.3.3 . Bean属性赋值:引用类型自动装配 (DI)

 1. 自动装配实现


        1. 前提:​​​​​​​ 参与自动装配的组件必须在IoC容器中. 注意:不区分IoC的方式!XML和注解都可以!
     

        2. @Autowired注解 在成员变量上直接标记@Autowired注解即可,不需要提供setXxx()方法。以后我们在项目中的正式用法就是这样。

        3. @Autowired注解细节
          1. 标记位置
              1. 成员变量 与xml进行bean ref引用不同,他不需要有set方法!

@Service("smallDog")
public class SoldierService {
    
    @Autowired
    private SoldierDao soldierDao;
    
    public void getMessage() {
        soldierDao.getMessage();
    }
}


          2. 构造器

@Controller(value = "tianDog")
public class SoldierController {
    
    private SoldierService soldierService;
    
    @Autowired
    public SoldierController(SoldierService soldierService) {
        this.soldierService = soldierService;
    }
    ……


          3. setXxx()方法

@Controller(value = "tianDog")
public class SoldierController {

    private SoldierService soldierService;

    @Autowired
    public void setSoldierService(SoldierService soldierService) {
        this.soldierService = soldierService;
    }
    ……

   
2. 佛系装配

      给 @Autowired 注解设置 required = false 属性表示:能装就装,装不上就不装。但是实际开发时,基本上所有需要装配组件的地方都是必须装配的,用不上这个属性

@Controller(value = "tianDog")
public class SoldierController {

    // 给@Autowired注解设置required = false属性表示:能装就装,装不上就不装
    @Autowired(required = false)
    private ISoldierService soldierService;

3. 扩展JSR-250注解@Resource

          @Autowired注解是Spring框架自己的。
          @Resource注解默认根据Bean名称装配,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型装配。
      @Autowired注解默认根据类型装配,如果想根据名称装配,需要配合@Qualifier注解一起用。
          @Resource注解用在属性上、setter方法上。
          @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。

          @Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖:高于JDK11或低于JDK8需要引入以下依赖

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>


       @Resource使用

@Controller
public class UserController {
    @Resource(name = "newUserServiceImpl")
private UserService userService;
    public void show(){
        String show = userService.show();
        System.out.println(show);
    }
}
3.3.4 实验四: Bean属性赋值:基本类型属性赋值 (DI)

  @Value通常用于注入外部化属性

  例如声明外部配置:application.properties

jdbc.password=
<context:property-placeholder location="application.properties" />

  @Value注解读取配置

package com.atguigu.components;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * projectName: com.atguigu.components
 *
 * description: 普通的组件
 */
@Component
public class CommonComponent {

    /**
     * 情况1: ${key} 取外部配置key对应的值!
     * 情况2: ${key:defaultValue} 没有key,可以给与默认值
     */
    @Value("${catalog:hahaha}")
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
3.3.5 实验五: 基于注解+XML方式整合三层架构组件

  1. 需求分析

      搭建一个三层架构案例,模拟查询全部学生(学生表)信息,持久层使用JdbcTemplate和Druid技术,使用XML+注解方式进行组件管理!


 
  2. 数据库准备

参照:      2. 数据库准备


  3. 项目准备
        1. 项目创建      spring-annotation-practice-04

       
      2. 依赖导入

<dependencies>
      <!--spring context依赖-->
      <!--当你引入SpringContext依赖之后,表示将Spring的基础依赖引入了-->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>6.0.6</version>
      </dependency>

      <!-- 数据库驱动和连接池-->
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.25</version>
      </dependency>

      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>1.2.8</version>
      </dependency>
      
      <dependency>
            <groupId>jakarta.annotation</groupId>
            <artifactId>jakarta.annotation-api</artifactId>
            <version>2.1.1</version>
       </dependency>

      <!-- spring-jdbc -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>6.0.6</version>
      </dependency>

</dependencies> 


      3. 实体类准备

public class Student {

    private Integer id;
    private String name;
    private String gender;
    private Integer age;
    private String classes;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getClasses() {
        return classes;
    }

    public void setClasses(String classes) {
        this.classes = classes;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", classes='" + classes + '\'' +
                '}';
    }
}

  4. 三层架构搭建和实现

​​​​​​​
      1. 持久层

//接口
public interface StudentDao {

    /**
     * 查询全部学生数据
     * @return
     */
    List<Student> queryAll();
}

//实现类
@Repository
public class StudentDaoImpl implements StudentDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 查询全部学生数据
     * @return
     */
    @Override
    public List<Student> queryAll() {

        String sql = "select id , name , age , gender , class as classes from students ;";

        /*
          query可以返回集合!
          BeanPropertyRowMapper就是封装好RowMapper的实现,要求属性名和列名相同即可
         */
        List<Student> studentList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Student.class));

        return studentList;
    }
}


      2. 业务层

//接口
public interface StudentService {

    /**
     * 查询全部学员业务
     * @return
     */
    List<Student> findAll();

}

//实现类
@Service
public class StudentServiceImpl  implements StudentService {

    @Autowired
    private StudentDao studentDao;

    /**
     * 查询全部学员业务
     * @return
     */
    @Override
    public List<Student> findAll() {

        List<Student> studentList =  studentDao.queryAll();

        return studentList;
    }
}


      3. 表述层

@Controller
public class StudentController {

    @Autowired
    private StudentService studentService;

    public void  findAll(){
       List<Student> studentList =  studentService.findAll();
        System.out.println("studentList = " + studentList);
    }
}

  5. 三层架构IoC配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">


    <!-- 导入外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties" />

    <!-- 配置数据源 -->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${atguigu.url}"/>
        <property name="driverClassName" value="${atguigu.driver}"/>
        <property name="username" value="${atguigu.username}"/>
        <property name="password" value="${atguigu.password}"/>
    </bean>

    <bean class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druidDataSource" />
    </bean>

    <!-- 扫描Ioc/DI注解 -->
    <context:component-scan base-package="com.atguigu.dao,com.atguigu.service,com.atguigu.controller" />

</beans>

  6. 运行测试
public class ControllerTest {

    @Test
    public  void testRun(){
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("spring-ioc.xml");
        StudentController studentController = applicationContext.getBean(StudentController.class);
        studentController.findAll();
    }
}

  7. 注解+XML IoC方式问题总结


      1. 自定义类可以使用注解方式,但是第三方依赖的类依然使用XML方式!
      2. XML格式解析效率低!

遇见的bug 

一、系统的用户名覆盖问题

在使用.properties文件配置数据库连接信息时,spring默认会优先加载使用系统环境变量,此时,username实际上指的是当前计算机的用户名。而不是取值配置文件中定义的username。

报错:Access denied for user ‘king‘@‘localhost‘ (using password: YES) errorCode 1045, state 28000的

修改方法:

将配置文件中的username更改为其他名称,建议 原名称前加上"***.",例如chb.username

例如:

chb.url=jdbc:mysql://localhost:3306/studb
chb.driver=com.mysql.cj.jdbc.Driver
chb.username=root
chb.password=

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

热烈的眼泪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值