阶段七-Day01-Spring01

news2024/12/19 15:12:33

一、Spring框架介绍

1. 介绍

Spring Framework是由Spring团队研发的模块化、轻量级开源框架。其主要目的是为了简化项目开发。

Spring Framework前身是interface21,由Rod Johnson于2002年研发,主要是为了不使用EJB下依然能够构建高质量Java EE项目。EJB是当年横行一时的Java EE框架,目前已经属于淘汰技术。

2. 发展历史

  • 2002年,大约有3万行代码的interface21出现。

  • 2003年,Rod Johnson和朋友在interface21基础上研发了Spring。

  • 2004年3月,Spring 1.0发布。

  • 2006年10月,Spring 2.0发布。

  • 2007年11月,更名为 SpringSource,同时发布了 Spring 2.5。

  • 2009年12月,Spring 3.0 发布。同时把Spring由一个jar包拆分成多个jar包,真正实现模块化。

  • 2013年12 月,Spring 框架 4.0发布。

  • 2017年9月,Spring框架5.0发布。

暂时使用Spring框架版本5.3.16。

3. Spring各个模块

Test

对应spring-test.jar。Spring提供的测试工具,可以整合JUnit测试,简化测试环节。

Core Container

Spring的核心组件, 包含了Spring框架最基本的支撑。

Beans, 对应spring-beans.jar。Spring进行对象管理时依赖的jar包。

Core, 对应spring-core.jar,Spring核心jar包。

Context, 对应spring-context.jar, Spring容器上下文对象。

SpEL, 对应spring-expression.jar, Spring表达式语言。

AOP

面向切面编程,对应spring-aop.jar。

Aspects

Aspects的具体实现为面向切面编程的另一种实现。对应spring-aspects.jar。

Instrumentation

服务器代理接口的具体实现。对应spring-instrument.jar。

Messaging

集成messaging api和消息协议提供支持。对应spring-messaging.jar。

Data Access/Integration

Spring对数据访问层的封装。

JDBC,对应spring-jdbc.jar。Spring对jdbc的封装,当需要使用spring连接数据库时使用spring-jdbc.jar需要依赖spring-tx.jar。

Transactions。对应spring-tx.jar,事务管理。

ORM,对应spring-orm.jar。 spring整合第三方orm框架需要使用的jar包,例如Hibernate框架.

Web

Spring对javax下的接口或类做的扩展功能。

spring-web.jar。对Servlet,Filter,Listener等做的增强。

spring-webmvc.jar,实际上就是SpringMVC框架.。需要依赖spring环境和spring-web.jar。

二、Spring IoC/DI 介绍

1. Spring IoC/DI(常见面试题)

IoC(Inversion of Control) 控制反转

DI(dependency injection) 依赖注入

IoC/DI指的是一个过程:对象的创建仅仅通过Spring容器负责,Spring容器可以通过对象的构造方法或工厂方法进行实例化对象。在创建对象过程中,如果对象需要依赖其他对象也可以直接在Spring容器中注入到当前对象。

2. 专业术语介绍

  • 容器(Container):放置所有被管理的对象(所有的Bean)。其本质是在容器对象里面有一个全局Map对象,map对象中放置所有被管理的对象。Spring中容器是指ApplicationContext接口及子接口或实现类。

  • beans:容器中所有被管理的对象称为beans。如果单说其中一个对象可称为bean。

3. IoC/DI的好处

Spring IoC/DI使用后可以管理项目中相关对象,让对象管理的事情和业务分离(解耦)。同时程序员也不需要管理对象的依赖关系,所有的依赖关系交给Spring容器进行管理。

4. IoC/DI具体应用场景

IoC/DI 主要作用就是管理对象的实例化和对象之间依赖关系。项目中以前需要自己实例化的层对象、框架或工具包的入口类都可以交给Spring 容器进行管理。

  • 层对象:PeopleMapper 接口代理对象、PeopleServiceImpl。

  • 框架入口类:SqlSessionFactory等。

三、第一个Spring项目

Spring框架不依赖于Servlet容器(Tomcat),所以普通Java项目就可以使用Spring框架。

Spring框架提供了XML、注解、Java Config三种方式进行使用。

1. 创建项目,并添加依赖

在项目的pom.xml中添加Spring项目的最基本依赖。

Spring项目想要运行起来必须包含:

  • spring-context.jar。spring上下文依赖,它依赖了下面的四个jar。

    • spring-core.jar。Spring 核心jar包。它依赖了spring-jcl.jar。

    • spring-aop.jar。Spring AOP基本支持。

    • spring-expression.jar。Spring的表达式语言支持。

    • spring-beans.jar。Spring容器的bean 管理。

    • spring-jcl.jar。Spring 4版本时是common-logging.jar。从5开始Spring自己对日志进行了封装spring-jcl.jar。

所以在Maven中想要使用Spring框架只需要在项目中导入spring-context就可以了,其他的jar包根据Maven依赖传递性都可以导入进来。

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.16</version>
    </dependency>
</dependencies>

2. 随意创建一个类

package com.sh.pojo;

public class Emp {
    private int id;
    private String name;
    private String addr;

    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", addr='" + addr + '\'' +
                '}';
    }

    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 String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public Emp(int id, String name, String addr) {
        this.id = id;
        this.name = name;
        this.addr = addr;
    }

    public Emp() {
    }
}

3. 创建Spring配置文件

在src/main/resources下新建spring-config.xml文件。

小提示:

文件名称没有强制要求。官方示例中配置文件名称叫做applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- id:bean的名称   class:类型全限定路径 -->
<!-- 所有的对象都是通过bean来管理 -->
<bean id="emp01" class="com.sh.pojo.Emp"></bean>
</beans>

4. 创建测试类

创建测试类,测试Spring功能。

 @Test
    public void test(){
        //加载配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring-config01");
        //获取bean对象中的实例对象
        Object emp01 = ac.getBean("emp01");
        System.out.println(emp01);
    }

四、Bean实例化的两种方式(面试题)

在Spring中实例化Bean有两种方式:

  • 通过构造方法进行实例化。默认使用无参构造。这种方式和以前new的方式是等效的。上面的第一个Spring项目其实就是这种,只需要在XML中通过<bean>的class属性指定类的全限定路径,然后就可以实例化对象。

  • 通过工厂进行实例化。可以通过静态工厂和实例工厂进行实例化。这种方式完全是根据设计模式中工厂模式的思想而研发出的。Spring考虑到如果需要频繁实例化某个类的对象,工厂模式无疑是一个好选择。

上面第一个Spring项目已经演示过第一种实例化Bean的方式,所以下面重点演示使用工厂进行实例化bean。

1. 使用实例工厂实例化bean

1.1 创建工厂类

实例工厂方式需要实例化工厂类。所以工厂中创建bean的方法是一个实例方法。

在项目中创建实例工厂类,并编写方法返回创建的实例对象。

package factory;

import com.sh.pojo.Emp;

public class EmpFactory {
    Emp emp = new Emp();
    public Emp getInstance(){
        return emp;
    }
}
1.2 配置配置文件

在applicationContext.xml中先配置工厂实例,然后通过工厂实例产生自己想要的bean对象,注意bean标签中属性含义:

  • factory-bean:工厂bean的id属性值。

  • factory-method:工厂中创建bean的方法。

<!-- 实例工厂 -->
    <!-- 创建工厂实例 -->
    <bean id="factory" class="com.sh.factory.EmpFactory"/>
    <!-- 通过工厂实例化对象 -->
    <bean id="emp02" factory-bean="factory" factory-method="getInstance"></bean>
1.3 在测试类中测试效果

2. 使用静态工厂实例化bean

2.1 创建工厂类

静态工厂和实例工厂类最主要的区别是,创建bean的方法是static修饰的。

package com.sh.factory;

import com.sh.pojo.Emp;

public class StaticEmpFactory {
    //创建静态对象
    private static Emp emp = new Emp();
    //使用静态方法
    public static Emp getInstance(){
        return emp;
    }
}
2.2 配置配置文件

在applicationContext.xml中配置bean,注意bean标签中属性含义:

  • class:静态工厂类的全限定路径

  • factory-method:静态工厂中创建bean的静态方法。

<!-- 静态工厂 -->
    <!-- 因为静态方法在类不被创建的情况下就可以调用,所以直接调-->
    <bean id="emp03" class="com.sh.factory.StaticEmpFactory" factory-method="getInstance"></bean>

五、属性注入的两种方式(较常见面试题)

Spring中给Bean属性赋值有两种方式:

  • 构造注入(Constructor-based Dependency Injection):通过构造方法给bean的属性赋值。所以要求bean的类中必须提供对应参数的构造方法。相当于以前创建对象时new People(1,"张三");

  • 设值注入,又称setter注入(Setter-based Dependency Injection):通过Bean的set方法赋值。所以要求Bean中属性必须提供set方法。相当于以前的:People peo = new People(); peo.setId(1); peo.setName("张三");

1. 构造注入

  • 调用有参构造方法创建对象及完成属性值的注入,必须提供有参构造方法。

  • 提供了有参构造方法,不再默认提供无参构造方法,不使用构造注入会需要使用无参构造方法创建对象,需要提供无参构造方法。

1.1 检查Bean类中是否有有参构造方法
1.2 配置bean

在配置文件applicationContext.xml中可以通过<bean>的子标签<constructor-arg>设置构造方法中一个参数的值。

解释说明:

constructor-arg 里面有5个属性,这5个属性分为2类。

(1)用来确定给哪个属性进行赋值

name:参数名称。

index:参数索引。从0开始算起。

type:参数类型。8大基本数据类型可以直接写关键字。其他类型需要写类型的全限定路径。

这三个属性如果用一个就能精确的告诉Spring,要设置的构造方法参数是哪个,可以使用一个。如果无法精确到某个构造方法参数,可以多个一起结合使用。

(2)设置属性的值

value:简单数据类型直接设置。Spring会自动进行类型转换。

ref:需要引用另一个bean的id。也就是说这个参数是一个引用类型,且这个类的对象也被Spring容器管理。

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- id:bean的名称   class:类型全限定路径 -->
    <!-- 依赖注入 -->
    <!-- 方式一 : 构造注入 (通过有参构造方法完成属性的赋值,必须提供对应个数的有参构造方法)-->
    <bean id="emp" class="com.sh.pojo.Emp">
        <!--
        constructor-arg 构造方法的参数
        type 参数类型
        name 参数名
        index 参数索引
        这三个属性不是必须都指定,只要能够确定参数即可
        ref 值(引用类型 比如别的实体类)
        value 值
        -->
        <constructor-arg name="id" value="1"/>
        <constructor-arg name="name" value="zs"/>
        <constructor-arg name="addr" value="北京"/>
    </bean>

   
</beans>

2. 设值注入(setter注入)

  • 调用set方法完成属性值的注入,必须提供set方法。

  • Setter注入一般都是结合无参构造方法一起使用。所以类中有无参构造方法和set方法。

2.1 配置bean

使用属性property

<!-- 方式二 : 设置注入(setter注入 创建对象后,调用创建好的set方法进行属性赋值)-->
    <bean id="emp1" class="com.sh.pojo.Emp">
        <property name="id" value="2"/>
        <property name="name" value="zs"/>
        <property name="addr" value="上海"/>
    </bean>
2.2 其它引用数据类型的属性注入

无论是构造注入还是设值注入都提供了value和ref进行设置值。这两个属性只能给属性赋予简单数据类型或其他bean的引用。

如果类的属性是数组、集合等类型需要通过下面方式进行设置。

一旦使用了下面子标签方式,就不能对<property><constructor-args>设置value属性或ref属性。

2.1.1 Set类型
2.2.2 List类型
2.2.3 Array类型
2.2.4 Map类型
2.2.5 Null值类型
2.2.6 引用其他Bean

如果需要引用其他Bean,直接在property标签中使用ref引用就可以。使用子标签ref也可以,但是没有直接用ref属性的方式简单。

3. 构造注入和设值注入的混合使用

也可以让构造注入和设值注入混合使用。这两种方式只要保证有对应的有参构造方法和setter方法,就可以使用其中一种方式设置部分属性的值。

配置文件设置

<?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">
<bean id="people01" class="com.sh.pojo.People">
    <!-- 设值注入 使用property-->
    <!-- 普通属性 -->
    <property name="id" value="1"/>
    <property name="name" value="zs"/>
    <!-- 只有设值注入可以使用这些类型 -->
    <!-- list属性 -->
    <property name="list">
        <list>
            <value>1</value>
            <value>1</value>
            <value>1</value>
            <value>1</value>
        </list>
    </property>
    <!-- set属性 -->
    <property name="set">
        <!-- set不允许重复,重复的只取一个 -->
        <set>
            <value>1</value>
            <value>1</value>
            <value>1</value>
            <value>1</value>
        </set>
    </property>
    <property name="map">
        <map>
            <entry key="a" value="a"></entry>
            <entry key="b" value="b"></entry>
            <entry key="c" value="c"></entry>
        </map>
    </property>
    <property name="ints">
        <array>
            <value>1</value>
            <value>1</value>
            <value>1</value>
        </array>
    </property>
    <!-- 引用其他bean -->
    <!--
        name 属性名
        ref 其他bean的name
    -->
    <property name="emp" ref="emp"></property>

    <!-- 构造注入与设值注入也可以混合使用 -->
</bean>
    <bean id="emp" class="com.sh.pojo.Emp"></bean>
</beans>

六、自动注入

1. 属性值自动注入

小提示:

自动注入指的都是bean之间的自动注入。能够自动注入必须保证Spring 容器中包含能被自动注入的bean。

在Spring中,允许Bean的自动注入,有两种方式进行配置。

  • 在根标签<beans>中配置default-autowire属性,自动注入的策略,可取值有5个。

    1. default:默认值,不自动注入。(使用在bean标签中有其它含义)

    2. no:不自动注入。

    3. byName:

      1. 通过名称自动注入。名称:属性名与bean的id属性值。

      2. 会自动寻找容器中与注入值属性名同名的id属性值的bean进行注入。

      3. 底层为setter注入,设值注入。

    4. byType:

      1. 通过类型自动注入。类型:属性类型与bean的class类型。

      2. 会自动寻找容器中与注入值类型相同的bean进行注入。如果有多个相同类型的bean注入会出现异常。

      3. 底层为setter注入,设值注入。

    5. constructor:

      1. 通过构造方法进行注入。调用有参构造方法完成对象创建及属性自动注入。

      2. 寻找bean的有参构造方法中只包含需要注入属性参数的构造方法。自动属性注入。

      3. 底层为构造注入。

配置文件

<?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"
       default-autowire="constructor"
>

<!-- 自动注入,注入与被注入的bean必须都为spring管理的bean -->
    <!--
        全局配置:
            beans标签中配置:
                default-autowire=
                    1.no : 不自动注入
                    2.default : 不自动注入

                   set方法的自动注入
                    3.byName : 根据属性名字自动注入 (属性名与注入bean的id相同)
                    4.byType : 根据属性类型自动注入 (属性类型和注入的bean的类型相同)

                    构造方法的自动注入
                    5.constructor: 根据有参构造方法自动注入
                        1.先根据属性名获取对应的bean
                        2.根据属性名没有找到需要注入的bean,根据类型找需要的bean
    -->
    <bean id="cat" class="com.sh.pojo.Cat"></bean>
    <bean id="animal" class="com.sh.pojo.Animal" >
        <!--<constructor-arg name="name" value="dog"/>-->
        <!--<property name="name" value="dog"></property>-->
    </bean>

</beans>
  • <bean>标签中配置autowire属性,和default-autowire取值相同。

    • default:使用上级标签<beans>的default-autowire属性值。

    • default-autowire表示全局的配置。如果autowire和default-autowire同时存在,autowire生效。即局部的优先级高

七、bean标签的scope属性(面试题)

Spring中<bean>的scope控制的是Bean的有效范围。

一共有6个可取值,官方截图如下:

singleton:默认值。bean是单例的,每次获取Bean都是同一个对象。(单例设计模式)

prototype:bean时原型的,每次获取bean都重新实例化。

request:每次请求重新实例化对象,同一个请求中多次获取时单例的。

session:每个会话内bean是单例的。

application:整个应用程序对象内bean是单例的。

websocket:同一个websocket对象内对象是单例的。

里面的singleton和prototype在Spring最基本的环境中就可以使用,不需要web环境。

但是里面的request、session、application、websocket都只有在web环境才能使用。

衍生问题:Spring 中 Bean是否是线程安全的?

1. 如果bean的scope是单例的,bean不是线程安全的。

2. 如果bean的scope是prototype,bean是线程安全的。

<bean id="people" class="com.sh.pojo.People" scope="singleton"></bean>

八、单例设计模式(面试中笔试题)

设计模式:根据面向对象五大设计思想衍生出的常见23种设计模式,每种写法可以专门解决一类问题。

单例设计模式:保证某个类在整个应用程序中只有一个对象。

单例写法分为两种:饿汉式、懒汉式。

重要提示:

单例设计模式必须达到用纸手写的能力。

1. 饿汉式

//单例设计模式 - 饿汉式
public class SingletonHungry {
   //因为是单例,要设置为静态对象,只创建一次
    private static SingletonHungry s = new SingletonHungry();

    public SingletonHungry() {
    }

    //提供静态方法返回对象
    public static SingletonHungry getInstance(){
        
        return s;
    }
}

2. 懒汉式

package com.sh.util;

//单例设计模式 - 懒汉式
public class SingletonLazy {

    private static SingletonLazy s;
    //在方法被调用的时候才创建对象
    public static SingletonLazy getInstance(){
        //为了使线程安全,要加锁
        //使用双重检查锁DCL(Double Check Lock双端检锁)
        //但是双重检查锁DCL(Double Check Lock双端检锁)也不一定是线程安全的
        //因为有指令重排
        //必须关闭指令重排才能解决线程安全问题
        //可以使用volatile关键字来避免此问题。
        //private static volatile SingletonLazy instance = null;
        if (s == null){
            synchronized (SingletonLazy.class){
                //解决多线程重复创建对象,里面还需要再次判断
                if (s == null){
                    s = new SingletonLazy();
                    return s;
                }
            }
        }
        return s;
    }
}

九、Spring 循环注入问题(面试题)

1. 概念

循环注入即多个类相互依赖,产生了一个闭环。

2. 官方解释

在Spring IoC/DI使用过程中,可能出现循环注入的情况。

当两个类都是用构造注入时,没有等当前类实例化完成就需要注入另一个类,而另一个类没有实例化完整还需要注入当前类,所以这种情况是无法解决循环注入问题的的。会出现BeanCurrentlyInCreationException异常。

3. 循环依赖的场景

原因:

单例的setter注入: 

4. 解决循环依赖

如果两个类都使用设值注入且scope为singleton的就不会出现问题,可以正常执行。因为单例默认下有三级缓存(DefaultSingletonBeanRegistry),可以暂时缓存没有被实例化完成的Bean。

4.1 单例模式创建对象的步骤

Spring的单例对象的初始化主要分为三步:

  1. 实例化:其实也就是调用对象的构造方法实例化对象。

  2. 注入:填充属性,这一步主要是对bean的依赖属性进行填充。

  3. 初始化:属性注入后,执行自定义初始化操作。

4.2 循环依赖问题

A的某个field依赖了B的实例对象,同时B的某个field依赖了A的实例对象,这种情况为循环依赖。

4.3 解决循环依赖
  • 一级缓存(singletonObjects):存放实例化,属性注入,初始化完成的对象。

  • 二级缓存(earlySingletonObjects):存放早期暴露出来的Bean对象,属性还未填充完整。

  • 三级缓存(singletonFactories):存放bean创建工厂,以便于后面扩展有机会创建代理对象。

        二级缓存就可以解决简单的循环依赖,三级缓存是为了提高拓展性

十、BeanFactory和ApplicationContext(经典面试题)

1. BeanFactory接口

BeanFactory是Spring中的顶级接口,接口中定了Spring容器最基本功能。是Spring IoC的最核心接口。

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xbdr = new XmlBeanDefinitionReader(factory);
xbdr.loadBeanDefinitions(new FileSystemResource("C:\IdeaWS\spring_day01\src\main\resources\application.xml"));
Object teacher = factory.getBean("teacher");

BeanFactory是在调用getBean方法的时候才实例化Bean。(懒汉式)

2. ApplicationContext接口

ApplicationContext是BeanFactory的子接口。所以要比BeanFactory的功能更加强大,除了BeanFactory的功能,还包含了:

  • AOP 功能

  • 国际化(MessageSource)

  • 访问资源,如URL和文件(ResourceLoader)

  • 消息发送机制(ApplicationEventPublisher)

  • Spring集成Web时的WebApplicationContext

在使用时ApplicationContext时多使用ClassPathXmlApplicationContext

ApplicationContext applicationContext =
        new ClassPathXmlApplicationContext("applicationContext.xml");
Object teacher = applicationContext.getBean("teacher");

ApplicationContext是在加载配置文件后立即实例化Bean。(饿汉式)

可以通过bean标签的lazy-init属性进行控制,让bean懒加载。

十一、Spring整合MyBatis(非web环境)

1. 创建项目并添加依赖

创建一个普通Maven项目,并在pom.xml中添加依赖

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.sh</groupId>
  <artifactId>Spring02</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
    <!-- 引入spring框架需要的依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.16</version>
    </dependency>
    <!-- DataSource的实现类DriverManageDataSource实现所在的包 -->
    <!-- 把数据库连接操作交给Spring,后面事务才能使用Spring的声明式事务-->
    <!-- Spring整合MyBatis的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.7</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.9</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.28</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

2. 创建Spring配置文件

<?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">

<!--
    1.spring管理数据源 (数据库连接池)
        连接池分类:
            1. spring自带的连接池(org.springframework.jdbc.datasource.DriverManagerDataSource)
            2. 第三方连接池 (例如:com.alibaba.druid.pool.DruidDataSource(德鲁伊连接池))
    2.spring管理SqlSessionFactoryBean
        1.必须设置数据源
        2.通过sqlSessionFactoryBean设置mybatis的相关配置,例如定义别名

        注意:
            SqlSessionFactoryBean不是SqlSessionFactory的子类,SqlSessionFactoryBean中提供了
            getObject()方法可以获取SqlSessionFactory的实现类,通过SqlSessionFactory的实现类
            调用openSession()获取sqlSession。
    3.接口和映射文件绑定(接口中的方法和映射文件中的sql绑定)
        1.必须设置mapper接口的包名
        2.设置使用的SqlSessionFactoryBean的name
-->
    <!-- 
    id="dataSource":固定的,要根据id找到这个属性
    dataSource是SqlSessionFactoryBean类的一个属性
     -->
    <!-- 配置数据源 ,设置数据库连接的四个参数 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <!-- &amp 实体 代替 & -->
    <property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>
<!-- 配置SqlSessionFactoryBean -->
<bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!--
    SqlSessionFactoryBean中并不是SqlSessionFactory的子类
    但是SqlSessionFactoryBean中有一个getObject方法,方法可以返回SqlSessionFactory的实现类对象
    间接获取到SqlSessionFactory对象,再调用openSession方法就可以获取SqlSession对象
    -->
    <!-- 必备参数
        数据源 dataSource
        上面已经配置过了
    -->
    <property name="dataSource" ref="dataSource"/>
    <!-- 设置别名 -->
    <!-- 设置包的别名 -->
    <property name="typeAliasesPackage" value="com.sh.pojo"/>
</bean>

<!-- 配置.MapperScannerConfigurer 设置接口绑定 -->
<!-- 不用设置id -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 设置扫描哪个包下的mapper接口 -->
    <property name="basePackage" value="com.sh.mapper"/>
    <!--
    需要上面配置的SqlSessionFactoryBean
    获取间接获取到的SqlSessionFactory对象,通过调用openSession方法创建SqlSession
    再调用getMapper创建mapper接口的代理对象(相当于实现类的功能,但并不是严格意义的实现类)
    -->
    <property name="sqlSessionFactoryBeanName" value="SqlSessionFactory"/>
</bean>
</beans>

3. 创建实体类

创建com.sh.pojo.User

package com.sh.pojo;

import java.io.Serializable;

public class User implements Serializable {
    private int id;
    private String username;
    private String password;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public User(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public User() {
    }
}

4. 创建映射接口

创建com.sh.mapper.UserMapper

package com.sh.mapper;

import com.sh.pojo.User;

import java.util.List;

public interface UserMapper {

    List<User> selectAll();
}

5. 创建测试类

package com.sh;

import static org.junit.Assert.assertTrue;

import com.sh.mapper.UserMapper;
import com.sh.pojo.User;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.w3c.dom.ls.LSException;

import java.util.List;

/**
 * Unit test for simple App.
 */
public class AppTest 
{
    /**
     * Rigorous Test :-)
     */
    @Test
    public void shouldAnswerWithTrue()
    {
        assertTrue( true );
    }

    @Test
    public void test(){
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//底层已经封装好了获取代理对象的方法,直接通过接口的类对象就能获取代理对象
        UserMapper mapper = ac.getBean(UserMapper.class);
        List<User> list = mapper.selectAll();
        System.out.println(list);
    }
}

十二、Spring整合web

Spring 项目不需要依赖Web环境,但是Java项目大多数是Web项目,所以Spring也支持集成到Web环境中。

Spring 集成Web环境是通过Listener实现的,在ServletContext对象创建时加载Spring容器。Spring已经在spring-web.jar包中提供了ContextLoaderListener实现加载Spring配置文件的代码。我们只需要在web.xml配置<listener>标签让ContextLoaderListener生效,并且告诉ContextLoaderListener加载Spring配置文件的路径即可。

1. 创建项目,并添加依赖

创建Maven的web项目(添加上webapp目录等,并配置web模块),并在pom.xml配置依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <packaging>war</packaging>

  <name>Spring03Web</name>
  <groupId>com.sh</groupId>
  <artifactId>Spring03Web</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <!-- spring的上下文依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.16</version>
    </dependency>

    <!-- spring整合web的依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.3.16</version>
    </dependency>

    <!-- servlet-api -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>

    <!-- jsp-api -->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.3</version>
      <scope>provided</scope>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <!-- Tomcat插件 -->
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <path>/</path><!--发布到Tomcat的名称,即URL访问名称,平时多使用/-->
          <port>80</port><!-- 端口,平时多使用80或8080 -->

          <!-- 该编码指定的是为URI进行解码,所以只针对 get 请求有效。-->
          <uriEncoding>UTF-8</uriEncoding>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

2. 编写类

随意创建一个类,为了测试是否能从容器中获取到bean。

创建com.sh.pojo.User。

package com.sh.pojo;

import java.io.Serializable;

public class User implements Serializable {
    private int id;
    private String username;
    private String password;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public User(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public User() {
    }
}

3. 编写配置文件

建议:建立上applicationContext.xml的模板。

里面创建User的bean即可。

<?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">
<bean id="user" class="com.sh.pojo.User">
    <property name="username" value="zs"/>
</bean>
</beans>

4. 配置监听器

为了使spring容器只创建一次,避免每次访问都重新创建容器,可以使用静态代码创建容器,

tomcat中有三个域对象:

请求域,会话域,应用域

应用域(ServletContext)在tomcat启动后创建,tomcat关闭后销毁,且服务器中都共用,且创建一次

我们可以把spring容器存储在ServletContext中进行使用,可以通过监听器监听它的状态

可以自己写一个监听器,监听ServletContext的状态

package com.sh.lister;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

//配置监听器
//让web项目启动时自动创建Spring容器对象
//手写监听器
public class AppListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //ServletContext初始化后就创建spring容器并保存在servletContext中
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        ServletContext servletContext = sce.getServletContext();
        
        servletContext.setAttribute("ac",ac);

    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

在web.xml中配置监听器,让web项目启动时自动创建Spring容器对象(WebApplicationContext)。

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!-- 配置手写的监听器 -->
  <listener>
    <listener-class>com.sh.lister.AppListener</listener-class>
  </listener>
</web-app>

spring中内置了一个监听器,我们可以直接使用,但是需要对其进行配置

上下文参数名param-name的值是固定的contextConfigLocation。这个值是监听器需要获取的值。

上下文参数值需要带有classpath,表示加载类路径内容。target/classes目录内容。

classpath*:表示当前项目依赖的jar中资源也会寻找。

classpath:后面的值支持星号。例如applicationContext-*.xml表示加载所有以applicationContext-开头的xml文件。

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!-- 配置手写的监听器 -->
  <!--<listener>
    <listener-class>com.sh.lister.AppListener</listener-class>
  </listener>-->
  <!-- 配置spring中自带的监听器 -->
  <!--
  内置的监听器要想获取spring容器,它并不知道spring的配置文件是什么
  我们需要把文件传递给spring,其底层的策略是通过全局参数来传递
  -->
  <context-param>
    <!-- 必须写成contextConfigLocation -->
    <param-name>contextConfigLocation</param-name>
    <!-- classpath:表示导出之后的class路径之下 -->
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>

5. 编写Servlet

package com.sh.controller;

import com.sh.pojo.User;
import org.springframework.context.ApplicationContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/query")
public class UserServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = req.getServletContext();
        ApplicationContext ac = (ApplicationContext) servletContext.getAttribute("ac");
        User user = ac.getBean(User.class);
        System.out.println(user);
    }
}

6. 访问测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1121687.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu下 u2net tensorrt模型部署

TensorRT系列之 Windows10下yolov8 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov8 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov7 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov6 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov5 tensorrt模型加速…

浅析人脸活体检测技术的功能及几种分类

在日常生活工作中&#xff0c;出现了人脸验证、人脸支付、人脸乘梯、人脸门禁等等常见的应用场景。这说明人脸识别技术已经在门禁安防、金融行业、教育医疗等领域被广泛地应用&#xff0c;人脸识别技术的高速发展与应用同时也出现不少质疑。其中之一就是人脸识别很容易被照片、…

DDOS攻击的有效防护方式有哪些?

DDoS攻击简介&#xff1a; DDoS攻击&#xff0c;即分布式拒绝服务攻击&#xff08;Distributed Denial of Service&#xff09;&#xff0c;是一种网络攻击&#xff0c;旨在通过向目标服务器发送大量恶意请求&#xff0c;使服务器资源耗尽&#xff0c;无法满足合法用户的需求&a…

KubeSphere安装KubeEdge

1. kubesphere安装请参考博客 2. 配置master节点 控制台->平台管理->集群管理->自定义CRD&#xff0c;搜索​​clusterconfiguration​​&#xff0c;查看详情&#xff0c;在资源列表中&#xff0c;点击 ​​ks-installer​​ 右侧的图标&#xff0c;然后选择编辑配…

一文带你彻底弄懂ZGC

1 推荐的文章 1.1 必看 干掉1ms以内的Java垃圾收集器ZGC到底是个什么东西&#xff1f; 1.2 选看 ZGC有什么缺点? 2 疑问【皆来自上面两篇文章】 2.1 什么使得用户线程工作的同时&#xff0c;让垃圾收集器可以回收垃圾-读写屏障 ZGC (Z Garbage Collector) 和读写屏障: …

【瑞吉外卖部分功能补充】

瑞吉外卖部分功能补充 菜品的启售和停售 在浏览器控制台点击对应功能后可以看到前端发送的请求是&#xff1a;http://localhost:9999/dish/status/1?ids1413342036832100354&#xff0c;请求方式为POST。 接收到前端参数后&#xff0c;进行controller层代码补全&#xff0c…

简单说明反射和new的区别和反射的使用代码展示

目录 1.反射的认识 2.反射和new的区别 3.反射的使用代码展示 4.反射优点和缺点 1.反射的认识 反射是Java语言的一种机制&#xff0c;它允许程序在运行时检查和操作类、方法、字段等信息&#xff0c;而不需要提前知道它们的具体定义。通过反射&#xff0c;我们可以在运行时动…

直接插入排序——希尔排序

排序——先写单个——再衍生到整体 单个插入排序——在插入前数组里面的数是有序的&#xff0c;然后来了一个数据&#xff0c;就要用这个数组从后往前和这个数比较&#xff0c; 整体的话就是&#xff0c;end从0开始&#xff0c;循环n-1次 void TnsertSort(int* a,int n) {in…

QML之Repeater 控件使用

Repeater 控件是 重复作用 根据 model中的index 数量进行重复 废话不说 直接看如何用 当model 为数字时 Rectangle{height: 1200width: 500visible: trueanchors.fill: parentColumn{spacing: 20Repeater{model: 10delegate: Rectangle{width: 60height: 20color: index%2 …

VulnHub ch4inrulz: 1.0.1

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

【网络编程】应用层——HTTP协议

文章目录 一、HTTP协议简介二、认识URL三、HTTP协议格式1. HTTP请求协议格式2. HTTP响应协议格式 三、构建HTTP请求和响应四、HTTP的方法五、HTTP的状态码六、HTTP常见的Header七、Cookie和Session 一、HTTP协议简介 HTTP 协议 是 Hyper Text Transfer Protocol&#xff08;超文…

苹果ios打包出来的ipa应用APP怎么不能安装?多种安装不上的原因排查

亲爱的同学们&#xff0c;非常高兴能和同学们一起探讨关于苹果应用安装失败的问题。作为一个开发者&#xff0c;我们很可能会遇到这样的情况&#xff1a;开发好一个应用&#xff0c;兴致勃勃地想把它运行到手机上去测试&#xff0c;结果发现安装失败了。而此时&#xff0c;定位…

【2023_10_22计算机热点知识分享】:人工智能

最近计算机领域的热点话题之一是人工智能的发展。人工智能是一种能够模拟人类智能的技术&#xff0c;它可以通过机器学习、深度学习、自然语言处理等技术&#xff0c;实现语音识别、图像识别、自然语言处理等智能化的功能。人工智能技术的发展&#xff0c;正在深刻地改变着人类…

Docker概述、部署、镜像与容器管理

Docker概述、部署、镜像与容器操作 一、Docker是什么&#xff1f;1.1、Docker介绍1.2、Docker的设计宗旨1.3、容器运行条件1.4、容器与虚拟机的区别1.5、Docker核心概念1.5.1、镜像1.5.2、容器1.5.3、仓库 二、Docker部署三、Docker 镜像管理3.1、搜索镜像3.2、查看仓库中有哪些…

01-JVM 内存结构

JVM 内存结构 Java 虚拟机的内存空间分为 5 个部分&#xff1a; 程序计数器Java 虚拟机栈本地方法栈堆方法区 JDK 1.8 同 JDK 1.7 比&#xff0c;最大的差别就是&#xff1a;元数据区取代了永久代。元空间的本质和永久代类似&#xff0c;都是对 JVM 规范中方法区的实现。不过…

Redis --- 安装教程

Redis--- 特性&#xff0c;使用场景&#xff0c;安装 安装教程在Centos7.6下安装Redis5 特性在内存中存储数据可编程的扩展能力持久化集群高可用快速 应用场景实时数据存储作为缓存或者Session存储消息队列 安装教程 在Centos7.6下安装Redis5 1.安装scl源 yum install cento…

云原生微服务 第十章 Spring Cloud Alibaba 之 Nacos discovery

系列文章目录 第一章 Java线程池技术应用 第二章 CountDownLatch和Semaphone的应用 第三章 Spring Cloud 简介 第四章 Spring Cloud Netflix 之 Eureka 第五章 Spring Cloud Netflix 之 Ribbon 第六章 Spring Cloud 之 OpenFeign 第七章 Spring Cloud 之 GateWay 第八章 Sprin…

STM32F4_网络通信(网口)

前言 STM32F4开发板上自带了网口。可以通过开发板自带的网口和LWIP实现&#xff1a;TCP服务器、TCP客服端、UDP以及WEB服务器等四个功能。 1. STM32 以太网简介 STM32F4 芯片自带以太网模块&#xff0c;该模块包括带有专用 DMA 控制器的 MAC 802.3&#xff08;介质访问控制&am…

文心一言 VS 讯飞星火 VS chatgpt (118)-- 算法导论10.3 3题

三、用go语言&#xff0c;在ALLOCATE-OBJECT和 FREE-OBJECT过程的实现中&#xff0c;为什么不需要设置或重置对象的 prev 属性呢? 文心一言&#xff1a; 在 Go 语言中&#xff0c;ALLOCATE-OBJECT 和 FREE-OBJECT 过程的实现通常不需要显式地设置或重置对象的 prev 属性。这…

【MATLAB源码-第54期】基于白鲸优化算法(WOA)和遗传算法(GA)的栅格地图路径规划最短路径和适应度曲线对比。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 ​1.白鲸优化算法&#xff08;WOA&#xff09;&#xff1a; 白鲸优化算法是一种受白鲸捕食行为启发的优化算法。该算法模拟了白鲸群体捕食的策略和行为&#xff0c;用以寻找问题的最优解。其基本思想主要包括以下几点&#x…