Spring第一章-IOC容器

本篇主要为学习spring源码做准备,只是粗略列出功能点及部分解释,完全按照spring官网的内容学习,有些内容没有看懂,并标注了问题,还有一些没有用过着实看不懂,尤其后面几节,只是按照官网做了翻译。

官方文档:
https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#beans-beanfactory

针对提出的问题,没看懂的部分及需要细节完善的部分,学习完源码再后续补充

如果有什么问题可以一起交流学习

1. The IoC Container

1.1. Introduction to the Spring IoC Container and Beans

       依赖注入:通过这个过程,对象只能通过构造函数参数,工厂方法的参数或从工厂方法构造或返回对象实例之后在对象实例上设置的属性来定义它们的依赖关系;然后通过创建bean时注入这些依赖项。这个过程本质上是bean本身的逆过程(因此称为控制反转),它通过直接构造类或诸如Service Locator模式之类的机制来控制依赖项的实例化或位置。

       控制反转:这个过程实际上bean本身的逆过程;控制依赖项的实例化

       bean是由ioc容器实例化,组装和管理的对象

       BeanFactory提供了配置框架和基本功能,ApplicationContext添加了更多企业特定的功能。ApplicationContext是BeanFactory的完整超集

1.2. Container Overview

       容器概览:
       org.springframework.context.ApplicationContext 表示ioc容器
       一般不需要显示的创建ioc容器,比如web工程使用web.xml配置实现

       bean配置:注解+xml

       可以使用groovy语言实现bean配置

扫描二维码关注公众号,回复: 4574421 查看本文章

1.3. Bean Overview

       ioc容器管理很多bean
       在容器本身内,这些bean定义表示为BeanDefinition 对象,其中包含以下元数据

        1. 类名配置
        2. 行为配置(生命周期回调,范围等)
        3. 依赖项配置
        4. 在新创建的对象中设置其他配置;比如 池的大小限制或管理连接池中的连接数

       属性配置
在这里插入图片描述

       除了包含关于如何创建特定bean的信息的bean定义之外,ApplicationContext实现还允许注册(由用户)在容器外部创建的现有对象。这是通过getBeanFactory()方法访问ApplicationContext的BeanFactory来实现的,该方法返回BeanFactory DefaultListableBeanFactory实现。DefaultListableBeanFactory通过registerSingleton(…)和registerBeanDefinition(…)方法支持这种注册。然而,典型的应用程序只使用通过常规bean定义元数据定义的bean。

1.3.1. Naming Beans

       bean命名:可以使用id属性,name属性或两者来指定bean标识符,name 属性中指定它们,用逗号(,),分号(;)或空格分隔;
       在Spring 3.1之前的版本中,该id属性被定义为一种xsd:ID类型,它约束了可能的字符。从3.1开始,它被定义为一种xsd:string类型;
       如果您不提供 name或id显式提供,则容器会为该bean生成唯一的名称。但是,如果要通过名称引用该bean,通过使用ref元素或 Service Locator样式查找,则必须提供名称;不提供名称的动机与使用内部bean和自动装配协作者有关。

       bean命名约定:首字母小写,之后首字母大写,一般是类名
       可以使用alias定义别名,但是一般name属性就可以实现
       如果使用Javaconfiguration,则@Bean可以使用注释来提供别名

       内部类定义:com.example.SomeThing$OtherThing

1.3.2. Instantiating Beans

       bean的实例化

  1. 使用构造方法实例化(默认)
  2. 使用静态工厂方法实例化factory-method:使用当前这个bean的指定的这个方法创建实例(同一个类)
  3. 使用实例工厂实例化factory-bean,factory-method 与2类似:使用指定的这个bean的方法创建实例(不同的类)

1.4. Dependencies

1.4.1. Dependency Injection

  1. 基于构造函数的依赖,官方建议使用这种方法

    constructor-arg 指定构造函数的参数:可以为基本类型或bean类型注入
    type/index/name 可以按类型,下表顺序(从0开始),名字进行注入

  2. 基于setter的依赖注入 这种方法注入的参数可选,如果使用第一种可能需要写好多

       创建容器的时候会验证bean的配置,创建单例作用域并创建一个预先实例化的bean;只有请求时才会创建bean --new ClassPathXmlApplicationContext 为什么在这个操作的时候,所有的bean实例就已经被创建了,构造方法或set方法已经被调用了;并不是在getBean时创建的(还是说这个预实例是在配置懒加载时候才有效)======这个操作应该不仅仅是创建容器
       对于循环依赖的场景,使用构造方法注入依赖会报错,只能使用set方法进行注入;

1.4.2. Dependencies and Configuration in Detail

  1. 可以使用特定标签配置依赖,可以保证属性在编译期就是正确的 P标签

    xmlns:p=“http://www.springframework.org/schema/p
    C标签使用内联属性来配置构造函数参数,而不是嵌套constructor-arg;两种方法
    xmlns:c=“http://www.springframework.org/schema/c

  2. 属性可以是基本类型,自定义,也可以是集合List,Properties等;value也不仅仅是bean,也可以是properties文件

  3. 使用parent属性指定目标bean会创建对当前容器的父容器中的bean的引用 —不太懂

  4. inner beans:property 里面定义bean

  5. 复合属性注入,即属性的属性注入

1.4.3. Using depends-on

       针对属性依赖,这种强依赖关系使用ref进行建立;针对弱依赖关系,比如可能在静态方法中的依赖,可以使用depends-on,创建bean时,先加载depends-on的bean,多个使用,分割 —这个有什么用呢,在java中不是会自动装载需要用到的类吗,还是说这个配置是为了在容器中管理这个类

1.4.4. Lazy-initialized Beans

       ApplicationContext会自动加载配置的所有单例bean作为初始化的一部分;如果不希望开始的时候被加载,可以使用lazy-init属性,延迟加载,但是如果该bean被其他类引用,其他类并不是懒加载的,这个时候该bean会作为属性初始化的创建实例
       可以使用配置,设置空间内的懒加载属性;指不在启动时加载,而是在第一次被请求时加载

<beans default-lazy-init="true">

1.4.5. Autowiring Collaborators

       使用autowire属性可以自动装配属性,取代ref的功能
       可选值byName/byType/constructor 根据属性名/属性类型/构造方法参数 自动匹配对应的bean实例

1.4.6. Method Injection

       方法注入:使用lookup-method标签指定的bean及对应的方法注入实例并返回给当前bean使用;例:抽象类,可以使用这个标签指定自己某个方法的实现方法,之后就可以调用了
       方法替换:使用replaced-method标签,使用指定bean替换当前bean中指定的方法;被指定的bean需要实现MethodReplacer接口,使用reimplement方法替换指定的方法;-----为什么这个替换方法会被调用很多遍

       为了避免使代码与spring的耦合度太高:一个解决办法是放弃一些控制反转。通过实现ApplicationContextAware接口,以及每次bean A需要时,对容器进行getBean(“B”)调用,可以让bean A了解容器,从而请求(通常是新的)bean B实例

1.5. Bean Scopes

       生命周期:singleton/prototype/request/session/application/websocket
在这里插入图片描述

1.5.1. The Singleton Scope

       单例:正常配置的bean默认都是单例;可以指定 scope=“singleton”

1.5.2. The Prototype Scope

       任意数量的实例:每次对一个bean的请求(包含getBean及注入到其他bean中)都会返回一个新的bean实例;通常有状态bean使用这种作用域,无状态bean使用单例
scope=“prototype”

1.5.3. Singleton Beans with Prototype-bean Dependencies

       关于单例bean引入一个多例bean作为属性,由于注入只发生一次,所以单例bean持有的这个多例bean的属性实例也是一个
       如果需要使用多例bean的多个属性,可以使用方法注入的自定义生成实例的方式

1.5.4. Request, Session, Application, and WebSocket Scopes

       只有使用web感知的spring applicationContext时(XmlWebApplicationContext),这些作用域才有效,使用普通的ioc容器(ClassPathXmlApplicationContext)会报错

       这些web范围的bean,在使用之前,需要首先进行一些初始化操作

  1. 如果是spring mvc中,实际上是在spring中处理请求,DispatcherServlet无需进行特殊配置
  2. servlet2.5 版本,是在spring之外处理请求DispatcherServlet(如:jsf或struts),则需要注册监听
    org.springframework.web.context.request.RequestContextListener
    ServletRequestListener
  3. servlet3+ 版本可以使用WebApplicationInitializer 接口以编程方式完成

scope=“request” 每个http请求
scope=“session” session级
scope=“application” ServletContext级别

       如果将一个寿命较短的scope注入到一个较长的寿命的scope中;则可以使用aop代理来代替作用域短的bean <aop:scoped-proxy/>cglib实现代理 -----这个方法需要测试

```
<bean id="userPreferences" class="com.something.UserPreferences" scope="session">
    <!-- instructs the container to proxy the surrounding bean -->
    <aop:scoped-proxy/> 
</bean>
```

1.5.5. Custom Scopes

       创建自定义作用域:实现org.springframework.beans.factory.config.Scope接口;这个接口提供可以从作用域中获取对象,将其从作用域中删除,然后销毁
       使用自定义作用域:使用registerScope方法将自定义的作用注册,之后就可以像正常的其他作用域一样配置使用

1.6. Customizing the Nature of a Bean

       spring提供了许多可用于自定义bean特性的接口,分类如下

1.6.1. Lifecycle Callbacks

       第一种类型:生命周期回调
       bean的回调函数:
       要与容器的bean生命周期管理进行交互,可以实现Spring InitializingBean和DisposableBean接口。容器调用afterPropertiesSet()前者,destroy()后者让bean在初始化和销毁​​bean时执行某些操作
       JSR-250 @PostConstruct和@PreDestroy注释通常被认为是在现代Spring应用程序中接收生命周期回调的最佳实践。使用这些注释意味着您的bean不会耦合到特定于Spring的接口;如果您不想使用JSR-250注释但仍想删除耦合,请考虑使用init-method和destroy-method对象定义元数据
       这两种方法的表达是一样的,第一种基于spring解耦
在这里插入图片描述

       <beans default-init-method="init">
       default-destroy-method
       可以通过beans配置,指定该命名空间内的默认init/destory方法

       初始化方法是在依赖注入之后立即调用

       该Lifecycle接口为任何具有自己的生命周期要求的对象(例如启动和停止某些后台进程)定义了基本方法;任何Spring管理的对象都可以实现该Lifecycle接口。然后,当它 ApplicationContext自己接收到启动和停止信号时(例如,对于运行时的停止/重启场景),它将这些调用级联到Lifecycle该上下文中定义的所有实现
       LifecycleProcessor它本身是Lifecycle 接口的扩展。它还添加了另外两种方法来响应刷新和关闭的上下文
       请注意,在销毁之前不保证停止通知。在常规关闭时,所有Lifecyclebean在传播一般销毁回调之前首先收到停止通知。但是,在上下文生命周期中的热刷新或中止刷新尝试时,仅调用destroy方法
       对启停实现更细粒度的控制,可以实现org.springframework.context.SmartLifecycle接口

       在非web应用中关闭ioc容器:使用ConfigurableApplicationContext的registerShutdownHook方法

1.6.2. ApplicationContextAware and BeanNameAware

       第二种类型:ApplicationContextAware和BeanNameAware
       当ApplicationContext创建实现org.springframework.context.ApplicationContextAware接口的对象实例时,将向该实例提供对该ApplicationContext.的引用;这个接口提供一个setApplicationContextAware的方法,入参是ApplicationContext,在创建bean时,如果检测到bean实现了这个接口,容器会将自己作为参数调用这个set方法,这样bean就用了ApplicationContext的属性,可以理解为是对其的一个扩展

       BeanNameAware 该接口提供一个setBeanName(String name) 方法,入参是当前bean在容器中的名字

1.6.3. Other Aware Interfaces

       第三种类型:其他的aware接口
       除此之外还有其他的Aware用于特定的功能的Aware
       如果使用这些接口,程序将绑定spring,需要以编程的方式访问容器的基础框架bean;就是将这些接口配置成bean; 见1.4.6的解决方案
在这里插入图片描述

1.7. Bean Definition Inheritance

       bean定义继承:一个模板方法模式的定义
在这里插入图片描述

1.8. Container Extension Points

       容器扩展:正常不需要子类化ApplicationContext 接口;可以通过插入特殊集成接口的实现来扩展ioc容器

1.8.1. Customizing Beans by Using a BeanPostProcessor

       使用BeanPostProcessor自定义bean

       需要在bean完成实例化,配置和初始化bean之后实现某些自定义的逻辑,可以插入一个或多个BeanPostProcessor的实现
       通过Ordered 接口的属性,可以指定BeanPostProcessor多个实例的调用顺序
       BeanPostProcessor实例在bean(或对象)实例上运行。也就是说,Spring IoC容器实例化一个bean实例,然后BeanPostProcessor实例完成它们的工作
       BeanPostProcessor是容器级别的,只有当您使用容器层次结构时,这才是相关的;在一个容器中定义的bean不会由在另一个容器中定义的BeanPostProcessor进行后处理,即使两个容器都是相同层次结构的一部分(只对当前容器中定义的bean进行处理)
       只要将这个<bean class="scripting.InstantiationTracingBeanPostProcessor"/>实现类配置在beans的空间里,实例化每个bean时对应的方法就会被调用(两个方法postProcessBeforeInitialization/postProcessAfterInitialization 之前之后)

1.8.2. Customizing Configuration Metadata with a BeanFactoryPostProcessor

       与BeanPostProcessor语意相同,唯一区别:BeanFactoryPostProcessor对bean配置元数据进行操作,即可以更改bean实例;
       Spring IoC容器允许BeanFactoryPostProcessor读取配置元数据,并可能在容器实例化BeanFactoryPostProcessor实例以外的任何bean之前对其进行更改。

       示例:
       动态的加载属性 PropertyPlaceholderConfigurer间接实现这个接口
在这里插入图片描述
       spring2.5 之后
<context:property-placeholder location="classpath:com/something/jdbc.properties"/>
       属性覆盖
<context:property-override location="classpath:override.properties"/>

       在PropertyPlaceholderConfigurer不仅将查找在属性Properties 指定的文件。默认情况下,如果它在指定的属性文件中找不到属性,它还会检查Java System属性。您可以通过systemPropertiesMode使用以下三个受支持的整数值之一设置configurer 的属性来自定义此行为

1.8.3. Customizing Instantiation Logic with a FactoryBean

       使用FactoryBean自定义实例化逻辑

       自定义FactoryBean:实现FactoryBean接口;
       使用场景:比如有一个复杂的初始化过程,java实现
       该FactoryBean接口提供了三种方法:

  • Object getObject():返回此工厂创建的对象的实例。实例可以共享,具体取决于此工厂是返回单例还是原型。
  • boolean isSingleton():true如果FactoryBean返回单例或false其他方式返回 。
  • Class getObjectType():返回getObject()方法返回的对象类型,或者null如果事先不知道类型。

1.9. Annotation-based Container Configuration

       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"
    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">

    <context:annotation-config/>

</beans>

1.9.1. @Required

       用于bean的set方法
       此注释指示必须在配置时通过bean定义中的显式属性值或通过自动装配填充受影响的bean属性。如果尚未填充受影响的bean属性,则容器将引发异常。这允许急切和明确的失败,以后避免NullPointerException实例等。我们仍然建议您将断言放入bean类本身(例如,转换为init方法)。即使您在容器外部使用类,这样做也会强制执行那些必需的引用和值。 —自动装配时,被装配的bean也是需要容器来管理的,自动装配的时候会自动注入,为什么还需要这个注解,仅仅是标识吗

1.9.2. Using @Autowired

       主要作用用于表示在多个结果集的情况下,指示容器该进行哪种选择
       还表示自动注入,一般指按类型

       用于构造方法:主要对于多个构造方法的场景,指定容器使用哪个构造方法
------在以构造方法注入的时候,会根据bean配置的属性,自动去寻找对应签名的构造方法进行注入;比如配置的bean有两个constructor-arg,回调两个参数的构造方法,即使在只有一个参数的构造方法上加上这个注解,在加载的时候会报错,那这个注解有啥用呢?还是写法不对
报错信息 :Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)

       还可以用于set方法,任意有参数的方法及字段上
       自动装配,指示的是默认的,可以使用@Autowired(required = false)修改该默认项
       @Inject可以使用JSR 330的注释代替Spring的@Autowired注释
       从Spring Framework 5.0开始,您还可以使用@Nullable注释(任何包中的任何类型的注释 - 例如,javax.annotation.Nullable来自JSR-305):来指定set方法的参数不能为空,修饰参数

1.9.3. Fine-tuning Annotation-based Autowiring with @Primary

       在按类型自动装配的过程中,
       @Primary表示当多个bean可以自动装配到单值依赖项时,应该优先选择特定的bean
       --在自动注入时,一般按类型,如果是接口的话,需要实现类增加@Copmonent 或者 @Service注解来通知容器;如果实现类有多个则需要使用该注解来表明该注入哪个

1.9.4. Fine-tuning Annotation-based Autowiring with Qualifiers

       @Primary当可以确定一个主要候选者时,是通过具有多个实例的类型使用自动装配的有效方式。当您需要更多控制选择过程时,可以使用Spring的@Qualifier注释,可以选择具体哪一个进行注入

       还可以自定义限定符,通过配置待选择值

1.9.5. Using Generics as Autowiring Qualifiers

       还可以使用Java泛型类型作为隐式的限定形式
—这个是咋用的,没看懂例子

1.9.6. Using CustomAutowireConfigurer

       CustomAutowireConfigurer 是一个BeanFactoryPostProcessor允许您注册自己的自定义限定符注释类型的,即使它们没有使用Spring的@Qualifier注释进行注释

<bean id="customAutowireConfigurer"
        class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
    <property name="customQualifierTypes">
        <set>
            <value>example.CustomQualifier</value>
        </set>
    </property>
</bean>

—这个是咋用的,没看懂例子

1.9.7. Injection with @Resource

       Spring还通过@Resource在字段或bean属性setter方法上使用JSR-250 注释来支持注入;在set方法上增加如下注释
@Resource(name="myMovieFinder")

1.9.8. Using @PostConstruct and @PreDestroy

       CommonAnnotationBeanPostProcessor不仅识别@Resource注释,还识别JSR-250生命周期注释
       示例:缓存在初始化时预先填充,在销毁时清除:注释在普通的方法上实现功能

@PostConstruct 初始化
@PreDestroy  销毁

1.10. Classpath Scanning and Managed Components

       类路径扫描和管理组件:上一节的注解提供依赖注入的功能,当仍需将bean配置在xml中;本节通过注解隐式注册,消除xml注册的必要性

1.10.1. @Component and Further Stereotype Annotations

       @Repository注释是满足存储库角色或原型(也称为数据访问对象或DAO)的任何类的标记,此标记的用途之一是异常的自动转换(自动翻译异常)
       Spring提供进一步典型化注解:@Component,@Service,和 @Controller。

  • @Component是任何Spring管理组件的通用构造型。
  • @Repository,@Service和,@Controller是@Component更具体的用例的专业化(分别在持久性,服务和表示层)。

因此,您可以来注解你的组件类有 @Component,但是,通过与注解它们@Repository,@Service或者@Controller ,你的类能更好地被工具处理,或与切面进行关联

1.10.2. Using Meta-annotations and Composed Annotations

       spring提供的元注解:注解的注解
       组合注释:如下示例
在这里插入图片描述

1.10.3. Automatically Detecting Classes and Registering Bean Definitions

       Spring可以自动检测构造型类并使用它注册相应的 BeanDefinition实例ApplicationContext @Service、@Repository
       要自动检测这些类并注册相应的bean,您需要添加 @ComponentScan到您的@Configuration类,其中该basePackages属性是两个类的公共父包。(或者,您可以指定以逗号或分号或空格分隔的列表,其中包含每个类的父包。)

       扩展:@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义;@Configuration @Bean 只是标记这个类或方法是干这个用的,并没有实际的意思,不写也可以,只是更清晰的表示
       @Configuration 下可以使用@ImportResource引入xml的bean配置;@Import引入其他配置类
       @Component/@ComponentScan 组合注册bean

1.10.4. Using Filters to Customize Scanning

       使用Filter自定义扫描,可以使用拦截器过滤需要自动注册的bean
在这里插入图片描述

1.10.5. Defining Bean Metadata within Components

       在组件中定义bean元数据
       纯翻译,没太懂:常规Spring组件中的@Bean方法的处理方式与Spring@Configuration类中的对应方法不同。区别在于@Component类没有通过CGLIB增强以拦截方法和字段的调用。CGLIB代理是在@Configuration类中@Bean方法中调用方法或字段来创建对协作对象的bean元数据引用的方法。这样的方法不是用普通的Java语义调用的,而是通过容器来提供通常的生命周期管理和Spring bean的代理,即使通过引用对@ bean方法的编程调用来引用其他bean。相反,在普通的@组件类中调用“bean”方法中的方法或字段具有标准Java语义,没有特殊的CGLIB处理或其他约束应用。

1.10.6. Naming Autodetected Components

       命名自动检测组件
       当组件作为扫描过程的一部分自动检测时,其bean名称由该扫描程序BeanNameGenerator接口已知的策略生成
       说的应该是自动检测的时候,注解里面的值,可以不必自动生成;比如通过注解注册的类,beanid默认是小写开头的类名,注解的值可以修改这个内容

1.10.7. Providing a Scope for Autodetected Components

       为自动检测组件提供范围
       @Scope(“prototype”)

1.10.8. Providing Qualifier Metadata with Annotations

       使用注释提供限定符元数据:限定字段,方法,参数
       限定容器的选择
       @Qualifier(“Action”)、@Genre(“Action”)、@Offline

1.10.9. Generating an Index of Candidate Components

       生成候选组件索引
       虽然类路径扫描非常快,但可以通过在编译时创建候选的静态列表来提高大型应用程序的启动性能。在此模式下,应用程序的所有模块都必须使用此机制,因为当 ApplicationContext检测到此类索引时,它会自动使用它而不是扫描类路径

       要生成索引,请为包含作为组件扫描指令目标的组件的每个模块添加其他依赖项。以下示例显示了如何使用Maven执行此操作:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-indexer</artifactId>
        <version>5.1.3.RELEASE</version>
        <optional>true</optional>
    </dependency>
</dependencies>

       以下示例显示了如何使用Gradle执行此操作:

dependencies {
    	compileOnly("org.springframework:spring-context-	
indexer:5.1.3.RELEASE")
	}

描述比较粗略,没看懂怎么用

1.11. Using JSR 330 Standard Annotations

       从Spring 3.0开始,Spring提供对JSR-330标准注释(依赖注入)的支持。这些注释的扫描方式与Spring注释相同。要使用它们,您需要在类路径中包含相关的jar

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

1.11.1. Dependency Injection with @Inject and @Named

       @Inject替换@Autowired
       @Named限定参数,可以指定beanid
       @Nullable 限定参数null

1.11.2. @Named and @ManagedBean: Standard Equivalents to the @Component Annotation

       @Named/@ManagedBean 替换@Component 注册bean

1.11.3. Limitations of JSR-330 Standard Annotations

       使用注解时,有些重要的功能不可用
       对应关系

Spring javax.inject.* javax.inject restrictions / comments
@Autowired @Inject @Inject 不能有属性,可以与jdk1.8的 Optional一起使用.
@Component @Named / @ManagedBean JSR-330不提供可组合模型,只是一种识别命名组件的方法
@Scope(“singleton”) @Singleton spring与jsr-330 都提供scope的注解,jsr-330只有单例
@Qualifier @Qualifier / @Named javax.inject.Qualifier 只是一个用于构建自定义元注解,具体string限定符(比如@Qualifier里面带参数) 可以通过javax.inject.Named.实现
@Value - no equivalent
@Required - no equivalent
@Lazy - no equivalent
ObjectFactory Provider javax.inject.Provider是Spring的直接替代品ObjectFactory,只有较短的get()方法名称。它也可以与Spring @Autowired或非注释构造函数和setter方法结合使用

1.12. Java-based Container Configuration

       基于java的容器配置:如何在java代码中使用注解配置spring容器

1.12.1. Basic Concepts: @Bean and @Configuration

       基本概念
       @Bean注释被用于指示一个方法实例,配置和初始化为通过Spring IoC容器进行管理的新对象;@Bean注释与元素扮演的角色相同
       You can use @Bean-annotated methods with any Spring @Component. However, they are most often used with @Configuration beans.
       对类进行注释@Configuration表明其主要目的是作为bean定义的来源

1.12.2. Instantiating the Spring Container by Using

       AnnotationConfigApplicationContext
AnnotationConfigApplicationContext在Spring 3.0中引入的Spring
       使用注解的context
       两种方式注册类

  • 通过这个context的构造方法
  • 通过这个context的register方法
@Configuration
@ComponentScan(basePackages = "com.acme")

等同于

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

等同于

ctx为context的实例
ctx.scan("com.acme");
ctx.refresh();

使用以上配置启用扫描组件

AnnotationConfigWebApplicationContext

1.12.3. Using the @Bean Annotation

在这里插入图片描述
       bean的依赖项

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService(AccountRepository accountRepository) {
        return new TransferServiceImpl(accountRepository);
    }
}

       生命周期回调

@Bean(initMethod = "init")
@Bean(destroyMethod = "cleanup")

       指定bean的范围;或者使用1.10.2示例的组合方式
@Scope("prototype")

       自定义bean名称
@Bean(name = "myThing")

       bean属性
@Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})

       描述信息

@Bean
      @Description("Provides a basic example of a bean")

1.12.4. Using the @Configuration annotation

       该注解表示bean的来源,bean注解对应的依赖关系,之前提到的模板方法等,只有在这个注解下定义才有效
       这个注解的类,最终只是容器中的一个bean

1.12.5. Composing Java-based Configurations

       @Import 可以引入bean
@Import(ConfigA.class)
       多个依赖
@Import({ServiceConfig.class, RepositoryConfig.class})
       基于某些任意的系统状态,有条件地启用或禁用完整的@Configuration类或甚至单个的@Bean方法是非常有用的。一个常见的例子是使用@Profile注释仅在Spring环境中启用了特定概要文件时才激活bea
       @Profile注释实际上是通过使用更灵活的注释@Conditional实现的。@Conditional注释指示特定的org.springframework.context.anno…Condition实现,在注册@Bean之前应该参考这些实现
----这个没试过,需要参考spring的API
       与配置文件结合使用
在这里插入图片描述

1.13. Environment Abstraction

       Enviroment接口是集成在容器中的抽象,它建模应用程序环境的两个关键方面:概要文件和属性
       概要文件是一个命名的、逻辑的bean定义组,只有在给定概要文件处于活动状态时才向容器注册。bean可以被分配给一个配置文件,不管是用XML定义的还是带有注释的。环境对象与概要文件相关的作用是确定当前哪些概要文件(如果有的话)是活动的,以及默认情况下哪些概要文件(如果有的话)应该是活动的。
       属性在几乎所有应用程序中都扮演着重要的角色,并且可能来源于各种来源:属性文件、JVM系统属性、系统环境变量、JNDI、servlet上下文参数、ad-hoc Properties对象、Map对象等等。环境对象与属性的关系的作用是为用户提供一个方便的服务接口,用于配置属性源并从属性源解析属性。

1.13.1. Bean Definition Profiles

       bean定义的配置文件
       使用场景:

  • 与QA或生产中从JNDI查找相同的数据源相比,在开发中针对内存中的数据源进行工作。
  • 仅在将应用程序部署到性能环境中时才注册监视基础结构。
  • 为客户A与客户B部署注册bean的自定义实现。

       @Profile:通过配置改参数,比如:生产测试两套环境使用不同的配置文件或实现类,可以使用@ActiveProfiles指定当前活跃的配置
       @Profile注释允许您在一个或多个指定的概要文件处于活动状态时指示组件有资格注册 —看不懂
在这里插入图片描述
       在xml配置中指定配置

       通过context选择对应的配置

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
多个
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");

-Dspring.profiles.active="profile1,profile2"

       可以指定默认的配置
@Profile("default")

1.13.2. PropertySource Abstraction

spring中enviroment提供可配置属性源层次结构的搜索操作

ApplicationContext ctx = new GenericApplicationContext();
Environment env = ctx.getEnvironment();
boolean containsMyProperty = env.containsProperty("my-property");

       表示my-property是否为当前环境定义
       Environment对象对一组PropertySource对象执行搜索。PropertySource是对键-值对的任何源的简单抽象,Spring的标准环境配置有两个PropertySource对象-一个表示JVM系统属性集(System.getProperties())和一个表示系统环境变量集
       这些默认属性源StandardEnvironment适用于独立应用程序。StandardServletEnvironment 填充了其他默认属性源,包括servlet配置和servlet上下文参数。它可以选择启用a JndiPropertySource
------这个需要测试下,不太懂

       执行的搜索是分层的。默认情况下,系统属性优先于环境变量。因此,如果my-property在调用期间恰好在两个位置都设置了属性env.getProperty(“my-property”),则系统属性值“wins”并返回。请注意,属性值未合并,而是由前面的条目完全覆盖
       对于公共StandardServletEnvironment层次结构,完整层次结构如下,最高优先级条目位于顶部:

  1. ServletConfig参数(如果适用 - 例如,在DispatcherServlet上下文的情况下)
  2. ServletContext参数(web.xml context-param条目)
  3. JNDI环境变量(java:comp/env/条目)
  4. JVM系统属性(-D命令行参数)
  5. JVM系统环境(操作系统环境变量)

       最重要的是,整个机制是可配置的。您可能希望将自定义的属性源集成到此搜索中。为此,请实现并实例化您自己的PropertySource并将其添加到PropertySources当前的集合中Environment。以下示例显示了如何执行此操作

ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());

       在上面的代码中,MyPropertySource在搜索中添加了最高优先级。如果它包含my-property属性,则检测并返回该属性,以支持my-property任何其他属性PropertySource。所述 MutablePropertySources API公开了大量的,其允许该组的属性源的精确操作方法

1.13.3. Using @PropertySource

       该注解可以将PropertySource添加到spring的enviroments中

@Configuration
@PropertySource("classpath:/com/myco/app.properties")

@PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")

1.13.4. Placeholder Resolution in Statements

       占位符:只要customer在enviroment中可用

<beans>
    <import resource="com/bank/service/${customer}-config.xml"/>
</beans>

1.14. Registering a LoadTimeWeaver

       代码织入???

@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
}

xml实现
<beans>
    <context:load-time-weaver/>
</beans>

说明:https://www.cnblogs.com/wade-luffy/p/6073702.html

1.15. Additional Capabilities of the ApplicationContext

       ApplicationContext的附加功能

1.15.1. Internationalization using MessageSource

       国际化
       ApplicationContext接口扩展了一个名为的接口MessageSource,因此提供了国际化(“i18n”)功能。Spring还提供了HierarchicalMessageSource接口,可以分层次地解析消息。这些接口共同提供了Spring影响消息解析的基础
       接口提供getMessage的重载方法

       当ApplicationContext被加载时,它自动搜索MessageSource 在上下文中定义的bean。bean必须具有名称messageSource。如果找到这样的bean,则对前面方法的所有调用都被委托给消息源。如果未找到任何消息源,则ApplicationContext尝试查找包含具有相同名称的bean的父级。如果是,它将使用该bean作为MessageSource。如果 ApplicationContext找不到任何消息源,DelegatingMessageSource则实例化为空 以便能够接受对上面定义的方法的调用

       spring提供两种方式MessageSource的实现,ResourceBundleMessageSource和 StaticMessageSource。两者都是HierarchicalMessageSource为了进行嵌套消息传递而实现的。在StaticMessageSource很少使用,但提供了编程的方式向消息源添加消息
示例:

<beans>
    <bean id="messageSource"
            class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>format</value>
                <value>exceptions</value>
                <value>windows</value>
            </list>
        </property>
    </bean>
</beans>

# in format.properties
message=Alligators rock!

# in exceptions.properties
argument.required=The {0} argument is required.

public static void main(String[] args) {
    MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
    String message = resources.getMessage("message", null, "Default", null);
    System.out.println(message);
}

输出:
Alligators rock!

       {0} 表示这个object数组的标

this.messages.getMessage("argument.required",
            new Object [] {"userDao"}, "Required", null)

       总之,MessageSource是在名为beans.xml的文件中定义的,该文件存在于类路径的根部。messageSource bean定义通过其basenames属性引用许多资源包。列表中传递给basenames属性的三个文件作为文件存在于类路径的根部,分别称为format.properties、exceptions.properties和windows.properties。

       针对国际化,这三个文件可以提供不同的语言环境,输出不同语言的内容,参数是可选的

1.15.2. Standard and Custom Events

       标准化与自定义事件
       ApplicationContext通过ApplicationEvent 类和ApplicationListener接口提供事件处理。如果将实现ApplicationListener接口的bean 部署到上下文中,则每次 ApplicationEvent将其发布到该ApplicationContextbean时,都会通知该bean。从本质上讲,这是标准的观察者模式

       spring提供的标准事件,内置事件
Event Explanation

Event Explanation
ContextRefreshedEvent 在初始化或刷新ApplicationContext时发布(例如,通过在ConfigurableApplicationContext接口上使用.esh()方法)。这里,“initialized”意味着加载所有bean,检测和激活后处理器bean,预实例化单例,并且ApplicationContext对象准备好使用。只要上下文尚未关闭,只要所选ApplicationContext实际上支持这种“热”刷新,就可以多次触发刷新。例如,XmlWebApplicationContext支持热刷新,但是GenericApplicationContext不支持。
ContextStartedEvent 使用ConfigurableApplicationContext接口上的start()方法启动ApplicationContext时发布。这里,“开始”意味着所有生命周期bean都接收一个显式的启动信号。通常,该信号用于在显式停止之后重新启动be an,但是也可以用于启动尚未配置为自动启动的组件(例如,尚未在初始化时启动的组件)。
ContextStoppedEvent 通过在ConfigurableApplicationContext接口上使用stop()方法停止ApplicationContext时发布。在这里,“停止”意味着所有生命周期bean接收显式停止信号。停止的上下文可以通过START()调用重新启动。
ContextClosedEvent 使用ConfigurableApplicationContext接口上的close()方法关闭ApplicationContext时发布。这里,“关闭”意味着所有单独的bean被破坏。封闭的环境达到了它的生命终点。无法刷新或重新启动。
RequestHandledEvent 一个特定于Web的事件,告诉所有bean已经为HTTP请求提供服务。请求完成后发布此事件。此事件仅适用于使用Spring的Web应用程序DispatcherServlet。

       自定义事件:集成ApplicationEvent(官网在这有个详细的示例:一个使用spring实现的观察者模式的示例)

  1. 要发布自定义ApplicationEvent,请在ApplicationEventPublisher上调用publishEvent()方法。通常,这是通过创建实现ApplicationEventPublisherAware的类并将其注册为Spring
    bean来实现的
  2. 在配置时,Spring容器检测到EmailService实现 ApplicationEventPublisherAware并自动调用 setApplicationEventPublisher()。实际上,传入的参数是Spring容器本身。您正通过其ApplicationEventPublisher界面与应用程序上下文进行
    交互
  3. 要接收自定义ApplicationEvent,您可以创建一个实现 ApplicationListener并将其注册为Spring bean的类
  4. 请注意,ApplicationListener通常使用自定义事件的类型进行参数化(BlackListEvent在前面的示例中)。这意味着该onApplicationEvent()方法可以保持类型安全,避免任何向下转换的需要。您可以根据需要注册任意数量的事件侦听器,但请注意,默认情况下,事件侦听器会同步接收事件。这意味着该publishEvent()方法将阻塞,直到所有侦听器都已完成对事件的处理。这种同步和单线程方法的一个优点是,当侦听器接收到事件时,如果事务上下文可用,它将在发布者的事务上下文内运行。如果需要另一个事件发布策略,请参阅Spring的ApplicationEventMulticaster界面的javadoc

       spring4.2 开始,spring提供@EventListener在托管bean的任何公共方法上注册监听器;这样监听类就不需要实现ApplicationListener接口了
       如果监听多个事件
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
       可以使用spel表达式过滤
@EventListener(condition = "#blEvent.content == 'my-event'")
       spel表达式参数说明

Name Location Description Example
Event root object The actual ApplicationEvent. #root.event
Arguments array root object The arguments (as array) used for invoking the target. #root.args[0]
Argument name evaluation context The name of any of the method arguments. If, for some reason, the names are not available (for example, because there is no debug information), the argument names are also available under the #a<#arg> where #arg stands for the argument index (starting from 0). #blEvent or #a0 (you can also use #p0 or #p<#arg>notation as an alias)

       异步事件监听

@EventListener
@Async
  1. 异步监听处理方法如果抛出异常,则他不会传播给调用者
  2. 此类监听器无法发送回复,如果需要将处理结果发送给另一个事件,需要手动发送

       订购监听者:如果需要在一个监听器之前调用一个监听器

@EventListener
@Order(42)

       通用事件:监听泛型的事件

1.15.3. Convenient Access to Low-level Resources

       访问低级资源:参见第二章
       应用程序上下文是ResourceLoader,可以用于加载resource对象。Resource本质上是JDK java.net.URL类的更富特征的版本。事实上,Resource的实现在适当的情况下包装Java.NET.URL的实例。资源可以以透明的方式从几乎任何位置获得低级资源,包括从类路径、文件系统位置、可以用标准URL描述的任何位置以及一些其他变体。如果资源位置字符串是一个没有特殊前缀的简单路径,那么这些资源来自于特定且适合于实际的应用程序上下文类型。
       可以将部署到应用程序上下文中的bean配置为实现特殊的回调接口ResourceLoaderAware,以便在初始化时自动回调,应用程序上下文本身作为ResourceLoader传递。还可以公开类型资源的属性,以便访问静态资源。它们像其他属性一样被注入其中。您可以将这些Resource属性指定为简单的String路径,并依赖一个特殊的JavaBean PropertyEditor(由上下文自动注册)在部署bean时将这些文本字符串转换为实际的Resource对象。
       提供给ApplicationContext构造函数的位置路径实际上是资源字符串,并以简单的形式根据特定的上下文实现适当地处理。例如,ClassPathXmlApplicationContext将简单的位置路径视为类路径位置。您还可以使用带有特殊前缀的位置路径(资源字符串)来强制从类路径或URL加载定义,而不管实际的上下文类型。

1.15.4. Convenient ApplicationContext Instantiation for Web Applications

       web工程中ApplicationContext实例化

  1. 可以使用ContextLoader创建一个ApplicationContext 实例
  2. 可以使用ApplicationContext的一个实现创建
  3. 使用监听创建,如下
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

       侦听器检查上下文配置位置参数。如果参数不存在,侦听器使用/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml作为默认值。当参数确实存在时,侦听器使用预定义的分隔符(逗号、分号和空格)来分离String,并将这些值用作搜索应用程序上下文的位置。支持Ant风格的路径模式。例如/WEB-INF/*Context.xml(对于名称以Context.xml结尾并驻留在WEB-INF目录中的所有文件)和/WEB-INF/**/*Context.xml(对于WEB-INF的任何子目录中的所有此类文件)。

1.15.5. Deploying a Spring ApplicationContext as a Java EE RAR File

       将ApplicationContext 作为java ee rar文件

       可以将Spring部署ApplicationContext为RAR文件,将上下文及其所有必需的bean类和库JAR封装在Java EE RAR部署单元中。这相当于ApplicationContext能够访问Java EE服务器设施的独立引导(仅在Java EE环境中托管)。RAR部署是部署无头WAR文件的一种更自然的替代方案 - 实际上是一个没有任何HTTP入口点的WAR文件,仅用于ApplicationContext在Java EE环境中引导Spring

       RAR部署非常适用于不需要HTTP入口点但仅包含消息端点和预定作业的应用程序上下文。在这样的上下文中的Bean可以使用应用程序服务器资源,例如JTA事务管理器和JNDI绑定的JDBC DataSource实例和JMS ConnectionFactory实例,并且还可以通过Spring的标准事务管理以及JNDI和JMX支持工具向平台的JMX服务器注册。应用程序组件还可以WorkManager通过Spring的TaskExecutor抽象与应用程序服务器的JCA交互。

       有关SpringContextResourceAdapter RAR部署中涉及的配置详细信息,请参阅该类的javadoc 。
       对于将Spring ApplicationContext简单部署为Java EE RAR文件:

  1. 将所有应用程序类打包到一个RAR文件(这是一个具有不同文件扩展名的标准JAR文件)。。将所有必需的库JAR添加到RAR存档的根目录中。。添加
    META-INF/ra.xml部署描述符(如javadoc中SpringContextResourceAdapter所示)和相应的Spring
    XML bean定义文件(通常为“META-INF / applicationContext.xml”)。
  2. 将生成的RAR文件放入应用程序服务器的部署目录中。

       这种RAR部署单元通常是独立的。它们不会将组件暴露给外部世界,甚至不会暴露给同一应用程序的其他模块。与基于RAR的交互ApplicationContext通常通过与其他模块共享的JMS目标进行。ApplicationContext例如,基于RAR的还可以调度一些作业或对文件系统(或类似物)中的新文件作出反应。如果它需要允许来自外部的同步访问,它可以(例如)导出RMI端点,这可以由同一台机器上的其他应用程序模块使用。

1.16. The BeanFactory

       BeanFactory API为Spring的IOC功能提供了基础。它的特定契约主要用于与Spring的其他部分和相关的第三方框架的集成,它的DefaultListableBeanFactory实现是高级GenericApplicationContext容器中的关键委托。
       BeanFactory和相关接口(例如BeanFactoryAware,InitializingBean, DisposableBean)对于其他框架组件的重要结合点。通过不需要任何注释或甚至反射,它们允许容器与其组件之间的非常有效的交互。应用程序级bean可以使用相同的回调接口,但通常更喜欢通过注释或通过编程配置进行声明性依赖注入。
       请注意,核心BeanFactoryAPI级别及其DefaultListableBeanFactory 实现不会对配置格式或要使用的任何组件注释做出假设。所有这些风格都通过扩展(例如XmlBeanDefinitionReader和AutowiredAnnotationBeanPostProcessor)来实现,并BeanDefinition作为核心元数据表示在共享对象上运行。这是使Spring的容器如此灵活和可扩展的本质。

1.16.1. BeanFactory or ApplicationContext?

       本节解释BeanFactory和ApplicatinContext容器级别之间的差异以及对引导的影响。

       除非您有充分的理由不这样做,否则应该使用ApplicationContext,其中GenericApplicationContext及其子类AnnotationConfigApplicationContext是自定义引导的常用实现。这些是Spring核心容器的主要入口点,用于所有常见目的:加载配置文件、触发类路径扫描、以编程方式注册bean定义和带注释的类,以及(从5.0开始)注册功能bean定义。
       因为ApplicationContext包括BeanFactory的所有功能,所以一般建议在普通BeanFactory上使用它,除非需要对bean处理进行完全控制。在ApplicationContext(例如GenericApplicationContext实现)中,通过约定(即,通过bean名称或bean类型-尤其是后处理器)检测几种bean,而普通DefaultListableBeanFactory对任何特殊bean都是不可知的。
       对于许多扩展容器功能,例如注释处理和AOP代理,BeanPostProcessor扩展点是必不可少的。如果仅使用普通DefaultListableBeanFactory处理器,则默认情况下不会检测到并激活此类后处理器。这种情况可能令人困惑,因为您的bean配置实际上没有任何问题。相反,在这种情况下,容器需要通过其他设置完全自举。

       下表列出了BeanFactory和ApplicatinContext接口和实现提供的特性。

Feature BeanFactory ApplicationContext
Bean instantiation/wiringbean实例化、布线? Yes Yes
Integrated lifecycle management集成的生命周期管理 No Yes
Automatic BeanPostProcessor registration自动BeanPostProcessor 注册 No Yes
Automatic BeanFactoryPostProcessor registration自动BeanFactoryPostProcessor 注册 No Yes
Convenient MessageSource access (for internalization)方便MessageSource 访问 No Yes
Built-in ApplicationEvent publication mechanism内置ApplicationEvent 发布机制 No Yes

       为了用DefaultListableBeanFactory显式注册bean后处理器,需要以编程方式调用addBeanPostProcessor

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// populate the factory with bean definitions

// now register any needed BeanPostProcessor instances
factory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
factory.addBeanPostProcessor(new MyBeanPostProcessor());

// now start using the factory

       要将BeanFactoryPostProcessor应用于普通DefaultListableBeanFactory,需要调用它的postProcessBeanFactory方法

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(new FileSystemResource("beans.xml"));

// bring in some property values from a Properties file
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));

// now actually do the replacement
cfg.postProcessBeanFactory(factory);

       在这两种情况下,显式注册步骤都不方便,这就是为什么各种ApplicationContext变体优于DefaultListableBeanFactorySpring支持的应用程序中的普通模式 ,特别是在典型企业设置中依赖于BeanFactoryPostProcessor和BeanPostProcessor扩展容器功能的实例时。

       一个 AnnotationConfigApplicationContext注册后处理器具有所有通用注释,并且可以通过配置注释在封面下引入额外的处理器,例如@EnableTransactionManagement。在Spring的基于注释的配置模型的抽象级别,bean后处理器的概念变成仅仅是内部容器细节。

猜你喜欢

转载自blog.csdn.net/u013523089/article/details/84845196
今日推荐