欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring之旅(2)Bean,以及bean创建的几种方法,构造器,静态工厂方法,实例工厂方法

程序员文章站 2022-05-21 23:06:10
...

环境

  • idea:2020.3
  • spring:5.1.3.RELEASE
  • os:mac

Spring之旅(2)Bean

一个bean主要有下面的几个metadata

  • 包限定的类名,通常来说是Bean的实现类。
  • Bean的行为配置元素,描述bean应该如何在容器中运行(scope, lifecycle callbacks等)
  • 对其他bean的引用,这些bean配合它本身进行工作。这些引用就是所谓的合作者或者依赖
  • 其他的一些配置,比如说链接池的一些数量或者连接数等等。

下面的表定义了bean的properties

Property Explained in…
Class [nstantiating 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

命名一个bean

在xml的配置中,正常用id 或者 name这样的attribute,或者两个都用id必须是唯一的,name更像是一种别名,可以起很多个name,用,或者空格隔开就行。当然你也可以不指明,不指明会随机生成一个唯一的name,但是如果你想在你的bean中引用它的话,你就得给他一个名字。bean的命名风格遵循驼峰命名。

  • 举例子
<bean id="dog" class="bean.Dog" name="mydog, dog2"></bean>
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml");
System.out.println(context.containsBean("mydog"));
System.out.println(context.containsBean("dog"));
System.out.println(context.containsBean("dog2"));
true
true
true
  • 如果不指明id,name,显然不是当中的任何一个,不指明在其他bean中也就无法引用
<bean class="bean.Dog"></bean>
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml");
System.out.println(context.containsBean("mydog"));
System.out.println(context.containsBean("dog"));
System.out.println(context.containsBean("dog2"));
false
false
false

alias标签

from:https://blog.csdn.net/Truong/article/details/27837699

在对bean进行定义时,除了使用id属性来指定名称之外,为了提供多个名称,可以使用alias标签来指定。而所有的这些名称都指向同一个bean,在某些情况下提供别名非常有用,比如为了让应用的每一个组件能更容易的对公共组件进行引用。

然而,在定义bean时就指定所有的别名并不是总是恰当的。有时我们期望能在当前位置为那些在别处定义的bean引入别名。在XML配置文件中,可用单独的元素来完成bean别名的定义。如:

配置文件中定义了一个JavaBean

我要给这个JavaBean增加别名,以方便不同对象来调用。我们就可以这样写:

或者是用name属性来指定,如:

考虑一个更为具体的例子,组件A在XML配置文件中定义了一个名为componentA-dataSource的DataSource bean。但组件B却想在其XML文件中以componentB-dataSource的名字来引用此bean。而且在主程序MyApp的XML配置文件中,希望以myApp-dataSource的名字来引用此bean。最后容器加载三个XML文件来生成最终的ApplicationContext,在此情形下,可通过在MyApp XML文件中添加下列alias元素来实现:

这样一来,每个组件及主程序就可通过唯一名字来引用同一个数据源而互不干扰。

个人感觉目前我肯定用不上这个。先记录下。

实例化一个bean

bean的定义包含各种properties,里面最重要的就是class属性,spring在被询问的时候,会根据metadata中的配置,去实例化bean出来,spring如何实例化bean?文档给出了三种方法。

  • 通过构造器去实例化
  • 静态工厂方法
  • 实例工厂方法

通过构造器进行创建(默认的方法)

    <bean id="dog" class="bean.Dog">
        <property name="name" value="123"></property>
    </bean>
Dog.java
package bean;

public class Dog {

    private String name;

    public Dog(String name) {
        // 验证到底用的哪个构造器
        System.out.println("通过有参constructor进行创建的bean");
        this.name = name;
    }

    public Dog() {
        System.out.println("通过无参constructor进行创建的bean");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("通过set方法添加属性");
        this.name = name;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                '}';
    }
}

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml");
        Dog dog = (Dog) context.getBean("dog");
        System.out.println(dog);
    }
}
----output----
通过无参constructor进行创建的bean
通过set方法添加属性
Dog{name='123'}

分析:显然,这边是通过set方法进行填充的properties,并且通过无参构造器进行实例化。

通过静态工厂方法来实例化

如果用静态工厂方法来实例化的时候,需要用class来指定包含static工厂方法的类,用factory-method 来指定方法名。

<bean id="dog2" class="bean.DogFactory" factory-method="createDog"></bean>
public class DogFactory {

    private static Dog dog = new Dog();

    public DogFactory() {
    }

    public static Dog createDog(){
        System.out.println("通过静态工厂方法进行创建bean");
        return dog;
    }
}
public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml");
        Dog dog = (Dog) context.getBean("dog2");
        System.out.println(dog);
    }
}

----output----
通过静态工厂方法进行创建bean
Dog{name='null'}

通过这样定义就没有使用构造器的方法去实例化bean,而是通过静态工厂方法去实例化的。

通过工厂实例化方法(非静态)

和静态工厂方法差不多,使用实例工厂方法实例化从容器中调用现有 bean 的非静态方法以创建新 bean。要使用此机制,请将class属性留空,并在factory-bean属性中,在当前(或父容器或祖先容器)中指定包含要创建该对象的实例方法的 bean 的名称。使用factory-method属性设置工厂方法本身的名称。

    <bean id="dogFactory2" class="bean.DogFactory2"></bean>
    <bean id="dog3" factory-bean="dogFactory2" factory-method="createDog"></bean>
public class DogFactory2 {

    public Dog createDog() {
        System.out.println("通过实例化方法来构造bean,而不是静态方法");
        return dog;
    }
}
public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml");
        Dog dog = (Dog) context.getBean("dog3");
        System.out.println(dog);
    }
}

----output----
通过实例化方法来构造bean,而不是静态方法
Dog{name='null'}

如果在工厂方法中设置了property会和bean标签中的property冲突吗?

public class DogFactory2 {

    public Dog createDog() {
        Dog dog = new Dog("dog4");
        System.out.println("通过实例化方法来构造bean,而不是静态方法");
        System.out.println("======工厂方法中的property======");
        System.out.println(dog);
        return dog;
    }
}
public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml");
        Dog dog = (Dog) context.getBean("dog3");
        System.out.println("======bean中的property======");
        System.out.println(dog);
    }
}
  • 在xml中不指定property属性,没有啥问题,确实是通过工厂的方法,输出的是工厂方法添加的name=dog4
    <bean id="dogFactory2" class="bean.DogFactory2"></bean>
    <bean id="dog3" factory-bean="dogFactory2" factory-method="createDog">
<!--        <property name="name" value="dog3"></property>-->
    </bean>
----output----
通过实例化方法来构造bean,而不是静态方法
======工厂方法中的property======
Dog{name='dog4'}
======bean中的property======
Dog{name='dog4'}
  • 在xml中不指定property属性 ,很明显最后调用了set方法将peoperty的属性添加了进去,变成了dog3。所以,可以得出是先调用的工厂方法,之后再把property标签的属性用set方法添加进去的!有一个先后顺序,这是个意外发现。同时也说明,property属性底层是用的set方法。
    <bean id="dogFactory2" class="bean.DogFactory2"></bean>
    <bean id="dog3" factory-bean="dogFactory2" factory-method="createDog">
        <property name="name" value="dog3"></property>
    </bean>
----output----
通过实例化方法来构造bean,而不是静态方法
======工厂方法中的property======
Dog{name='dog4'}
通过set方法添加属性
======bean中的property======
Dog{name='dog3'}