关于Spring ApplicationContext和Bean创建

1 篇文章 0 订阅

       在社区中似乎存在很多关于如何表达bean配置的困惑,或者更确切地说如何将bean配置从XML转换为Java(或Groovy,或Kotlin,或......),因为它看起来好像不同的配置方式产生的是完全不同的东西。

       但事实上,它们或多或少是以格式(Java,XML,Properties)表示的配置,以指示Spring ApplicationContext(实际上是BeanFactory)根据这些定义(aka BeanDefinition创建bean。A BeanDefinition基本上是如何准备/创建bean的方法。

让我们使用几个类创建一个小样本,来深入了解这些类的内容。

public class Person {

  private String name;

  public void setName(String name) {
    this.name=name;
  }

  public String getName() {
    return this.name;
  }
}

服务的接口问候Person

public interface Greeter {

  void greet(Person person);
}

将问候语打印到标准输出的实现。

public class SystemOutGreeter implements Greeter {

  public void greet(Person person) {
    System.out.printf("Greetings %s!%n", person.getName());
  }
}

使用Property文件进行配置

现在让我们进入一个时间机器,回到Spring的开始15年。在XML和注释之出现之前使用属性配置文件的时候。创建一个application-context.properties并让我们使用它来引导我们的ApplicationContext。是的,今天仍然使用Spring 5,我们可以使用属性文件来创建ApplicationContext。它甚至可以通过类等方式在框架内使用ResourceBundleViewResolver

person.(class)=biz.deinum.blog.context.springcontexts.Person
person.name=Marten Deinum

greeter.(class)=biz.deinum.blog.context.springcontexts.SystemOutGreeter

现在我们已经拥有了所有移动部件,让我们用它创建一个ApplicationContext。

public class SpringContextsApplication {

  public static void main(String[] args) throws Exception {
    GenericApplicationContext contextFromProperties =
      new GenericApplicationContext();

    BeanDefinitionReader reader =
      new PropertiesBeanDefinitionReader(contextFromProperties);
    reader.loadBeanDefinitions("classpath:application-context.properties");
    contextFromProperties.refresh();

    doGreeting(contextFromProperties);

    contextFromProperties.stop();
  }

  private static void doGreeting(ApplicationContext ctx) {
    Greeter greeter = ctx.getBean(Greeter.class);
    Person person = ctx.getBean(Person.class);
    greeter.greet(person);
  }
}

那么所有这一切都做到了。首先我们需要一个ApplicationContext,为此我们可以使用GenericApplicationContext这个类。然后我们需要一些东西加载我们的BeanDefinitions,这是BeanDefinitionReader发挥作用的地方。因为我们需要使用属性文件PropertiesBeanDefinitionReader。PropertiesBeanDefinitionReader获取属性文件并将其转换为BeanDefinition实例。在我们的例子中,它将创建2个BeanDefinition实例,一个是 Person另一个实例SystemOutGreeter。特殊.(class)符号指定了bean的类型(有更多内容可以看到javadoc)。还有person.name = Marten Deinum,这会将Person的name属性设置为指定值。 它将通过使用反射来完成Spring中数据的绑定与支持。

加载的BeanDefinitions被添加到BeanFactory(the ApplicationContext is a BeanFactory on steroids),因此它可以创建实际的bean实例。

在我们使用ApplicationContext之前,我们必须在其上调用refresh()方法。 注意:在大多数情况下,这是自动完成的!

之后,我们得到了GreeterPersonApplicationContext和打印问候。

输出: Greetings, Marten Deinum!

创建persongreeterbean的最终结果(通过前面提到的反射)如下:

Person person = new Person();
person.setName("Marten Deinum");

Greeter greeter = new SystemOutGreeter();

使用XML进行配置

现在让我们对XML做同样的事情。创建一个applicationContext.xml配置PersonSystemOutGreeter

<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="greeter" class="biz.deinum.blog.context.springcontexts.SystemOutGreeter" />

  <bean id="person" class="biz.deinum.blog.context.springcontexts.Person">
    <property name="name" value="Marten Deinum" />
  </bean>
</beans>

XML比属性文件更详细。我们有一个bean元素,该元素又有一个class属性来指定bean的类型。在bean元素内部,我们可以指定property元素来指​​定要设置的属性,在我们的示例中,我们将name属性再次设置为给定值。

要加载此文件,我们需要一个BeanDefinitionReader可以加载XML文件的文件,因此要用到XmlBeanDefinitionReader

public class SpringContextsApplication {

  public static void main(String[] args) throws Exception {
    GenericApplicationContext contextFromXml =
      new GenericApplicationContext();

    BeanDefinitionReader reader =
      new XmlBeanDefinitionReader(contextFromXml);
    reader.loadBeanDefinitions("classpath:applicationContext.xml");
    contextFromXml.refresh();

    doGreeting(contextFromXml);

    contextFromXml.stop();
  }

  private static void doGreeting(ApplicationContext ctx) {
    Greeter greeter = ctx.getBean(Greeter.class);
    Person person = ctx.getBean(Person.class);
    greeter.greet(person);
  }
}

代码与具有属性文件的代码大致相同,除了突出显示的行,而不是加载属性文件现在使用XML文件进行配置。输出仍然相同。

创建persongreeter仍然是相同的,并再次归结为:

Person person = new Person();
person.setName("Marten Deinum");

Greeter greeter = new SystemOutGreeter();

但是通常你不会编写这段代码,而是你会用它ClassPathXmlApplicationContext来为你完成所有这些工作。

public class SpringContextsApplication {

  public static void main(String[] args) throws Exception {
    ConfigurableApplicationContext contextFromXml =
      new ClassPathXmlApplicationContext("applicationContext.xml");

    doGreeting(contextFromXml);

    contextFromXml.stop();
 }
  ... // Method omitted
}

此代码和上面的代码在内部发生的情况基本相同,但是这要短得多。

使用Java进行配置

最后,我们可以使用Java代码来进行配置。在Spring中,Java配置类是一个使用注释@Configuration的方法注释的常规类@Bean

@Configuration
public class ApplicationContext {

  @Bean
  public Person person() {
    Person person = new Person();
    person.setName("Marten Deinum");
    return person;
  }

  @Bean
  public SystemOutGreeter greeter() {
    return new SystemOutGreeter();
  }
}

注意:以下代码将不会编译,因为它使用Spring中不可访问的类,它仅仅是为了显示它在Spring内部是如何工作的(以简化形式!)。

public class SpringContextsApplication {

  public static void main(String[] args) throws Exception {
    GenericApplicationContext contextFromJava =
      new GenericApplicationContext();

    ConfigurationClassBeanDefinitionReader reader =
      new ConfigurationClassBeanDefinitionReader(contextFromJava);
    reader.loadBeanDefinitions(Collections.singletonSet(
      new ConfigurationClass(ApplicationContext.class, "applicationContext")));
    contextFromJava.refresh();

    doGreeting(contextFromJava);

    contextFromJava.stop();
  }

  private static void doGreeting(ApplicationContext ctx) {
    Greeter greeter = ctx.getBean(Greeter.class);
    Person person = ctx.getBean(Person.class);
    greeter.greet(person);
  }
}

这或多或少是当Spring找到Java配置类时发生的事情。然而,所有这些都隐藏在AnnotationConfigApplicationContext Class内。

public class SpringContextsApplication {

  public static void main(String[] args) throws Exception {
    AnnotationConfigApplicationContext contextFromJava =
      new AnnotationConfigApplicationContext(ApplicationContext.class);

    doGreeting(contextFromJava);

    contextFromJava.stop();
  }

  private static void doGreeting(ApplicationContext ctx) {
    Greeter greeter = ctx.getBean(Greeter.class);
    Person person = ctx.getBean(Person.class);
    greeter.greet(person);
  }

结论

现在看到所有3种不同的配置机制的结论是什么。前两个机制转换为与@Bean注释方法中发生的相同。

基于.(class)for属性文件和基于classXML的配置的属性,您可以得出结论Spring new <class-value-here>()自己。然后它将set<property-name-here>(<property-value-here>)像在基于Java的配置中一样调用,或者<constructor-arg>在XML配置中使用时传递构造函数参数)。

PropertiesXMLJava
.(class)=Personclass=PersonName of the class
person.name=Marten Deinum<property name="name" value="Marten Deinum"setName("Marten Deinum")

对于那些感兴趣的人,可以在GitHub上找到源代码。

https://github.com/mdeinum/blog-spring-contexts

本文翻译自谷歌社群。原文地址:https://mdeinum.github.io/2018-04-12-on-spring-applicationcontext-and-bean-creation/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值