Posts Spring——基础(持续更新中)
Post
Cancel

Spring——基础(持续更新中)

Spring

概述

  1. 最受欢迎的企业级 Java 应用程序开发框架
  2. 一个开源的 Java 平台
  3. 轻量级的框架,基础版本只有2M左右
  4. 框架的核心特性是可以用于开发任何 Java 应用程序

三层架构

  1. 表现层:Web层 MVC是表现层的一个设计模型
  2. 业务层:Service层
  3. 持久层:dao层

特性

非侵入式、控制反转(IOC)、依赖注入、面向切面(AOP)、容器、组件化、一站式。。。

参考文章:W3Cschool

体系结构

photo

核心容器

  • Spring-core:提供了框架的基本组成部分,包括IoC和依赖注入功能。
  • Spring-beans:模块提供 BeanFactory,应用工厂模式。
  • context:基于core和beans模块。
  • Spring-expression:提供了强大的表达式语言,用于在运行时查询和操作对象图。

完整依赖关系如下图所示

photo

数据访问/集成

数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:

ps:JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service

Web

Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成。

  • Web 模块提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与 web 相关的部分。
  • Web-MVC 模块为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。
  • Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。
  • Web-Portlet 模块提供了用于 Portlet 环境的 MVC 实现,并反映了 spring-webmvc 模块的功能。

Test、其他

IoC容器

Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。(这些对象被称为 Spring Beans

在Spring出现之前,通常new(实例化)一个实例是由程序员来完成,而“控制反转”就是将new 实例的操作交给Spring容器来做。(BeanFactory在Spring中就是IoC容器的实际代表者

Bean定义

bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。

创建Bean

创建实体类

1
2
3
4
5
6
7
public class PC {
    private String name;
    public PC(){ System.out.println("PC实例化"); }
    public void startUp(){ System.out.println(this.name+"正在启动"); }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

添加applicationContext.xml文件(该文件名可随便起,一般为applicationContext.xml)

1
2
3
4
5
6
7
8
<?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="pc" class="top.jamartin.spring.PC">
        <property name="name" value="我的电脑" />
    </bean>
</beans>

Spring中两种不同类型的容器

  • Spring BeanFactory:给DI(依赖注入)提供最基本的支持。
  • Spring ApplicationContext:该容器添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。

BeanFactory

主要的功能就是为DI(依赖注入)提供支持,该容器接口在org.springframework.beans.factory.BeanFactory中被定义。

ps:在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。

通过XmlBeanFactory生成工厂:(已过时)

1
2
3
4
5
6
@Test
public void TestXmlBeanFactory(){
    XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
    PC pc = factory.getBean("pc", PC.class);
    pc.startUp();
}

ApplicationContext

Application Context 是 BeanFactory 的子接口,也被称为 Spring 上下文。

ps:ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。当然,BeanFactory 仍可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。

最常被使用的 ApplicationContext 接口实现:

  • FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径。
  • ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
  • WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。

这里举例通过ClassPathXmlApplicationContext生成工厂bean。

实体类和applicationContext.xml文件和之前一样,只需要改测试类:

1
2
3
4
5
6
@Test
public void TestClassPathXmlApplicationContext(){
    Application factory = new ClassPathXmlApplicationContext("applicationContext.xml");
    PC pc = factory.getBean("pc", PC.class);
    pc.startUp();
}

结果都是一样的:

image-20220401150944682

Bean的作用域

作用域的属性为scope

作用域 描述
singleton 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
prototype 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
global-session 一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext环境

举例:

将刚刚的applicationContext.xml文件中的bean标签更改一下

1
2
3
4
<bean id="pc" class="top.jamartin.spring.PC" 
      scope="singleton">
    <property name="name" value="我的电脑" />
</bean>

在测试类中多new一个实例

1
2
3
4
5
6
7
8
@Test
public void TestScope(){
    ApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml");
    PC pc = factory.getBean("pc", PC.class);
    pc.startUp();
    PC pc2 = factory.getBean("pc",PC.class);
    pc2.startUp();
}

PC只实例化了一次

image-20220401160013002

再将 “singleton” 改为 ”prototype” 重新测试一下:

image-20220401160230703

Bean的生命周期

首先,在PC类中添加两个方法:init()和destory()

1
2
3
4
5
6
7
8
9
public class PC {
    ...
    public void init(){
        System.out.println("init");
    }
    public void destory(){
        System.out.println("destory");
    }
}

然后更改配置文件

1
2
3
4
5
<bean id="pc" class="top.jamartin.spring.PC" 
      scope="singleton"
      init-method="init" destory-method="destory" >
    <property name="name" value="我的电脑" />
</bean>

在测试类中实例化一个PC

1
2
3
4
5
6
@Test
public void TestScope(){
    ApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml");
    PC pc = factory.getBean("pc", PC.class);
    pc.startUp();
}

依赖注入

Spring 框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系。

基于构造函数的依赖注入

还是通过PC来举例子:

一个PC(电脑)一般需要配一些硬件设备才能使用,例如:鼠标键盘、硬盘等。

先给PC加一个HardWare(硬盘)

1
2
3
4
5
6
7
8
public class HardWare {
    private String name;
    public void read(){ System.out.println("读取数据"); }
    public void write(){ System.out.println("写数据"); }
    public HardWare() { System.out.println("HardWare has constructor"); }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

然后在PC中引入HardWare

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class PC {
    private String name;
    //引入硬盘
    private HardWare hd;
   	public PC(HardWare hd){
        System.out.println("Inside HardWare contructor");
        this.hd = hd;
    }
    
    public PC(){ System.out.println("PC实例化"); }
    public void startUp(){ 
        System.out.println(this.name+"正在启动"); 
        hd.read();
    }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

编辑测试类:

1
2
3
4
5
public void TestConstruct(){
    ApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml");
    PC pc = factory.getBean(PC.class);
    pc.startUp();
}

运行测试类:

photo

可以看到,硬盘实例化后,被注入到了PC中,这就叫做依赖注入。

基于设值函数的依赖注入

以刚刚的例子,硬盘类不变,PC类更为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//PC类
public class PC {
    private String name;
    //引入硬盘
    private HardWare hd;
    
    public HardWare getHd() {
        return hd;
    }

    public void setHd(HardWare hd) {
        this.hd = hd;
        System.out.println("Setter HardWare")
    }
    public PC(){ System.out.println("PC实例化"); }
    public void startUp(){ 
        System.out.println(this.name+"正在启动"); 
        hd.read();
    }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

运行测试类:

photo

注入集合

在上面的例子中介绍了如何注入 Beans,但是如果想要传递多个值,例如List

、Set、Map等,该怎么做呢?(Spring 提供了四种类型的集合的配置元素)

元素 描述
<list> 它有助于连线,如注入一列值,允许重复。
<set> 它有助于连线一组值,但不能重复。
<map> 它可以用来注入名称-值对的集合,其中名称和值可以是任何类型。
<props> 它可以用来注入名称-值对的集合,其中名称和值都是字符串类型。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.tutorialspoint;
import java.util.*;
public class JavaCollection {
   private List addressList;
   private Set addressSet;
   private Map addressMap;
    
   public void setAddressList(List addressList) {
      this.addressList = addressList;
   }
   public List getAddressList() {
      System.out.println("List Elements :"  + addressList);
      return addressList;
   }
   public void setAddressSet(Set addressSet) {
      this.addressSet = addressSet;
   }
   public Set getAddressSet() {
      System.out.println("Set Elements :"  + addressSet);
      return addressSet;
   }
   public void setAddressMap(Map addressMap) {
      this.addressMap = addressMap;
   }
   public Map getAddressMap() {
      System.out.println("Map Elements :"  + addressMap);
      return addressMap;
   }
}

配置文件applicationContext.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<bean id="js" class="top.jamartin.JavaSet">
	<!-- results in a setAddressList(java.util.List) call -->
    <property name="addressList">
    <list>
        <value>INDIA</value>
        <value>Pakistan</value>
        <value>USA</value>
        <value>USA</value>
    </list>
    </property>
	<!-- results in a setAddressSet(java.util.Set) call -->
    <property name="addressSet">
        <set>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
        </set>
    </property>
    <!-- results in a setAddressMap(java.util.Map) call -->
    <property name="addressMap">
        <map>
            <entry key="1" value="INDIA"/>
            <entry key="2" value="Pakistan"/>
            <entry key="3" value="USA"/>
            <entry key="4" value="USA"/>
        </map>
    </property>
</bean>

编写测试类:

1
2
3
4
5
6
7
8
@Test
public void TestCollection(){
    ApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml");
    JavaSet js = factory.getBean(JavaSet.class);
    System.out.println(js.getAddressList());
    System.out.println(js.getAddressMap());
    System.out.println(js.getAddressSet());
}

执行测试类:

photo

Spring Beans 自动装配

自动装配ByName

还是PC机的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//PC类
public class PC {
    private String name;
    //引入硬盘
    private HardWare hd;
    
    public HardWare getHd() {
        return hd;
    }

    public void setHd(HardWare hd) {
        this.hd = hd;
        System.out.println("Setter HardWare")
    }
    public PC(){ System.out.println("PC实例化"); }
    public void startUp(){ 
        System.out.println(this.name+"正在启动"); 
        hd.read();
    }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

如果需要通过ByName自动装配,则配置文件中pc 就需要添加一个autowire属性:

<beans>
    <bean id="pc" class="top.jamartin.PC" autowire="byName">
        <property name="name" value="我的电脑" />
    </bean>
    <bean id="hardware" class="top.jamartin.HardWare" />
</beans>

ByName : 会自动在 beans.xml(容器)的上下文中查找 和自己对象中 set方法 set后面的值对应的 bean 的 id或name。

需要确保配置文件下有一个bean中的id/name与调用Bean的属性相同。

自动装配ByType

<beans>
    <bean id="pc" class="top.jamartin.PC" autowire="byType">
        <property name="name" value="我的电脑" />
    </bean>
    <bean id="HardWare" class="top.jamartin.HardWare" />
</beans>

byType:会自动在beans.xml(容器)上下文中查找,和自己 对象的属性类型 相同的 bean。

由构造函数自动装配

在PC机中加入带有硬盘参数的构造函数:

1
2
3
4
5
6
7
8
9
//PC类
public class PC {
    ...
    private HardWare hd;
    public PC(HardWare hd){
        this.hd = hd;
    }
    ...
}

如果需要通过Constructor自动装配,则配置文件中pc 就需要添加一个autowire属性:

<beans>
    <bean id="pc" class="top.jamartin.PC" autowire="constructor">
        <constructor-arg value="Generic Text Editor"/>
    </bean>
    <bean id="HardWare" class="top.jamartin.HardWare" />
</beans>
This post is licensed under CC BY 4.0 by the author.

持久层框架——Hibernate

宝塔+Lychee部署自己的图床

Comments powered by Disqus.