三、Spring源码-注解说明

1.@Configuration

  Indicates that a class declares one or more @Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime, for example:

@Configuration
public class AppConfig {

		@Bean
		public MyBean myBean() {
				// instantiate, configure and return bean ...
		}
}

1.1 Bootstrapping @Configuration classes

Via AnnotationConfigApplicationContext

  @Configuration classes are typically bootstrapped using either AnnotationConfigApplicationContext or its web-capable variant, AnnotationConfigWebApplicationContext. A simple example with the former follows:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
   ctx.register(AppConfig.class);
   ctx.refresh();
   MyBean myBean = ctx.getBean(MyBean.class);
   // use myBean ...

  See AnnotationConfigApplicationContext Javadoc for further details and see AnnotationConfigWebApplicationContext for web.xml configuration instructions.

Via Spring XML

  As an alternative to registering @Configuration classes directly against an AnnotationConfigApplicationContext, @Configuration classes may be declared as normal definitions within Spring XML files:

<beans>
     <context:annotation-config/>
     <bean class="com.acme.AppConfig"/>
beans>

  In the example above, is required in order to enable ConfigurationClassPostProcessor and other annotation-related post processors that facilitate handling @Configuration classes.

Via component scanning

  @Configuration is meta-annotated with @Component, therefore @Configuration classes are candidates for component scanning (typically using Spring XML’s element) and therefore may also take advantage of @Autowired/@Inject at the field and method level (but not at the constructor level).
@Configuration classes may not only be bootstrapped using component scanning, but may also themselves configure component scanning using the @ComponentScan annotation:

@Configuration
@ComponentScan("com.acme.app.services")
public class AppConfig {
		// various @Bean definitions ...
}

  See @ComponentScan Javadoc for details.

1.2 Working with externalized values

Using the Environment API

  Externalized values may be looked up by injecting the Spring Environment into a @Configuration class using the @Autowired or the @Inject annotation:

	@Configuration
   public class AppConfig {
       @Inject Environment env;
       @Bean
       public MyBean myBean() {
           MyBean myBean = new MyBean();
           myBean.setName(env.getProperty("bean.name"));
           return myBean;
       }
   }

  Properties resolved through the Environment reside in one or more “property source” objects, and @Configuration classes may contribute property sources to the Environment object using the @PropertySources annotation:

@Configuration
   @PropertySource("classpath:/com/acme/app.properties")
   public class AppConfig {
       @Inject Environment env;
       @Bean
       public MyBean myBean() {
           return new MyBean(env.getProperty("bean.name"));
       }
   }

  See Environment and @PropertySource Javadoc for further details.

Using the @Value annotation

  Externalized values may be ‘wired into’ @Configuration classes using the @Value annotation:

@Configuration
   @PropertySource("classpath:/com/acme/app.properties")
   public class AppConfig {
       @Value("${bean.name}") String beanName;
       @Bean
       public MyBean myBean() {
           return new MyBean(beanName);
       }
   }

  This approach is most useful when using Spring’s PropertySourcesPlaceholderConfigurer, usually enabled via XML with . See the section below on composing @Configuration classes with Spring XML using @ImportResource, see @Value Javadoc, and see @Bean Javadoc for details on working with BeanFactoryPostProcessor types such as PropertySourcesPlaceholderConfigurer.

1.3 Composing @Configuration classes

With the @Import annotation

  @Configuration classes may be composed using the @Import annotation, not unlike the way that works in Spring XML. Because @Configuration objects are managed as Spring beans within the container, imported configurations may be injected using @Autowired or @Inject:

@Configuration
   public class DatabaseConfig {
       @Bean
       public DataSource dataSource() {
           // instantiate, configure and return DataSource
       }
   }
   @Configuration
   @Import(DatabaseConfig.class)
   public class AppConfig {
       @Inject DatabaseConfig dataConfig;
       @Bean
       public MyBean myBean() {
           // reference the dataSource() bean method
           return new MyBean(dataConfig.dataSource());
       }
   }

  Now both AppConfig and the imported DatabaseConfig can be bootstrapped by registering only AppConfig against the Spring context:
new AnnotationConfigApplicationContext(AppConfig.class);

With the @Profile annotation

@Configuration classes may be marked with the @Profile annotation to indicate they should be processed only if a given profile or profiles are active:
   @Profile("embedded")
   @Configuration
   public class EmbeddedDatabaseConfig {
       @Bean
       public DataSource dataSource() {
           // instantiate, configure and return embedded DataSource
       }
   }
   @Profile("production")
   @Configuration
   public class ProductionDatabaseConfig {
       @Bean
       public DataSource dataSource() {
           // instantiate, configure and return production DataSource
       }
   }

  See @Profile and Environment Javadoc for further details.

With Spring XML using the @ImportResource annotation

  As mentioned above, @Configuration classes may be declared as regular Spring definitions within Spring XML files. It is also possible to import Spring XML configuration files into @Configuration classes using the @ImportResource annotation. Bean definitions imported from XML can be injected using @Autowired or @Inject:

@Configuration
   @ImportResource("classpath:/com/acme/database-config.xml")
   public class AppConfig {
       @Inject DataSource dataSource; // from XML
       @Bean
       public MyBean myBean() {
           // inject the XML-defined dataSource bean
           return new MyBean(this.dataSource);
       }
   }

With nested @Configuration classes

@Configuration classes may be nested within one another as follows:
   @Configuration
   public class AppConfig {
       @Inject DataSource dataSource;
       @Bean
       public MyBean myBean() {
           return new MyBean(dataSource);
       }
       @Configuration
       static class DatabaseConfig {
           @Bean
           DataSource dataSource() {
               return new EmbeddedDatabaseBuilder().build();
           }
       }
   }

  When bootstrapping such an arrangement, only AppConfig need be registered against the application context. By virtue of being a nested @Configuration class, DatabaseConfig will be registered automatically. This avoids the need to use an @Import annotation when the relationship between AppConfig DatabaseConfig is already implicitly clear.

Note also that nested @Configuration classes can be used to good effect with the @Profile annotation to provide two options of the same bean to the enclosing @Configuration class.

1.4 Configuring lazy initialization

  By default, @Bean methods will be eagerly instantiated at container bootstrap time. To avoid this, @Configuration may be used in conjunction with the @Lazy annotation to indicate that all @Bean methods declared within the class are by default lazily initialized. Note that @Lazy may be used on individual @Bean methods as well.

1.5 Testing support for @Configuration classes

  The Spring TestContext framework available in the spring-test module provides the @ContextConfiguration annotation, which as of Spring 3.1 can accept an array of @Configuration Class objects:

@RunWith(SpringJUnit4ClassRunner.class)
   @ContextConfiguration(classes={AppConfig.class, DatabaseConfig.class})
   public class MyTests {
  
       @Autowired MyBean myBean;
  
       @Autowired DataSource dataSource;
  
       @Test
       public void test() {
           // assertions against myBean ...
       }
   }

  See TestContext framework reference documentation for details.

1.6 Enabling built-in Spring features using @Enable annotations

  Spring features such as asynchronous method execution, scheduled task execution, annotation driven transaction management, and even Spring MVC can be enabled and configured from @Configuration classes using their respective “@Enable” annotations. See @EnableAsync, @EnableScheduling, @EnableTransactionManagement, @EnableAspectJAutoProxy, and @EnableWebMvc for details.

1.7 Constraints when authoring @Configuration classes

  • Configuration classes must be provided as classes (i.e. not as instances returned from factory methods), allowing for runtime enhancements through a generated subclass.

  • Configuration classes must be non-final.

  • Configuration classes must be non-local (i.e. may not be declared within a method).

  • Any nested configuration classes must be declared as static.

  • @Bean methods may not in turn create further configuration classes (any such instances will be treated as regular beans, with their configuration annotations remaining undetected).

2.@Bean

  Indicates that a method produces a bean to be managed by the Spring container.

2.1 Overview

  The names and semantics of the attributes to this annotation are intentionally similar to those of the element in the Spring XML schema. For example:

@Bean
public MyBean myBean() {
    // instantiate and configure MyBean obj
    return obj;
}

2.2 Bean Names

  While a name attribute is available, the default strategy for determining the name of a bean is to use the name of the @Bean method. This is convenient and intuitive, but if explicit naming is desired, the name attribute (or its alias value) may be used. Also note that name accepts an array of Strings, allowing for multiple names (i.e. a primary bean name plus one or more aliases) for a single bean.

@Bean({"b1", "b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
public MyBean myBean() {
    // instantiate and configure MyBean obj
    return obj;
}

Profile, Scope, Lazy, DependsOn, Primary, Order

  Note that the @Bean annotation does not provide attributes for profile, scope, lazy, depends-on or primary. Rather, it should be used in conjunction with @Scope, @Lazy, @DependsOn and @Primary annotations to declare those semantics. For example:

@Bean
@Profile("production")
@Scope("prototype")
public MyBean myBean() {
    // instantiate and configure MyBean obj
    return obj;
}

  The semantics of the above-mentioned annotations match their use at the component class level: @Profile allows for selective inclusion of certain beans. @Scope changes the bean’s scope from singleton to the specified scope. @Lazy only has an actual effect in case of the default singleton scope. @DependsOn enforces the creation of specific other beans before this bean will be created, in addition to any dependencies that the bean expressed through direct references, which is typically helpful for singleton startup. @Primary is a mechanism to resolve ambiguity at the injection point level if a single target component needs to be injected but several beans match by type.

  Additionally, @Bean methods may also declare qualifier annotations and @Order values, to be taken into account during injection point resolution just like corresponding annotations on the corresponding component classes but potentially being very individual per bean definition (in case of multiple definitions with the same bean class). Qualifiers narrow the set of candidates after the initial type match; order values determine the order of resolved elements in case of collection injection points (with several target beans matching by type and qualifier).

NOTE: @Order values may influence priorities at injection points, but please be aware that they do not influence singleton startup order which is an orthogonal concern determined by dependency relationships and @DependsOn declarations as mentioned above. Also, javax.annotation.Priority is not available at this level since it cannot be declared on methods; its semantics can be modeled through @Order values in combination with @Primary on a single bean per type.

DependsOn

通常情况下,可以直接通过之前提到的所有元素,来显式地指定bean之间的依赖关系。这样,容器在初始化当前bean定义的时候,会根据这些元素所标记的依赖关系,首先实例化当前bean定义所依赖的其他bean定义。但是,如果某些时候,我们没有通过类似 的元素明确指定对象A依赖于对象B的话,如何让容器在实例化对象A之前首先实例化对象B呢?

public class SystemConfigurationSetup {
static {
    DOMConfigurator.configure("配置文件路径");
    // 其他初始化代码
    }
}

系统中所有需要日志记录的类,都需要在这些类使用之前首先初始化log4j。那么,就会非显式地依赖于 SystemConfigurationSetup 的静态初始化块。如果 ClassA 需要使用log4j,那么就必须在bean定义中使用 depends-on 来要求容器在初始化自身实例之前首先实例化 SystemConfigurationSetup ,以保证日志系统的可用,如下代码演示的正是这种情况:

<bean id="classAInstance" class="...ClassA" depends-on="configSetup"/>
<bean id="configSetup" class="SystemConfigurationSetup"/>

autowire

除了可以通过配置明确指定bean之间的依赖关系,Spirng还提供了根据bean定义的某些特点将相互依赖的某些bean直接自动绑定的功能。通过 的 autowire 属性,可以指定当前bean定义采用某种类型的自动绑定模式。这样,你就无需手工明确指定该bean定义相关的依赖关系,从而也可以免去一些手工输入的工作量。

Spring提供了5种自动绑定模式,即 no 、 byName 、 byType 、 constructor 和 autodetect ,下面是它们的具体介绍。

  • no

    容器默认的自动绑定模式,也就是不采用任何形式的自动绑定,完全依赖手工明确配置各个bean之间的依赖关系,以下代码演示的两种配置是等效的:

    <bean id="beanName" class="..."/>
    或者
    <bean id="beanName" class="..." autowire="no"/>
    
  • byName

    按照类中声明的实例变量的名称,与XML配置文件中声明的bean定义的beanName的值进行匹配,相匹配的bean定义将被自动绑定到当前实例变量上。这种方式对类定义和配置的bean定义有一定的限制。假设我们有如下所示的类定义:

    public class Foo {
        private Bar emphasisAttribute;
        ...
        // 相应的setter方法定义
    }
    public class Bar {
        ...
    }
    

    那么应该使用如下代码所演示的自动绑定定义,才能达到预期的目的:

    <bean id="fooBean" class="...Foo" autowire="byName">bean>
    <bean id="emphasisAttribute" class="...Bar">bean>
    

    需要注意两点:第一,我们并没有明确指定 fooBean 的依赖关系,而仅指定了它的 autowire 属性为 byName ;第二,第二个bean定义的 id 为 emphasisAttribute ,与 Foo 类中的实例变量名称相同。

  • byType

    如果指定当前bean定义的 autowire 模式为 byType ,那么,容器会根据当前bean定义类型,分析其相应的依赖对象类型,然后到容器所管理的所有bean定义中寻找与依赖对象类型相同的bean定义,然后将找到的符合条件的bean自动绑定到当前bean定义。

    对于 byName 模式中的实例类 Foo 来说,容器会在其所管理的所有bean定义中寻找类型为Bar的bean定义。如果找到,则将找到的bean绑定到 Foo 的bean定义;如果没有找到,则不做设置。但如果找到多个,容器会告诉你它解决不了“该选用哪一个”的问题,你只好自己查找原因,并自己修正该问题。所以, byType 只能保证,在容器中只存在一个符合条件的依赖对象的时候才会发挥最大的作用,如果容器中存在多个相同类型的bean定义,那么,不好意思,采用手动明确配置吧!

    指定 byType 类型的 autowire 模式与 byName 没什么差别,只是 autowire 的值换成 byType 而已,可以参考如下代码:

    <bean id="fooBean" class="...Foo" autowire="byType">bean>
    <bean id="anyName" class="...Bar">bean>
    
  • constructor

    byName 和 byType 类型的自动绑定模式是针对property的自动绑定,而 constructor 类型则是针对构造方法参数的类型而进行的自动绑定,它同样是 byType 类型的绑定模式。不过, constructor 是匹配构造方法的参数类型,而不是实例属性的类型。与 byType 模式类似,如果找到不止一个符合条件的bean定义,那么,容器会返回错误。使用上也与 byType 没有太大差别,只不过是应用到需要使用构造方法注入的bean定义之上,代码清单给出了一个使用 construtor 模式进行自动绑定的简单场景演示。

    public class Foo {
        private Bar bar;
        public Foo(Bar arg) {
            this.bar = arg;
        }
        ...
    }
    

    相应配置为

    <bean id="foo" class="...Foo" autowire="constructor"/>
    <bean id="bar" class="...Bar">bean>
    
  • autodetect

    这种模式是 byType 和 constructor 模式的结合体,如果对象拥有默认无参数的构造方法,容器会优先考虑 byType 的自动绑定模式。否则,会使用 constructor 模式。当然,如果通过构造方法注入绑定后还有其他属性没有绑定,容器也会使用 byType 对剩余的对象属性进行自动绑定。

注意: 手工明确指定的绑定关系总会覆盖自动绑定模式的行为。
自动绑定只应用于“原生类型、String类型以及Classes类型以外”的对象类型,对“原生类型、String类型和Classes类型”以及“这些类型的数组”应用自动绑定是无效的。

  • 自动绑定与手动明确绑定

    自动绑定和手动明确绑定各有利弊。自动绑定的优点有如下两点。

    • (1) 某种程度上可以有效减少手动敲入配置信息的工作量。
    • (2) 某些情况下,即使为当前对象增加了新的依赖关系,但只要容器中存在相应的依赖对象,就不需要更改任何配置信息。

    自动绑定的缺点有如下几点。

    • (1) 自动绑定不如明确依赖关系一目了然。我们可以根据明确的依赖关系对整个系统有一个明确的认识,但使用自动绑定的话,就可能需要在类定义以及配置文件之间,甚至各个配置文件之间来回转换以取得相应的信息。
    • (2) 某些情况下,自动绑定无法满足系统需要,甚至导致系统行为异常或者不可预知。根据类型( byType )匹配进行的自动绑定,如果系统中增加了另一个相同类型的bean定义,那么整个系统就会崩溃;根据名字( byName )匹配进行的自动绑定,如果把原来系统中相同名称的bean定义类型给换掉,就会造成问题,而这些可能都是在不经意间发生的。
    • (3) 使用自动绑定,我们可能无法获得某些工具的良好支持,比如Spring IDE。

lazy-init

延迟初始化( lazy-init )这个特性的作用,主要是可以针对 ApplicationContext 容器的bean初始化行为施以更多控制。与 BeanFactory 不同, ApplicationContext 在容器启动的时候,就会马上对所有的“singleton的bean定义”进行实例化操作。通常这种默认行为是好的,因为如果系统有问题的话,可以在第一时间发现这些问题,但有时,我们不想某些bean定义在容器启动后就直接实例化,可能出于容器启动时间的考虑,也可能出于其他原因的考虑。总之,我们想改变某个或者某些bean定义在 ApplicationContext 容器中的默认实例化时机。这时,就可以通过 的 lazy-init 属性来控制这种初始化行为,如下代码所示:

<bean id="lazy-init-bean" class="..." lazy-init="true"/>
<bean id="not-lazy-init-bean" class="..."/>

这样, ApplicationContext 容器在启动的时候,只会默认实例化 not-lazy-init-bean 而不会实例化 lazy-init-bean 。

当然,仅指定 lazy-init-bean 的 lazy-init 为 true ,并不意味着容器就一定会延迟初始化该bean的实例。如果某个非延迟初始化的bean定义依赖于 lazy-init-bean ,那么毫无疑问,按照依赖决计的顺序,容器还是会首先实例化 lazy-init-bean ,然后再实例化后者,如下代码演示了这种相互牵连导致延迟初始化失败的情况:

<bean id="lazy-init-bean" class="..." lazy-init="true"/>
<bean id="not-lazy-init-bean" class="...">
    <property name="propName">
        <ref bean="lazy-init-bean"/>
    property>
bean>

虽然 lazy-init-bean 是延迟初始化的,但因为依赖它的 not-lazy-init-bean 并不是延迟初始化,所以 lazy-init-bean 还是会被提前初始化,延迟初始化的良好打算“泡汤”。如果我们真想保证 lazy-init-bean 一定会被延迟初始化的话,就需要保证依赖于该bean定义的其他bean定义也同样设置为延迟初始化。在bean定义很多时,好像工作量也不小哦。不过不要忘了, 可是所有 的统领啊,让它一声令下吧!

<beans default-lazy-init="true">
    <bean id="lazy-init-bean" class="..."/>
    <bean id="not-lazy-init-bean" class="...">
        <property name="propName">
            <ref bean="lazy-init-bean"/>
        property>
    bean>
beans>

Scope

BeanFactory 除了拥有作为IoC Service Provider的职责,作为一个轻量级容器,它还有着其他一些职责,其中就包括对象的生命周期管理。

本节主要讲述容器中管理的对象的scope这个概念。多数中文资料在讲解bean的scope时喜欢用“作用域”这个名词,应该还算贴切吧。不过,我更希望告诉你scope这个词到底代表什么意思,至于你怎么称呼它反而不重要。

scope用来声明容器中的对象所应该处的限定场景或者说该对象的存活时间,即容器在对象进入其相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁这些对象。打个比方吧!我们都是处于社会(容器)中,如果把中学教师作为一个类定义,那么当容器初始化这些类之后,中学教师只能局限在中学这样的场景中;中学,就可以看作中学教师的scope。

Spring容器最初提供了两种bean的scope类型:singleton和prototype,但发布2.0之后,又引入了另外三种scope类型,即request、session和global session类型。不过这三种类型有所限制,只能在Web应用中使用。也就是说,只有在支持Web应用的 ApplicationContext 中使用这三个scope才是合理的。

我们可以通过使用 的singleton或者scope属性来指定相应对象的scope,其中,scope属性只能在XSD格式的文档声明中使用,类似于如下代码所演示的形式:

DTD:
<bean id="mockObject1" class="...MockBusinessObject" singleton="false"/>
XSD:
<bean id="mockObject2" class="...MockBusinessObject" scope="prototype"/>

让我们来看一下容器提供的这几个scope是如何限定相应对象的吧!

  • 1.singleton

    配置中的bean定义可以看作是一个模板,容器会根据这个模板来构造对象。但是要根据这个模板构造多少对象实例,又该让这些构造完的对象实例存活多久,则由容器根据bean定义的scope语意来决定。标记为拥有singleton scope的对象定义,在Spring的IoC容器中只存在一个实例,所有对该对象的引用将共享这个实例。该实例从容器启动,并因为第一次被请求而初始化之后,将一直存活到容器退出,也就是说,它与IoC容器“几乎”拥有相同的“寿命”。

    图是Spring参考文档中所给出的singleton的bean的实例化和注入语意演示图例,或许可以更形象地说明问题。

    三、Spring源码-注解说明_第1张图片

    需要注意的一点是,不要因为名字的原因而与GoF所提出的Singleton模式相混淆,二者的语意是不同的: 标记为singleton的bean是由容器来保证这种类型的bean在同一个容器中只存在一个共享实例;而Singleton模式则是保证在同一个 Classloader 中只存在一个这种类型的实例。

    通常情况下,如果你不指定bean的scope,singleton便是容器默认的scope,所以,下面三种配置形式实际上达成的是同样的效果:

    
    <bean id="mockObject1" class="...MockBusinessObject"/>
    
    <bean id="mockObject1" class="...MockBusinessObject" singleton="true"/>
    
    <bean id="mockObject1" class="...MockBusinessObject" scope="singleton"/>
    
  • 2.prototype

    针对声明为拥有prototype scope的bean定义,容器在接到该类型对象的请求的时候,会每次都重新生成一个新的对象实例给请求方。虽然这种类型的对象的实例化以及属性设置等工作都是由容器负责的,但是只要准备完毕,并且对象实例返回给请求方之后,容器就不再拥有当前返回对象的引用,请求方需要自己负责当前返回对象的后继生命周期的管理工作,包括该对象的销毁。也就是说,容器每次返回给请求方一个新的对象实例之后,就任由这个对象实例“自生自灭”了。

    所以,对于那些请求方不能共享使用的对象类型,应该将其bean定义的scope设置为prototype。这样,每个请求方可以得到自己对应的一个对象实例。通常,声明为prototype的scope的bean定义类型,都是一些有状态的,比如保存每个顾客信息的对象。

    从Spring 参考文档上的这幅图片(见图4-6),你可以再次了解一下拥有prototype scope的bean定义,在实例化对象并注入依赖的时候,它的具体语意是个什么样
    子。

    三、Spring源码-注解说明_第2张图片

    你用以下形式来指定某个bean定义的scope为prototype类型,效果是一样的:

    
    <bean id="mockObject1" class="...MockBusinessObject" singleton="false"/>
    
    <bean id="mockObject1" class="...MockBusinessObject" scope="prototype"/>
    
  • 3.request、session和global session

    这三个scope类型是Spirng 2.0之后新增加的,它们不像之前的singleton和prototype那么“通用”,因为它们只适用于Web应用程序,通常是与 XmlWebApplicationContext 共同使用,而这些将在第6部分详细讨论。不过,既然它们也属于scope的概念,这里就简单提几句。

    • request

      request通常的配置形式如下:

      <bean id="requestProcessor" class="...RequestProcessor" scope="request"/>
      

      Spring容器,即 XmlWebApplicationContext 会为每个HTTP请求创建一个全新的 Request-Processor 对象供当前请求使用,当请求结束后,该对象实例的生命周期即告结束。当同时有10个HTTP请求进来的时候,容器会分别针对这10个请求返回10个全新的 RequestProcessor 对象实例,且它们之间互不干扰。从不是很严格的意义上说,request可以看作prototype的一种特例,除了场景更加具体之外,语意上差不多。

    • session

      对于Web应用来说,放到session中的最普遍的信息就是用户的登录信息,对于这种放到session中的信息,我们可使用如下形式指定其scope为session:

      <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
      

      Spring容器会为每个独立的session创建属于它们自己的全新的 UserPreferences 对象实例。与request相比,除了拥有session scope的bean的实例具有比request scope的bean可能更长的存活时间,其他方面真是没什么差别。

    • global session

      还是 userPreferences ,不过scope对应的值换一下,如下所示:

      <bean id="userPreferences" class="com.foo.UserPreferences" scope="globalSession"/>
      

      global session只有应用在基于portlet的Web应用程序中才有意义,它映射到portlet的global范围的session。如果在普通的基于servlet的Web应用中使用了这个类型的scope,容器会将其作为普通的session类型的scope对待。

  • 4.自定义scope类型

      在Spring 2.0之后的版本中,容器提供了对scope的扩展点,这样,你可以根据自己的需要或者应用的场景,来添加自定义的scope类型。需要说明的是,默认的singleton和prototype是硬编码到代码中的,而request、session和global session,包括自定义scope类型,则属于可扩展的scope行列,它们都实现了 rg.springframework.beans.factory.config.Scope接口,该接口定义如下:

    public interface Scope {
        Object get(String name, ObjectFactory objectFactory);
        Object remove(String name);
        void registerDestructionCallback(String name, Runnable callback);
        String getConversationId();
    }
    

      要实现自己的scope类型,首先需要给出一个 Scope 接口的实现类,接口定义中的4个方法并非都是必须的,但 get 和 remove 方法必须实现。我们可以看一下http://www.jroller.com/eu/entry/implementing_efficinet_id_generator中提到的一个 ThreadScope 的实现

    自定义的 ThreadScope 的定义

    public class ThreadScope implements Scope {
        private final ThreadLocal threadScope = new ThreadLocal() {
            protected Object initialValue() {
                return new HashMap();
            }
        };
        public Object get(String name, ObjectFactory objectFactory) {
            Map scope = (Map) threadScope.get();
            Object object = scope.get(name);
            if(object==null) {
                object = objectFactory.getObject();
                scope.put(name, object);
            }
            return object;
        }
        public Object remove(String name) {
            Map scope = (Map) threadScope.get();
            return scope.remove(name);
        }
        public void registerDestructionCallback(String name, Runnable callback) {
        }
        ...
    }
    

      更多 Scope 相关的实例,可以参照同一站点的一篇文章“More fun with Spring scopes”(http://jroller.com/eu/entry/more_fun_with_spring_scopes),其中提到 PageScope 的实现。

      有了 Scope 的实现类之后,我们需要把这个 Scope 注册到容器中,才能供相应的bean定义使用。通常情况下,我们可以使用 ConfigurableBeanFactory 的以下方法注册自定义 scope :

    void registerScope(String scopeName, Scope scope);
    

      其中,参数 scopeName 就是使用的bean定义可以指定的名称,比如Spring框架默认提供的自定义scope类型request或者session。参数 scope 即我们提供的 Scope 实现类实例。

      对于以上的 ThreadScope ,如果容器为 BeanFactory 类型(当然,更应该实现 Configurable-BeanFactory ),我们可以通过如下方式来注册该 Scope :

    Scope threadScope = new ThreadScope();
    beanFactory.registerScope("thread",threadScope);
    

      之后,我们就可以在需要的bean定义中直接通过“ thread ”名称来指定该bean定义对应的scope为以上注册的 ThreadScope 了,如以下代码所示:

    <bean id="beanName" class="..." scope="thread"/>
    

      除了直接编码调用 ConfigurableBeanFactory 的 registerScope 来注册 scope ,Spring还提供了一个专门用于统一注册自定义scope的 BeanFactoryPostProcessor 实现(有关 BeanFactoryPost-Processor 的更多细节稍后将详述),即 org.springframework.beans.factory.config.Custom-ScopeConfigurer 。对于 ApplicationContext 来说,因为它可以自动识别并加载 BeanFactoryPost-Processor ,所以我们就可以直接在配置文件中,通过这个 CustomScopeConfigurer 注册来 Thread-Scope

    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes">
            <map>
                <entry key="thread" value="com.foo.ThreadScope"/>
            map>
        property>
    bean>
    

      在以上工作全部完成之后,我们就可以在自己的bean定义中使用这个新增加到容器的自定义scope“ thread ”了,如下代码演示了通常情况下“ thread ”自定义scope的使用:

    <bean id="beanName" class="..." scope="thread">
        <aop:scoped-proxy/>
    bean>
    

      由于 aop:scoped-proxy/ 涉及Spring AOP相关知识,这里不会详细讲述。需要注意的是,使用了自定义scope的bean定义,需要该元素来为其在合适的时间创建和销毁相应的代理对象实例。对于request、session和global session来说,也是如此。

@Bean Methods in @Configuration Classes

  Typically, @Bean methods are declared within @Configuration classes. In this case, bean methods may reference other @Bean methods in the same class by calling them directly. This ensures that references between beans are strongly typed and navigable. Such so-called ‘inter-bean references’ are guaranteed to respect scoping and AOP semantics, just like getBean() lookups would. These are the semantics known from the original ‘Spring JavaConfig’ project which require CGLIB subclassing of each such configuration class at runtime. As a consequence, @Configuration classes and their factory methods must not be marked as final or private in this mode. For example:

@Configuration
public class AppConfig {

    @Bean
    public FooService fooService() {
        return new FooService(fooRepository());
    }

    @Bean
    public FooRepository fooRepository() {
        return new JdbcFooRepository(dataSource());
    }

    // ...
}

@Bean Lite Mode

  @Bean methods may also be declared within classes that are not annotated with @Configuration. For example, bean methods may be declared in a @Component class or even in a plain old class. In such cases, a @Bean method will get processed in a so-called ‘lite’ mode.

  Bean methods in lite mode will be treated as plain factory methods by the container (similar to factory-method declarations in XML), with scoping and lifecycle callbacks properly applied. The containing class remains unmodified in this case, and there are no unusual constraints for the containing class or the factory methods.

  In contrast to the semantics for bean methods in @Configuration classes, ‘inter-bean references’ are not supported in lite mode. Instead, when one @Bean-method invokes another @Bean-method in lite mode, the invocation is a standard Java method invocation; Spring does not intercept the invocation via a CGLIB proxy. This is analogous to inter-@Transactional method calls where in proxy mode, Spring does not intercept the invocation — Spring does so only in AspectJ mode.

@Component
public class AppConfig {
    @Bean
    public Foo foo() {
        return new Foo(bar());
    } 
    @Bean
    public Bar bar() {
        return new Bar();
    }
}

  foo()方法中new Foo(bar())传入的bar()方法会每次产生一个新的Bar对象,并不会像非lite模式中,每次调用法传入的Bar对象都是同一个
推荐的方法是@Configuration类中使用Bean方法,可以确保始终使用完整的模式。这将防止相同的@Bean方法被意外的多次调用,并且有助于减少lite模式下操作时难以跟踪的微小错误。

3.@Component[自行翻看源码]

4.@ComponentScan[自行翻看源码]

5.@Conditional[自行翻看源码]

6.@Import[自行翻看源码]

你可能感兴趣的:(2.Spring源码,spring,java,后端)