Spring系列2:Spring容器基本概念和使用

2022年01月16日 阅读数:3
这篇文章主要向大家介绍Spring系列2:Spring容器基本概念和使用,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

本文内容

  1. 简单回顾IoC和DI概念
  2. Spring容器的概念
  3. 的xml配置和初始化
  4. 容器的基本使用
  5. bean的定义和初始化配置

简单理解IoC和DI概念

什么是IoC控制反转?java

通俗地但不严谨地讲,之前传统方式都是应用程序须要一个对象,直接经过new的方式来生成,该对象的管理也是由当前程序本身控制。如今有一个容器,负责将应用程序须要的全部对象都new好了,对象都统一由这个容器管理,应用程序须要对象的时候直接找容器要,应用程序说我不关系对象是怎么来的反正你给我就行。这样和之前的方式不同了,之前是应用程序本身建立和管理,如今交给容器统一建立管理了,控制权发生反转了,这简单理解为IoC。git

什么是DI依赖注入?github

通俗地但不严谨地讲,应用程序须要的对象A依赖于B,由容器直接自动将B依赖给到对象A,能够理解为自动将依赖B注入到A 中了。面试

Spring官方的对于这个2个概念的说明,比较绕,这里也附上。spring

IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern.apache

IoC也称为依赖项注入(DI)。在这个过程当中,对象只能经过构造函数参数、工厂方法的参数或在对象实例被构造或从工厂方法返回后在对象实例上设置的属性来定义它们的依赖关系(即它们所处理的其余对象)。容器而后在建立bean时注入这些依赖项。这个过程本质上是bean自己的逆过程(所以得名“控制反转”),它经过直接构造类来控制依赖项的实例化或位置app

Spring容器的概念和使用

Spring IoC容器负责实例化、配置和组装bean。容器经过读取配置元数据来获取关于实例化、配置和组装哪些对象的指令。配置元数据以XML、Java注释或Java代码表示。maven

Talk is cheap. Show me the code函数

屁话少说,放码过来测试

下面将经过一个案例来快速演示Spring容器的简单使用。

环境准备

IDE: IDEA

Maven: 3.5.6

JDK: java8

建立Maven工程并Spring引入依赖

pom文件以下

<?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>org.example</groupId>
    <artifactId>spring-ioc-quickstart</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <spring.verison>5.2.19.RELEASE</spring.verison>
    </properties>

    <dependencies>
        <!--Spring上下文的依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.verison}</version>
        </dependency>
    </dependencies>

    <build>
        <!--配置文件相关-->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.yml</include>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.yml</include>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>
</project>

建立2个简单类A、B

A依赖B以下

public class A {
    private B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }
}

B以下

public class B {
}

建立Spring的XML配置文件

resources目录建立spring.xml配置文件,并配置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">

    <!--A的定义信息-->
    <bean id="a" class="com.crab.spring.A">
        <!--注入B对象依赖-->
        <property name="b" ref="b"/>
    </bean>

    <!--B的定义信息-->
    <bean id="b" class="com.crab.spring.B"></bean>
</beans>

建立一个测试类

public class MainTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        A a = context.getBean("a", A.class);
        B b = context.getBean("b", B.class);
        System.out.println("A对象:" + a);
        System.out.println("A对象中的B依赖: " + a.getB() );
        System.out.println("B对象:" + b);
    }
}

最终文件目录结构

image-20220112120030437

运行结果

对象AB都统一由ClassPathXmlApplicationContext容器管理,并在A须要B依赖的时候容器自动注入,应用程序须要的时候直接从容器拿接口如context.getBean(),。结合着里面下IoC和DI的概念。以上就是Spring容器的简单使用。

A对象:com.crab.spring.A@2d928643
A对象中的B依赖: com.crab.spring.B@5025a98f
B对象:com.crab.spring.B@5025a98f

Spring 容器对象

BeanFactory 接口

BeanFactory 接口提供了一种高级配置机制,可以管理任何类型的对象,是Spring IoC容器根接口。主要的定义方法以下。

package org.springframework.beans.factory;

public interface BeanFactory {
    // 指定名称获取bean
    Object getBean(String name) throws BeansException;
    // 指定名称和类型获取bean
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;
	// 指定类型获取bean
	<T> T getBean(Class<T> requiredType) throws BeansException;
	// 容器中是否存在bean
	boolean containsBean(String name);
    // 是不是单例
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    
    //
}

很是建议阅读BeanFactory 的源码上的注释说明,很是的详尽,常见的面试:请描述下Spring的生命周期?注释上就有很是官方的完整说明

ApplicationContext接口

ApplicationContext接口是BeanFactory的子接口,在其基础上提供更多企业级的功能。负责实例化、配置和组装bean,支持xml配置文件、java注解、Java-based等方式进行bean的配置。常使用的实现类有: ClassPathXmlApplicationContextFileSystemXmlApplicationContextAnnotationConfigApplicationContext等,后面详细讲解和使用,请保持阅读的热情。

bean定义对象

在 Spring 中,构成应用程序并由 Spring IoC 容器管理的对象称为 bean。这些 bean 是使用提供给容器的配置元数据建立的,如以 XML 定义的形式。

<!--A的定义信息-->
<bean id="a" class="com.crab.spring.A">
    <!--注入B对象依赖-->
    <property name="b" ref="b"/>
</bean>

xml中<bean />配置格式和支持元素以下:

<bean id="myChild" class="com.crab.spring.demo02.ChildBean"
      init-method="init"
      destroy-method="destroy"
      name="childBean,aliasName"
      parent="myParent"
      scope="singleton"
      primary="true"
      depends-on="myParent"
      autowire="byType"
      autowire-candidate="true"
      factory-bean="myFactory"
      factory-method="getObj"
      abstract="false"
      ></bean>
元素 说明
id 惟一ID
class 对应的类,全路径
name 支持名称,能够逗号/分号/空格来分隔多个,多个名称可用道别名
init-method 自定义的初始化方法
destroy-method 自定义的bean被销毁的方法
parent 指定父类引用
scope 指定做用域,如单例和原型,后面详细讲
primary 是不是主要的,用于依赖注入时候容器内有多个同类型的bean时作选择
depends-on 依赖于容器中的另一个bean的引用
autowire 自动注入依赖,指定经过名称或是类型
autowire-candidate 标记自动依赖注入时候选
factory-bean 指定建立该bean的工厂
factory-method 指定建立的工厂方法
abstract 是不是抽象
lazy-init 延迟加载

一般状况下,若是不显式指定name ,Spring默认生成名称的规则是:将类名称转成小驼峰式来命名bean。如AccountManager 生成accountManager

在Spring容器内,bean的定义信息最终是经过接口BeanDefinition及其实现类体现。BeanDefinition接口和抽象类AbstractBeanDefinition`,主要定义以下

package org.springframework.beans.factory.config;

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	void setParentName(@Nullable String parentName);
	void setBeanClassName(@Nullable String beanClassName);
	void setScope(@Nullable String scope);
	void setLazyInit(boolean lazyInit);
	void setDependsOn(@Nullable String... dependsOn);
	void setAutowireCandidate(boolean autowireCandidate);
	void setPrimary(boolean primary);
	void setFactoryBeanName(@Nullable String factoryBeanName);
	void setFactoryMethodName(@Nullable String factoryMethodName);
	void setInitMethodName(@Nullable String initMethodName);
	void setDestroyMethodName(@Nullable String destroyMethodName);
    // 省略
}

package org.springframework.beans.factory.support;

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
		implements BeanDefinition, Cloneable {
	private volatile Object beanClass;
	private String scope = SCOPE_DEFAULT;
	private boolean abstractFlag = false;
	private Boolean lazyInit;
	private int autowireMode = AUTOWIRE_NO;
	private String[] dependsOn;
	private boolean autowireCandidate = true;
	private boolean primary = false;
	private String factoryBeanName;
	private String factoryMethodName;
	private String initMethodName;
	private String destroyMethodName;
}

总结

本文主要讲解了Ioc的概念,演示Spring Ioc容器的快速使用,并详细说明bean定义元素。下一篇将讲bean的依赖注入。

本文对应的源码:

https://github.com/kongxubihai/pdf-spring-series/tree/main/spring-ioc-quickstart

知识分享,转载请注明出处。学无前后,达者为先!