1.3。Bean总览

Spring IoC容器治理一个或多个bean。这些bean是应用您提供给容器的配置元数据创立的(例如,以XML <bean/>定义的模式 )。

在容器自身内,这些bean定义示意为BeanDefinition对象,其中蕴含(除其余信息外)以下元数据:

包限定的类名:通常,定义了Bean的理论实现类。
Bean行为配置元素,用于申明Bean在容器中的行为(作用域,生命周期回调等)。
援用其余bean进行其工作所需的bean。这些援用也称为协作者或依赖项。
要在新创建的对象中设置的其余配置设置-例如,池的大小限度或在治理连接池的Bean中应用的连接数。

该元数据转换为形成每个bean定义的一组属性。下表形容了这些属性:

属性解释
实例化bean
名称bean名称
生命周期bean生命周期
结构函数参数依赖注入
属性依赖注入
主动注入模式主动注入的合作者
提早初始化模式懒初始化bean
初始化办法初始化回调
销毁形式销毁回调

除了蕴含无关如何创立特定bean的信息的bean定义外,这些ApplicationContext实现还容许注册在容器内部(由用户)创立的现有对象。这是通过办法拜访ApplicationContext的BeanFactory的getBeanFactory()来实现,该办法返回BeanFactory的DefaultListableBeanFactory实现。DefaultListableBeanFactory 通过registerSingleton(..)和 registerBeanDefinition(..)办法反对此注册。然而,典型的应用程序仅应用通过惯例bean定义元数据定义的bean。

自定义类  不带任何注解    public class LearnBean {        public LearnBean(String name) {        }        public String getString(){            return "learnSpring";        }    }    第一种:AnnotationConfigApplicationContext自带的registerBean办法,能够传入class和结构参数    AnnotationConfigApplicationContext annotationConfigApplicationContext =                                 new AnnotationConfigApplicationContext();    annotationConfigApplicationContext.registerBean(LearnBean.class,"");    annotationConfigApplicationContext.refresh();    LearnBean bean = (LearnBean) annotationConfigApplicationContext.getBean("learnBean");    System.out.println(bean.getString());    第二种:还能够传入 class和beanDefinition也就是配置元数据 这个和 getBeanFactory().registerBeanDefinition(..)是一个意思    AnnotationConfigApplicationContext annotationConfigApplicationContext =                                 new AnnotationConfigApplicationContext();        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(LearnBean.class);    ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();    constructorArgumentValues.addIndexedArgumentValue(0,"111");    rootBeanDefinition.setConstructorArgumentValues(constructorArgumentValues);    annotationConfigApplicationContext.registerBeanDefinition("learnBean",rootBeanDefinition);    annotationConfigApplicationContext.refresh();    LearnBean bean = (LearnBean) annotationConfigApplicationContext.getBean("learnBean");    System.out.println(bean.getString());        留神:如果不写    annotationConfigApplicationContext.refresh();就会报错Exception in thread "main" java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@68de145 has not been refreshed yet    at org.springframework.context.support.AbstractApplicationContext.assertBeanFactoryActive(AbstractApplicationContext.java:1096)    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1108)    at org.springframework.example.DebuggerSpringMain.main(DebuggerSpringMain.java:40)        

Bean元数据和手动提供的单例实例须要尽早注册,以便容器在主动拆卸和其余自省步骤中正确地推理它们。尽管在某种程度上反对笼罩现有元数据和现有单例实例,然而在运行时(与对工厂的实时拜访同时)对新bean的注册不被正式反对,并且可能导致并发拜访异样,bean容器中的状态不统一或都。

很显然注册太晚,就无奈和Spring根底的步骤交融,一些依赖注入无奈实现
1.3.1。bean的命名

每个bean具备一个或多个标识符。这些标识符在承载Bean的容器内必须惟一。
一个bean通常只有一个标识符。然而,如果须要多个,则能够将多余的别名视为别名。

在基于XML配置文件,您能够应用id属性,name属性,或两者来指定bean标识符。id属性使您能够准确指定一个ID。
依照常规,这些名称是字母数字(“myBean”,“someService”等),但它们也能够蕴含特殊字符。如果要为bean引入其余别名,还能够在name属性中指定它们,并用逗号(,),分号(;)或空格分隔。
作为历史记录,在Spring3.1之前的版本中,该id属性被定义为一种xsd:ID类型,该类型限度了可能的字符。从3.1开始,它被定义为xsd:string类型。
请留神,Bean id唯一性仍由容器强制执行,只管不再由XML解析器执行。

您不须要为bean 提供name或id。如果不提供 name或id显式提供,则容器将为该bean生成一个惟一的名称。
然而,如果您心愿通过应用ref元素或服务定位器款式查找通过名称援用那个bean,那么您必须提供一个名称。应用外部bean 和 主动装配合的时候 通常不须要应用名称。

###### Bean命名约定约定是在命名bean时将规范Java约定用于实例字段名称。也就是说,bean名称以小写字母结尾,并从那里用驼峰式大小写。这样的名字的例子包含accountManager, accountService,userDao,loginController,等等。统一地命名Bean使您的配置更易于浏览和了解。另外,如果您应用Spring AOP,则在将切点利用于名称相干的一组bean时,它会很有帮忙。通过在类门路中进行组件扫描,Spring会依照后面形容的规定为未命名的组件生成Bean名称:实质上,采纳简略的类名称并将其初始字符转换为小写。然而,在(不寻常的)非凡状况下,如果有多个字符并且第一个和第二个字符均为大写字母,则会保留原始大小写。这些规定与java.beans.Introspector.decapitalize(由Spring在此处应用)定义的规定雷同。
在Bean定义之外别名Bean

在bean定义自身中,能够通过应用id属性指定的最多一个名称和属性中任意数量的其余名称的组合来为bean提供多个名称name。这些名称能够是同一个bean的等效别名,并且在某些状况下很有用,例如,通过应用特定于该组件自身的bean名称,让应用程序中的每个组件都援用一个公共依赖项。

然而,在理论定义bean的中央指定所有别名并不总是足够的。有时须要为在别处定义的bean引入别名。在大型零碎中通常是这种状况,在大型零碎中,配置在每个子系统之间调配,每个子系统都有本人的对象定义集。在基于XML的配置元数据中,您能够应用<alias/>元素来实现此工作。以下示例显示了如何执行此操作:

<alias name="fromName" alias="toName"/>在这种状况下,(在同一个容器中)名为fromName的bean在应用了这个别名定义之后,也能够被称为toName。

例如,
子系统A的配置元数据可能援用一个名为subsystem-DataSource的数据源。
子系统B的配置元数据能够援用名为subsystembl-DataSource的数据源。
在编写应用这两个子系统的主应用程序时,主应用程序以myApp-dataSource的名称援用数据源。
要让这三个名称援用同一个对象,您能够在配置元数据中增加以下别名定义:

<alias name="myApp-dataSource" alias="subsystemA-dataSource"/><alias name="myApp-dataSource" alias="subsystemB-dataSource"/>

当初,每个组件和主应用程序都能够通过惟一的名称援用数据源,并且能够保障不与任何其余定义抵触(无效地创立名称空间),然而它们援用的是同一bean。

Java-configuration

如果应用Java-configuration,则@Bean注解可用于提供别名。无关详细信息,请参见应用@Bean注解。

1.3.2。实例化bean

bean定义实质上是创立一个或多个对象的窍门。当被申请时,容器查看已命名bean的配方,并应用该bean定义封装的配置元数据来创立(或获取)理论对象。

如果应用基于XML的配置元数据,则能够在元素的class属性中指定要实例化的对象的类型(或类)<bean/>。此 class属性(在外部是实例的Class属性BeanDefinition)通常是必须的。

以下两种状况会用到Class属性:

通常,在容器自身通过反射调用其构造函数间接创立bean的状况下,指定要结构的bean类,这在某种程度上等同于应用new操作符的Java代码。要指定蕴含为创建对象而调用的动态工厂办法的理论类,在容器调用类上的动态工厂办法来创立bean的状况下就不太常见了。从动态工厂办法调用返回的对象类型能够是雷同的类,也能够齐全是另一个类。
外部类名称如果心愿为动态嵌套类配置bean定义,则必须应用嵌套类的二进制名称。例如,如果你在com中有一个叫做什么的类。这个货色类有一个名为OtherThing的动态嵌套类,bean定义上的class属性的值将是com.example.SomeThing$OtherThing。请留神名称中应用了$字符来分隔嵌套的类名和外部类名。<bean id="innerClass1" class="org.springframework.example.config.MyBean$InnerClass"/>
用构造函数实例化

当通过构造方法创立一个bean时,所有一般类都能够被Spring应用并与之兼容。也就是说,正在开发的类不须要实现任何特定的接口或以特定的形式进行编码。只需指定bean类就足够了。然而,依据您用于该特定bean的IoC的类型,您可能须要一个默认(空)构造函数。

Spring IoC容器简直能够治理您要治理的任何类。它不仅限于治理真正的JavaBean。大多数Spring用户更喜爱理论的JavaBean,它仅具备默认(无参数)构造函数,并具备依据容器中的属性建模的适当的setter和getter。您还能够在容器中具备更多奇异的非bean款式类。例如,如果您须要应用相对不合乎JavaBean标准的新式连接池,则Spring也能够对其进行治理。

应用基于XML的配置元数据,您能够如下指定bean类:

<bean id="exampleBean" class="examples.ExampleBean"/><bean name="anotherExample" class="examples.ExampleBeanTwo"/>

无关用于向构造函数提供参数(如果须要)并在结构对象之后设置对象实例属性的机制的详细信息,请参见 注入依赖项。

用动态工厂办法实例化

在定义应用动态工厂办法创立的bean时,请应用class属性指定蕴含static工厂办法的类,并应用命名factory-method为属性的属性来指定工厂办法自身的名称。您应该可能调用此办法(应用可选参数,如稍后所述)并返回一个流动对象,该对象随后将被视为已通过构造函数创立。这种bean定义的一种用法是static用旧代码调用工厂。

以下bean定义指定通过调用工厂办法来创立bean。该定义不指定返回对象的类型(类),而仅指定蕴含工厂办法的类。在此示例中,该createInstance() 办法必须是静态方法。以下示例显示如何指定工厂办法:

<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的非静态方法来创立新bean。要应用此机制,请将class属性留空,并在factory-bean属性中指定以后(或父容器或先人容器)中蕴含要创建对象的实例办法的bean的名称。应用factory-method属性设置工厂办法自身的名称。以下示例显示了如何配置此类Bean:

<bean id="serviceLocator" class="examples.DefaultServiceLocator"></bean><bean id="clientService"    factory-bean="serviceLocator"    factory-method="createClientServiceInstance"/>public class DefaultServiceLocator {    private static ClientService clientService = new ClientServiceImpl();    public ClientService createClientServiceInstance() {        return clientService;    }}

一个工厂类也能够蕴含一个以上的工厂办法,如以下示例所示:

<bean id="serviceLocator" class="examples.DefaultServiceLocator">    <!-- inject any dependencies required by this locator bean --></bean><bean id="clientService"    factory-bean="serviceLocator"    factory-method="createClientServiceInstance"/><bean id="accountService"    factory-bean="serviceLocator"    factory-method="createAccountServiceInstance"/>public class DefaultServiceLocator {    private static ClientService clientService = new ClientServiceImpl();    private static AccountService accountService = new AccountServiceImpl();    public ClientService createClientServiceInstance() {        return clientService;    }    public AccountService createAccountServiceInstance() {        return accountService;    }}

这种办法表明,工厂Bean自身能够通过依赖项注入(DI)进行治理和配置。详细信息,请参见依赖性和配置。

在Spring文档中,“ factory bean”是指在Spring容器中配置并通过实例或 动态工厂办法创建对象的bean 。相同, FactoryBean(留神大写)是指特定于Spring的 FactoryBean 实现类。

确定Bean的运行时类型

确定特定bean的运行时类型并非易事。Bean元数据定义中的指定类只是初始类援用,可能与申明的工厂办法联合应用,或者是FactoryBean可能导致Bean的运行时类型不同的类,或者在实例的状况下基本不设置-级别工厂办法(通过指定factory-bean名称解析)。另外,AOP代理能够应用基于接口的代理包装bean实例,而指标Bean的理论类型(仅是其实现的接口)的裸露水平无限。

找出特定bean的理论运行时类型的举荐办法是BeanFactory.getType调用指定的bean名称。这思考了上述所有状况,并返回了BeanFactory.getBean要针对雷同bean名称返回的对象的类型。