Spring framework文档第一章读书笔记

本文是作者阅读Spring框架5.0.6版官方文档的精华笔记,重点介绍Spring的IOC容器、bean管理、依赖注入、作用域和配置元数据等内容。适合已有Spring使用经验的读者,旨在帮助读者快速回顾和理解Spring的核心功能,包括bean的命名、实例化、依赖注入的多种方式、自定义bean行为以及不同作用域的bean管理。文档还涵盖了基于XML和Java的配置方式,以及环境抽象、事件处理、国际化等高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该文章是我读Spring英文官方文档的读书笔记,方便以后快速的回忆文档里讲述的内容,而不用再去读一遍官方文档。
文章内容精简掉了官方文档的一些比较浅显易懂的用法,一半是翻译,然后加入部分自己的理解,可以使读者快速的了解Spring提供了些什么功能,以及在什么情况下使用。

该文章只适合有一定Spring使用经验的人,因为博客内容不会讲解某一个功能具体怎么使用,而是只列出Spring有某某功能,以及简单的使用示例。

基于的Spring文档是Spring framework的core模块,版本5.0.6。
官方网站https://docs.spring.io/spring/docs/5.0.6.RELEASE/spring-framework-reference/core.html#spring-core
下载路径http://repo.springsource.org/libs-release-local/org/springframework/spring/5.0.6.RELEASE/

1.1 Introduction

  • org.springframework.beans 和 org.springframework.context 是spring ioc容器的基础。
  • ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext 是ApplicationContext的开箱即用的实现。

1.2 Container overview

  • 基于xml的配置方法,将bean元素放在元素内。而java configuration的配置方法,在有@Configuration的类里使用@Bean注解。
  • 基本的XML_based ocnfiguration metadata
 <?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="..." class="...">
          <!-- collaborators and configuration for this bean go here -->
</bean>
      <bean id="..." class="...">
          <!-- collaborators and configuration for this bean go here -->
</bean>
      <!-- more bean definitions go here -->
</beans>
  • 使用如下代码来加载来自CLASSPATH的配置文件,启动spring ApplicationContext。
   ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
  • 在xml配置文件中,使用import来加载其他配置文件
<beans>
      <import resource="services.xml"/>
      <import resource="resources/messageSource.xml"/>
      <import resource="/resources/themeSource.xml"/>
      <bean id="bean1" class="..."/>
      <bean id="bean2" class="..."/>
  </beans>
  • 使用容器
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml","daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
  • 使用GenericApplicationContext和reader delegates,可以更灵活的配置容器。
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();

1.3 Bean overview

  • spring ioc container 管理一个或多个bean,bean来自configuration metadata,比如xml的标签。Spring使用BeanDefinition来定义bean,其包含以下元数据

    • A package-qualified class name: typically the actual implementation class of the bean being defined.
    • Bean behavioral configuration elements, which state how the bean should behave in the container (scope, lifecycle callbacks, and so forth).
    • References to other beans that are needed for the bean to do its work; these references are also called collaborators or dependencies.
    • Other configuration settings to set in the newly created object, for example, the number of connections to use in a bean that manages a connection pool, or the size limit of the pool.
  • 用表格表示BeanDefinition的properties。Explained in 列表示该属性的详细介绍的章节名

Property Explained in…
class Instantiating beans
name Naming beans
scope Bean scopes
constructor arguments Dependency Injection
properties Dependency Injection
autowiring mode Autowiring collaborators
lazy-initialization mode Lazy-initialized beans
initialization method Initialization callbacks
destruction method Destruction callbacks

* ApplicationContext的实现还允许注册在容器外创建的对象,可以通过调用ApplicationContext的getBeanFactory() 获得BeanFactory的一个实现类DefaultListableBeanFactory,该实现类通过registerSingleton(..) 和 registerBeanDefinition(..)注册。

1.3.1 Naming beans

  • 在XML-based configuration metadata中,使用id和/或name为bean命名。一个bean只能有一个id,但是可以有多个name作为别名。使用name属性指定别名是,用逗号;分号或者空格将多个别名分隔。如果没有为bean指定id或name,name容器会自动分配一个唯一的标识符。
  • 有时候在bean定义的地方设置所以别名并不能满足所有情况,这时可以使用元素,在任何地方设置别名。
<alias name="fromName" alias="toName"/>

1.3.2 实例化bean

  • 一般情况下,在xml配置文件中,容器使用元素的class属性来实例化bean,但是也可以使用factory method来实例化bean。
    Class属性有以下两种用处:
    • 代表性的用处是,容器使用反射生成该属性指定的类的实例。
    • 指明包含静态工厂方法所在的类。
  • 使用反射,调用constructor实例化bean
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
  • 使用静态工厂方法实例化bean。其中class属性指的是包含工厂方法的类,factory-method属性就是工厂方法。
<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>
public class ClientService {
      private static ClientService clientService = new ClientService();
      private ClientService() {}
      public static ClientService createInstance() {
          return clientService;
} }
  • 使用已有实例的工厂方法实例化bean。这种情况下class属性为空,factory-bean属性指向工厂方法所在的bean的引用。
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
 public class DefaultServiceLocator {
      private static ClientService clientService = new ClientServiceImpl();
      public ClientService createClientServiceInstance() {
          return clientService;
    }
}

1.4 Dependencies

1.4.1 Dependency injection

基于构造函数的依赖注入

如果容器能够推断出相应的参数,则不用指定参数类型或者index,如下:

package x.y;
  public class Foo {
      public Foo(Bar bar, Baz baz) {
          // ...
} }
<beans>
      <bean id="foo" class="x.y.Foo">
          <constructor-arg ref="bar"/>
          <constructor-arg ref="baz"/>
      </bean>
      <bean id="bar" class="x.y.Bar"/>
      <bean id="baz" class="x.y.Baz"/>
</beans>

如果不能推断出相应参数,则需要指定,如下:

package examples;
  public class ExampleBean {
      // Number of years to calculate the Ultimate Answer
      private int years;
      // The Answer to Life, the Universe, and Everything
      private String ultimateAnswer;
      public ExampleBean(int years, String ultimateAnswer) {
          this.years = years;
          this.ultimateAnswer = ultimateAnswer;
} }
  • 可以指定type
<bean id="exampleBean" class="examples.ExampleBean">
      <constructor-arg type="int" value="7500000"/>
      <constructor-arg type="java.lang.String" value="42"/>
</bean>
  • 也可以指定index
<bean id="exampleBean" class="examples.ExampleBean">
      <constructor-arg index="0" value="7500000"/>
      <constructor-arg index="1" value="42"/>
</bean
  • 也可以指定参数name。使用这种方式,在编译代码时,必须指定debug flag为enabled,这样spring才能找到构造函数的正确参数名。如果不能指定debug flag为enabled,那么可以使用@ConstructorProperties JDK annotation来指定构造函数。
   <bean id="exampleBean" class="examples.ExampleBean">
      <constructor-arg name="years" value="7500000"/>
      <constructor-arg name="ultimateAnswer" value="42"/>
</bean>
package examples;
  public class ExampleBean {
   
      // Fields omitted
      @ConstructorProperties({
  "years", "ultimateAnswer"})
      public ExampleBean(int years, String ultimateAnswer) {
          this.years = years;
          this.ultimateAnswer = ultimateAnswer;
      }
}
基于setter的依赖注入

就是使用set方法注入

使用构造器注入还是setter注入?

对于强制要求的依赖,使用构造器注入,对于可选的依赖,使用setter注入。
在setter注入上添加@Required注解,也可以强制注入依赖。

dependency resolution process
  • 使用构造器注入,有可能会存在循环依赖的问题。
  • spring容器会发现循环依赖,或者依赖的bean不存在的情况,并抛出异常。
  • spring会在尽可能晚的时候加载bean,对于一些需要在使用时才初始化的bean,如果存在加载异常,并不会在spring启动的时候发现,只会在使用的时候发现问题。
  • 加载bean默认是pre-instantiated的,就是启动容器的时候就初始化bean。也可以设置为需要使用到的时候才加载。
依赖注入的例子

xml的例子,通过setter注入

<bean id="exampleBean" class="examples.ExampleBean">
      <!-- setter injection using the nested ref element -->
      <property name="beanOne">
          <ref bean="anotherExampleBean"/>
      </property>
      <!-- setter injection using the neater ref attribute -->
      <property name="beanTwo" ref="yetAnotherBean"/>
      <property name="integerProperty" value="1"/>
  </bean>
  <bean id="anotherExampleBean" class="examples.AnotherBean"/>
  <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

通过构造器注入

   <bean id="exampleBean" class="examples.ExampleBean">
      <!-- constructor injection using the nested ref element -->
      <constructor-arg>
          <ref bean="anotherExampleBean"/>
      </constructor-arg>
      <!-- constructor injection using the neater ref attribute -->
      <constructor-arg ref="yetAnotherBean"/>
      <constructor-arg type="int" value="1"/>
  </bean>
  <bean id="anotherExampleBean" class="examples.AnotherBean"/>
  <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

通过静态工厂方法注入

<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance">
      <constructor-arg ref="anotherExampleBean"/>
      <constructor-arg ref="yetAnotherBean"/>
      <constructor-arg value="1"/>
</bean>
  <bean id="anotherExampleBean" class="examples.AnotherBean"/>
  <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
 public class ExampleBean {
      // a private constructor
      private ExampleBean(...) {
          ...
}
      // a static factory method; the arguments to this method can be
      // considered the dependencies of the bean that is returned,
      // regardless of how those arguments are actually used.
      public static ExampleBean createInstance (
          AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
          ExampleBean eb = new ExampleBean (...);
          // some other operations...
          return eb;
} }

1.4.2 依赖和配置的细节

直接类型,原始类型、String等
  • 元素的value属性
 public class ExampleBean {
      // a private constructor
      private ExampleBean(...) {
          ...
}
      // a static factory method; the arguments to this method can be
      // considered the dependencies of the bean that is returned,
      // regardless of how those arguments are actually used.
      public static ExampleBean createInstance (
          AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
          ExampleBean eb = new ExampleBean (...);
          // some other operations...
          return eb;
} }
  • 也可以使用p-namespace
   <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:p="http://www.springframework.org/schema/p"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd">
      <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
          destroy-method="close"
          p:driverClassName="com.mysql.jdbc.Driver"
          p:url="jdbc:mysql://localhost:3306/mydb"
          p:username="root"
          p:password="masterkaoli"/>
</beans>
  • 也可以使用java.util.Properties实例。spring会通过PropertyEditor,将元素里的文字转换为java.util.Properties实例。
<bean id="mappings"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      <!-- typed as a java.util.Properties -->
      <property name="properties">
          <value>
              jdbc.driver.className=com.mysql.jdbc.Driver
              jdbc.url=jdbc:mysql://localhost:3306/mydb
          </value>
      </property>
</bean>
对其他bean的引用
  • 使用在 或者使用ref属性,可以引用bean
    <ref bean="someBean"/>
  • 使用parent属性,指定引用父容器的bean
<!-- in the parent context -->
  <bean id="accountService" class="com.foo.SimpleAccountService">
      <!-- insert dependencies as required as here -->
</bean>
<!-- in the child (descendant) context -->
  <bean id="accountService" <!-- bean name is the same as the parent bean -->
      class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="target">
          <ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
      </property>
      <!-- insert other configuration and dependencies as required here -->
  </bean>
内部类
  • 在和元素中使用元素,可以指定内部类。
<bean id="outer" class="...">
      <!-- instead of using a reference to a target bean, simply define the target bean
inline -->
      <property name="target">
          <bean class="com.example.Person"> <!-- this is the inner bean -->
              <property name="name" value="Fiona Apple"/>
              <property name="age" value="25"/>
          </bean>
      </property>
  </bean>
集合
<bean id="moreComplexObject" class="example.ComplexObject">
      <!-- results in a setAdminEmails(java.util.Properties) call -->
      <property name="adminEmails">
          <props>
              <prop key="administrator">administrator@example.org</prop>
              <prop key="support">support@example.org</prop>
              <prop key="development">development@example.org</prop>
          </props>
      </property>
      <!-- results in a setSomeList(java.util.List) call -->
      <property name="someList">
          <list>
              <value>a list element followed by a reference</value>
              <ref bean="myDataSource" />
          </list>
</property>
      <!-- results in a setSomeMap(java.util.Map) call -->
      <property name="someMap">
          <map>
              <entry key="an entry" value="just some string"/>
              <entry key ="a ref" value-ref="myDataSource"/>
          </map>
</property>
      <!-- results in a setSomeSet(java.util.Set) call -->
      <property name="someSet">
          <set>
              <value>just some string</value>
              <ref bean="myDataSource" />
          </set>
      </property>
  </bean>
集合合并,当子类继承父类的集合属性时,可以继承父类已有的集合的值。merge=true指明了继承父类的集合值。
<beans>
      <bean id="parent" abstract="true" class="example.ComplexObject">
          <property name="adminEmails">
              <props>
                  <prop key="administrator">administrator@example.com</prop>
                  <prop key="support">support@example.com</prop>
              </props>
          </property>
      </bean>
      <bean id="child" parent="parent">
          <property name="adminEmails">
              <!-- the merge is specified on the child collection definition -->
              <props merge</
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值