《Spring快速入门》读书笔记 第3章 核心容器

        个人读书笔记,题外话都写在第1章https://blog.csdn.net/u013652550/article/details/119800308


        第3章主要介绍了Bean容器相关的各种知识,包括配置和注入,作用域和生命周期等。

3.1 IOC容器

        Spring提供了BeanFactory、ApplicationContext两个IOC容器来管理众多的bean对象。


1. bean容器的启动

        (建议这一节直接跳了,不过考虑到完整性,还是贴一下大致流程)首先是bean对象的定义,又臭又长的源代码就不贴了,见书31~32页。贴一下成员列表。

beanClass保存bean的class属性。
scope保存bean的作用域。
abstractFlag保存该bean是否抽象。
lazyInit保存是否延迟初始化。
autowireMode保存是否自动装配。
dependencyCheck保存是否坚持依赖。
dependsOn保存依赖于哪些bean(必须提前初始化)。
constructorArgumentValues保存通过构造函数注入的依赖。
propertyValues保存通过setter方法注入的依赖。
factoryBeanName用于factorybean。
factoryMethodName用于factorybean。
initMethodName对应bean的init-method属性。
destroyMethodName对应bean的destroy-method属性。

        bean容器启动的第一步即将xml中每个bean元素分别转换成BeanDefinition对象。第一次看时看不懂最后几项没关系,后面几节马上会讲。

        第二步是将bean注册到beanFactory中。BeanDefinitionRegistry接口提供了以下方法:        

                registerBeanDefinition(String, BeanDefinition);
                removeBeanDefinition(String);
                getBeanDefinition(String);
                containsBeanDefinition(String);
                getBeanDefinitionNames();
                getBeanDefinitionCount();
                isBeanNameInUse(String);

        通过英文单词含义即可见名知意,不再赘述。DefaultListableBeanFactory类中实现了该接口,并将beanDefinition保存在了ConcurrentHashMap中。

        此外,Spring还对外暴露了一些接口来对bean初始化,例如BeanFactoryPostProcessor。(可覆盖、新增甚至重新初始化bean信息)


2. bean容器的实例化

        主要通过反射和CGLIB两种方式。Spring暴露了一些接口,如果目标bean对象实现了这些接口他们对应的方法会被调用,调用顺序见3.4节。就这4个接口来说,调用顺序是表格从上到下的。(PS:是否想起了第1章中@FunctionalInterface的相关知识)(PSS:感觉列表都是没啥用的,继续跳了)

接口方法说明
BeanNameAwaresetBeanName获取该bean在配置文件中对应的id
BeanFactoryAwaresetBeanFactory获取实例化该bean的BeanFactory
InitializingBeanafterPropertiesSetbean实例化、所有属性设置后调用初始化方法
DisposableBeandestroy在bean丢弃的时候调用销毁方法

        本节重点掌握一下bean的配置。

        创建Maven project,并引入spring-core、spring-context。

        这里提一嘴Spring Boot,在本书正文的最后两章我们将学习,他与Spring的一个显著不同就是简化了配置,比如这里说的配置操作都是不需要的。最方便的创建Maven项目的方法就是通过IDEA新建项目->Spring Initialzr,这里新建的是Spring Boot,其实并不需要进行配置,但是我们可以借此练习。关于Maven是什么:Maven 教程 | 菜鸟教程 (runoob.com)

        不变的开头:

<?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
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
</project>

        找到dependencies项,插入:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>

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

        如果代码标红记得点击右上角提示“加载Maven变更”。

        bean的XML配置放在src/main/resources/目录下,删除默认application.properties并新建ApplicationContext.xml进行配置即可。

        开头大体都是如下的:

<?xml version="1.0" encoding="UTF-8" ?>
<beans default-autowire="byName"
       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
            http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

        具体对bean的XML配置法将在下一节一并叙述。

        贴一段经常用的测试代码开头:

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext
                (new String[] {"ApplicationContext.xml"});
        BeanFactory factory = context;

        ((ClassPathXmlApplicationContext) context).close();
    }

        这里讲一下context的获取:可以ClassPathXmlApplicationContext表示从类路径下加载配置文件,相当于默认带classpath:前缀。如果想用绝对路径,需加上file:前缀,更好的解决方案是使用FileSystemXmlApplicationContext。

        (一小段可以跳的废话)ApplicationContext接口实现了BeanFactory接口,故可以直接赋值。它还继承了以下接口:

        MessageSource:为应用提供国际化访问功能。
        ResourcePatternResolver:提供资源(如URL和文件系统)的访问支持。
        ApplicationEventPublisher:引入事件机制。

3.2 Bean的配置

1. 基于XML配置Bean:

        一个<bean>通常需要定义id和class属性。class属性是必须的,id不是必需的,除非该bean被引用,通常都加上。

    <bean id="xmlCollectionsDemo" class="com.example.airdemo.XmlCollectionsDemo"/>

2. 使用注解定义Bean

        POJO:Plain Ordinary Java Object,简单的Java对象。实际就是普通Java Beans,是为了避免和EJB混淆所创造的简称。
        使用@Component注解在类声明处对类进行标注,它可以被Spring容器识别,自动将POJO转换为容器管理的bean。此外还有以下3个功能基本和@Component等效的Bean的衍型注解:
        @Repository:用于对DAO实现类进行标注。
        @Service:用于对Service实现类进行标注。
        @Controller:用于对Controller实现类进行标注。

3. 基于Java类提供Bean定义

        在普通的POJO类中只要标注@Configuration注解,就可以为Spring容器提供bean定义的信息了。每个标注了@Bean的类方法都相当于提供了一个bean的定义信息。

注意在XML中配置开启context扫描。

    <context:component-scan base-package="..."/>

3.3 Bean的注入

1. XML方式注入

属性注入

        在类中实现setter方法后在XML中使用property类配置属性,name表示属性名,value用来设置基本数据类型的属性值。引用时可以用<ref>标签配置bean的id属性。

    <bean id="CleanAir" class="com.demo.model.CleanAir">
        <qualifier value="cleanair"/>
    </bean>
    <bean id="xmlinstance" class="com.demo.model.XMLInstance">
        <property name="air" ref="CleanAir"/>
        <property name="name" value="abc"/>
    </bean>

构造函数注入

        在XML中,使用<constructor-arg>来设置构造函数的参数,index属性设置参数的顺序,参数顺序应该与构造函数一致,ref设置引用bean的id,value设置构造函数参数的值。

    <bean id="xmlconstructinstance" class="com.demo.model.XMLInstance">
        <constructor-arg index="1" ref="CleanAir"/>
        <constructor-arg index="0" value="abc"/>
    </bean>

工厂方法注入

        分为静态工厂方法和非静态工厂方法。在一个类中定义静态方法,或定义一个实例方法。

        1. 静态工厂方法:只需设置工厂方法对应的类,以及对应的工厂方法。

    <bean id="..." class="..." factory-method="..."/>

        2. 实例工厂方法:需要先实例化工厂类,再通过工厂类对象调用实例方法获取bean对象。

    <bean id="xmlfactory" class="..."/>
    <bean id="xmlfactoryinstance" factory-bean="xmlfactory" factory-method="..."/>

常见数据类型注入

        元素可以使用ref指定,或使用<bean>定义新实例。

        1. List与Set属性注入:大体相同,区别为List中元素有序,Set中元素无序。
        2. Map属性注入:使用<entry>配置Map里的元素,key指定索引,value指定值。
        3. Properties属性注入:<props>配置一个properties对象,<prop>配置一条属性,属性key配置索引。

        <property name="lists">
            <list>
                <value>1</value>
                <ref bean="cleanAir"/>
                <bean class="com.example.airdemo.CleanAir"/>
            </list>
        </property>
        <property name="sets">
            <set>
                <value>1</value>
                <ref bean="cleanAir"/>
                <bean class="com.example.airdemo.CleanAir"/>
            </set>
        </property>
        <property name="maps">
            <map>
                <entry key="key1" value="1"/>
                <entry key="key2" value-ref="cleanAir"/>
                <entry key="key3">
                    <bean class="com.example.airdemo.CleanAir"/>
                </entry>
            </map>
        </property>
        <property name="pros">
            <props>
                <prop key="prokey1">prokeyA</prop>
                <prop key="prokey2">prokeyB</prop>
            </props>
        </property>


        4. 自定义属性编辑器:通过继承PropertyEditorSupport的类,重写setAsText方法来实现注入。(记得写setter方法)

    <bean id="customEditorConfigurer"
          class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="java.util.Date" value="..."/>
            </map>
        </property>
    </bean>

        代码示例为Date类。省略处填入自定义的PropertyEditorSupport类的子类的全类名。配置完后将Date当作基本数据类型通过value注入即可。

初始化函数、销毁函数

        在xml配置bean时设置destroy-method、init-method属性值对应两个方法的方法名。注解中:
        @PostConstruct对应init-method。
        @PreDestroy对应destroy-method。

    <bean id="..." class="..." destroy-method="..." init-method="..."/>

2. 注解方式注入

        @Autowired:默认按类型匹配注入bean。
        @Required:适用于bean属性setter方法。
        @Qualifier:@Autowired默认是单实例的(见3.4),以此解决一个接口可能有多个实现的问题。
        @Value:等价于在xml配置属性时property的value设置默认值。
        @Resource:默认按名称匹配注入bean。要求提供一个bean名称的属性,如果属性为空,就自动采用标注处的变量名或方法名作为bean的名称。

        开启注解:以下两行任意一行即可。

    <context:annotatioin-config/>
    <context:component-scan base-package="..."/>

3.4 Bean的作用域和生命周期

1. Bean的作用域

        这里主要注意一下singleton(默认)与prototype:默认每次使用getBean方法获取的bean对象是相同的,而配置scope="prototype"后,每次获取都会创建新对象。(贴一张可以忽略的表)(后3种只有当使用基于Web的ApplicationContext时才生效)

作用域描述
单例(singleton)

默认,每一个Spring IoC容器都拥有唯一的一个实例对象

原型(prototype)一个Bean定义,任意多个对象
请求(request)

一个HTTP请求会产生一个Bean对象,也就是说,每一个HTTP请求都有自己的Bean实例

会话(session)限定一个Bean的作用域为HTTPSession的生命周期
全局会话(global session)限定一个Bean的作用域为全局HTTPSession的生命周期
    <bean id="..." class="..." scope="prototype"/>

2. Bean的生命周期

        (这一节都可以跳了没感觉有什么用)(为了完整性照着书上贴一下)

        容器启动后,会对scope为singleton且非懒加载的bean进行实例化,注入所有属性,然后依次回调接口方法。根据书上示例,BeanPostProcessor接口单独定义一个后置处理器实现,其余接口放在类中实现。调用方法顺序列表如下:

方法所属接口
构造方法\
setter方法(属性注入)\
setBeanNameBeanNameAware
setBeanFactoryBeanFactoryAware
setApplicationContextApplicationContextAware
postProcessBeforeInitializationBeanPostProcessor
afterPropertiesSetInitializingBean
自定义初始化函数(init-method)\
postProcessAfterInitializationBeanPostProcessor
destroyDisposableBean
自定义的销毁方法(destroy-method)\

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值