Spring初识(一)

一、引言


1.1 原生web开发中存在哪些问题?

  • 传统Web开发存在硬编码所造成的过度程序耦合(例如:Service中作为属性Dao对象)。

  • 部分Java EE API较为复杂,使用效率低(例如:JDBC开发步骤)。

  • 侵入性强,移植性差(例如:DAO实现的更换,从Connection到SqlSession)。

二、Spring框架


2.1 概念

什么是Spring ​ Spring是分层的JavaSE/EE full-stack(一站式) 轻量级开源框架,以IOC(Inverse of Control 控制反转)和AOP(Aspect Oriented Programming 面向切面编程为内核)

Spring是众多优秀设计模式的组合(工厂、单例、代理、适配器、包装器、观察者 ......)

分层: JavaEE的三层结构:web层、业务层、数据访问层(持久层,集成层) ​ Struts2是web层基于MVC设计模式框架. ​ Mybatis,Hibernate是持久的一个ORM的框架. ​ 一站式: ​ Spring框架有对三层的每层解决方案: ​ web层:Spring MVC. ​ 持久层:JDBC Template (了解) ​ 业务层:Spring的Bean管理

Spring的好处: ​ 方便解耦,简化开发 ​ Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理 ​ AOP编程的支持 ​ Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能 ​ 声明式事务的支持 ​ 只需要通过配置就可以完成对事务的管理,而无需手动编程 ​ 方便程序的测试 ​ Spring对Junit4支持,可以通过注解方便的测试Spring程序 ​ 方便集成各种优秀框架 ​ Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持 ​ Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,降低JavaEE API的使用难度

2.2 访问与下载

官方网站:Spring | Home

下载地址:JFrog

三、Spring架构组成


Spring架构由诸多模块组成,可分类为

  • 核心技术:依赖注入,事件,资源,i18n,验证,数据绑定,类型转换,SpEL,AOP

  • 测试:模拟对象,TestContext框架,Spring MVC测试,WebTestClient。

  • 数据访问:事务,DAO支持,JDBC,ORM。

  • Spring MVC和 Spring WebFlux Web框架。

  • 集成:远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存。

  • 语言:Kotlin,Groovy,动态语言。

Spring架构组成

GroupIdArtifactId说明
org.springframeworkspring-beansBeans 支持,包含 Groovy
org.springframeworkspring-aop基于代理的AOP支持
org.springframeworkspring-aspects基于AspectJ 的切面
org.springframeworkspring-context应用上下文运行时,包括调度和远程抽象
org.springframeworkspring-context-support支持将常见的第三方类库集成到 Spring 应用上下文
org.springframeworkspring-core其他模块所依赖的核心模块
org.springframeworkspring-expressionSpring 表达式语言,SpEL
org.springframeworkspring-instrumentJVM 引导的仪表(监测器)代理
org.springframeworkspring-instrument-tomcatTomcat 的仪表(监测器)代理
org.springframeworkspring-jdbc支持包括数据源设置和 JDBC 访问支持
org.springframeworkspring-jms支持包括发送/接收JMS消息的助手类
org.springframeworkspring-messaging对消息架构和协议的支持
org.springframeworkspring-orm对象/关系映射,包括对 JPA 和 Hibernate 的支持
org.springframeworkspring-oxm对象/XML 映射(Object/XML Mapping,OXM)
org.springframeworkspring-test单元测试和集成测试支持组件
org.springframeworkspring-tx事务基础组件,包括对 DAO 的支持及 JCA 的集成
org.springframeworkspring-webweb支持包,包括客户端及web远程调用
org.springframeworkspring-webmvcREST web 服务及 web 应用的 MVC 实现
org.springframeworkspring-webmvc-portlet用于 Portlet 环境的MVC实现
org.springframeworkspring-websocketWebSocket 和 SockJS 实现,包括对 STOMP 的支持
org.springframeworkspring-jclJakarta Commons Logging 日志系统

四、Spring入门


4.1 导入依赖

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

4.2 在\src\main\resources目录下创建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 http://www.springframework.org/schema/beans/spring-beans.xsd">
​
        <bean id="userDao" class="dao.UserDaoImpl"></bean>
        
    </beans>

4.3 测试(记着先创建类蛤,这里就不用说类怎么创建了吧)

@Test
    public  void  test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
​
        UserDao userDao = context.getBean(UserDao.class);
​
        System.out.println(userDao);
    }

4.4BeanFactory与ApplicationContext区别

ApplicationContext:它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。
BeanFactory:它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。

ApplicationContext对BeanFactory提供了扩展:
国际化处理
事件传递
Bean自动装配
各种不同应用层的Context实现
早期开发使用BeanFactory.

五、Spring对bean的管理细节


5.1创建bean的三种方式

Bean元素:使用该元素描述需要spring容器管理的对象 ​ class属性:被管理对象的完整类名. ​ name属性:给被管理的对象起个名字.获得对象时根据该名称获得对象. ​ id属性: 与name属性作用相同.

第一种方式:使用默认构造函数创建。


   在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
   采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。

<bean id="user" class="com.qwz.dao.impl.UserDaoImpl"></bean>




第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)

首先这是我的一个实体类car

package com.qwz.dao.entity;

public class Car {
    private Integer id;
    private String name;
    private String type;
    
    public Car(){}

    public Car(Integer id, String name, String type) {
        this.id = id;
        this.name = name;
        this.type = type;
    }

    public Integer getId() {
        return id;
    }

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

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

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

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

创建实体类的工厂

package com.qwz.dao.entity;

public class GetCar {


    public  Car getCar (){
        System.out.println("我是静态工厂创建bean对象");
        try {
            Car car = (Car)Class.forName("com.qwz.dao.entity.Car").newInstance();
            car.setName("法拉利");
            return car;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

在applicationContext.xml中使用工厂创建bean对象

    <bean id="getCar" class="com.qwz.dao.entity.GetCar"></bean>
    <bean id="get" factory-bean="getCar"  factory-method="getCar"></bean>


第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)

将生成bean对象的方法改为静态的时候

package com.qwz.dao.entity;

public class GetCar {


    public static Car getCar (){
        System.out.println("我是静态工厂创建bean对象");
        try {
            Car car = (Car)Class.forName("com.qwz.dao.entity.Car").newInstance();
            car.setName("法拉利");
            return car;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

配置文件为这样:

    <bean id="getCar" class="com.qwz.dao.entity.GetCar" factory-method="getCar"></bean>


5.2 bean对象的作用范围

bean标签的scope属性:
   作用:用于指定bean的作用范围
   取值: 常用的就是单例的和多例的
   singleton:单例的(默认值)(也就是只能创建出一个对象)
   prototype:多例的(可以创建出很多对象)
   request:作用于web应用的请求范围
   session:作用于web应用的会话范围
   global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session


 

5.3 bean对象的生命周期

生命周期属性
     配置一个方法作为生命周期初始化方法. spring会在对象创建之后立即调用. init-method
     配置一个方法作为生命周期的销毁方法. spring容器在关闭并销毁所有容器中的对象之前调用. destory-method

(注意,如果为多例的时候,销毁有可能不执行,因为不知道要销毁哪个对象)

举个栗子:

首先我创建了一个car类 里面有无参和有参构造,定义了初始化方法 init() destroy()

package com.qwz.dao.entity;

public class Car {
    private Integer id;
    private String name;
    private String type;

    public Car(){
        System.out.println("我是无参构造方法");
    }

    public Car(Integer id, String name, String type) {
        this.id = id;
        this.name = name;
        this.type = type;
    }

    //定义初始化和销毁的方法
    public static void init(){
        System.out.println("我是初始化方法");
    }
    public static void destroy(){
        System.out.println("我是销毁方法");
    }

    public Integer getId() {
        return id;
    }

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

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

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



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

配置文件如下(这里面我定义了两个bean实体类,其实只定义一个就行了,这个只是为了向大家显示一个特性,我在id为car1中定义了init和destroy方法,现在我获取id为car的对象,发现也照样会打印出初始化和销毁)

    <bean id="car1" class="com.qwz.dao.entity.Car"
    init-method="init" destroy-method="destroy"></bean>

    <bean id="car" class="com.qwz.dao.entity.Car" scope="prototype">
    <constructor-arg name="id" value="1" type="java.lang.Integer"></constructor-arg>
    <constructor-arg name="name" value="法拉利" type="java.lang.String"></constructor-arg>
    <constructor-arg name="type" value="911" type="java.lang.String"></constructor-arg>
    </bean>

测试类如下:

@org.junit.Test
    public void test2(){
        ClassPathXmlApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        Car car = (Car)applicationContext.getBean("car");
        System.out.println(car);
        applicationContext.close();
    }

结果如下(这个结果有点错误蛤 是用的带参的构造方法)

 当scope改为多例的时候,每次都会创建出新对象,这时候销毁的方法就不执行了(这个结果有点错误蛤 是用的带参的构造方法)

六、Spring中的依赖注入


6.1 Spring中的依赖注入

依赖注入:Dependency Injection
   IOC的作用:降低程序间的耦合(依赖关系)
   依赖关系的管理:以后都交给spring来维护,在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明
   
依赖关系的维护:就称之为依赖注入。
   
依赖注入:
   能注入的数据:
       基本类型和String
       其他bean类型(在配置文件中或者注解配置过的bean)
       复杂类型/集合类型
       
   注入的方式:
       第一种:使用构造函数提供
       第二种:使用set方法提供
       第三种:使用注解提供

6.2 构造函数注入

使用的标签:constructor-arg
   标签出现的位置:bean标签的内部
   
   标签中的属性:
       type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
       index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
       name:用于指定给构造函数中指定名称的参数赋值                                    
   
       value:用于提供基本类型和String类型的数据
       ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象

优势:
    在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。

弊端:
    改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。

举个栗子

Person类

package com.qwz.dao.entity;

public class Person {

    private String name;
    private String age;
    private String sex;
    private Car car;

    public Person() {
    }

    public Person(String name, String age, String sex, Car car) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.car = car;
    }

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", sex='" + sex + '\'' +
                ", car=" + car +
                '}';
    }
}
  <bean id="person" class="com.qwz.dao.entity.Person">
    <constructor-arg name="name" value="张三四五" type="java.lang.String"></constructor-arg>
    <constructor-arg name="age" value="21" type="java.lang.String"></constructor-arg>
    <constructor-arg name="sex" value="男" type="java.lang.String"></constructor-arg>
    <constructor-arg ref="car" ></constructor-arg>
    </bean>

6.3 set方法注入

涉及的标签:property
   出现的位置:bean标签的内部
   
   标签的属性:
       name:用于指定注入时所调用的set方法名称
       value:用于提供基本类型和String类型的数据
       ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
优势:
    创建对象时没有明确的限制,可以直接使用默认构造函数

弊端:
    如果有某个成员必须有值,则获取对象是有可能set方法没有执行。



举个栗子:

新建一个studnet类

package com.qwz.pojo;

import com.qwz.dao.entity.Car;
import lombok.Data;

@Data
public class Student {
    private Integer id;
    private String name;
    private String classes;
    private Car car;
}

配置文件:

 <bean id="student" class="com.qwz.pojo.Student">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="classes" value="10"></property>
        <property name="car" ref="car"></property>
    </bean>

6.4 复杂类型的注入/集合类型的注入

  用于给List结构集合注入的标签:
  list array set
  用于个Map结构集合注入的标签:
  map  props

package com.qwz.pojo;

import lombok.Data;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

@Data
public class MyTests {
    private Integer[] integers;
    private List list;
    private Set set;
    private Map map;
    private Properties properties;
}

配置文件:

  <bean id="myTest" class="com.qwz.pojo.MyTests">
        <property name="integers">
        <array>
            <value>1</value>
            <value>2</value>
            <value>3</value>
        </array>
    </property>
        <property name="list">
            <list>
                <value>打飞机</value>
                <ref bean="car"></ref>
            </list>
        </property>
        <property name="set">
            <set>
                <value>123</value>
                <value>123</value>
                <value>456</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="username" value="张四"></entry>
                <entry key-ref="student" value-ref="car"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="root">1234</prop>
                <prop key="name">钱五</prop>
                <prop key="age">48</prop>
            </props>
        </property>
    </bean>

结果比较长

 

6.5 注解方法注入(需要在applicationContext.xml中的添加context约束

(1)用于创建对象的


   他们的作用就和在XML配置文件中编写一个<bean>标签实现的功能是一样的
       Component:用于把当前类对象存入spring容器中
       value属性:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。
       
              Controller:一般用在表现层
              Service:一般用在业务层
              Repository:一般用在持久层


       以上三个注解的作用和属性与Component相同,是spring框架为我们提供明确的三层使用的注解


     
(2)用于注入数据的
    他们的作用就和在xml配置文件中的bean标签中写一个<property>标签的作用是一样的


   Autowired:自动按照类型注入
   Qualifier:在按照类中注入的基础之上再按照名称注入,value属性:用于指定注入bean的id
   Resource:直接按照bean的id注入。它可以独立使用,name属性:用于指定bean的id
   
注意:以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现,另外,集合类型的注入只能通过XML来实现。因为Resource注解是J2EE的,而不是Spring本身的,所以在使用时需要在pom.xml中导入依赖:

  

 <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
    </dependency>


   Value:用于注入基本类型和String类型的数据

(3)用于改变作用范围的

    作用和在bean标签中使用scope属性实现的功能是一样的
   Scope:用于指定bean的作用范围
   value:指定范围的取值。常用取值:singleton prototype



(4)和生命周期相关

    作用和在bean标签中使用init-method和destroy-methode的作用是一样的
   PreDestroy:用于指定销毁方法
   PostConstruct:用于指定初始化方法

实体类Car

package com.qwz.dao.entity;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Data
@Component(value = "car")
@Scope
public class Car {
    @Value("2")
    private Integer id;
    @Value("保时捷")
    private String name;
    @Value("718")
    private String type;

    @PostConstruct
    public static void init(){
        System.out.println("我是初始化方法");
    }
    @PreDestroy
    public static void destroy(){
        System.out.println("我是销毁的方法");
    }
}

Person类

package com.qwz.dao.entity;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Data
@Component(value = "person")
@Scope
public class Person {
    @Value("张三")
    private String name;
    @Value("25")
    private String age;
    @Value("男")
    private String sex;
    @Autowired
    @Qualifier(value = "car")
    private Car car;


}

配置文件:

<?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:component-scan base-package="com.qwz.dao.entity"></context:component-scan>
</beans>

测试类

 @org.junit.Test
    public void test3(){
        ClassPathXmlApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person)applicationContext.getBean("person");
        System.out.println(person);
    }

结果为:


在当前applicationContext.xml配置文件中引入其他配置文件
<import resource="other.xml"></import>

Context.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"
       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:component-scan base-package="com.qwz.dao.entity"></context:component-scan>
</beans>

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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <import resource="context.xml"></import>
</beans>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

宇智波波奶茶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值