Spring容器内部创建bean实例对象常见的有4种方式。
通过反射调用构造方法创建bean对象
调用类的构造方法获取对应的bean实例,是使用最多的方式,这种方式只需要在xml bean元素中指定class属性,spring容器内部会自动调用该类型的构造方法来创建bean对象,将其放在容器中以供使用。
语法
1 2 3 4 5 6 7
| <bean id="bean名称" name="bean名称或者别名" class="bean的完整类型名称"> <constructor-arg index="0" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="1" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="2" value="bean的值" ref="引用的bean名称" /> .... <constructor-arg index="n" value="bean的值" ref="引用的bean名称" /> </bean>
|
constructor-arg用于指定构造方法参数的值
index:构造方法中参数的位置,从0开始,依次递增
value:指定参数的值
ref:当插入的值为容器内其他bean的时候,这个值为容器中对应bean的名称
案例
UserModel类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| UserModel类
@Getter @Setter @ToString public class UserModel {
private String name; private int age;
public UserModel() { this.name = "我是通过UserModel的无参构造方法创建的!"; this.age = 100; }
public UserModel(String name, int age) { this.name = name; this.age = age; }
}
|
beans.xml配置
1 2 3 4 5 6 7 8
| <bean id="createBeanByConstructor1" class="demo1.UserModel"/>
<bean id="createBeanByConstructor2" class="demo1.UserModel"> <constructor-arg index="0" value="我是通过UserModel的有参方法构造的对象!"/> <constructor-arg index="1" value="30"/> </bean>
|
上面这2种写法,spring容器创建这两个UserModel的时候,都会通过反射的方式去调用UserModel类中对应的构造函数来创建UserModel对象。
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package demo1;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Client {
public static void main(String[] args) { String beanXml = "classpath:/bean.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml);
System.out.println("spring容器中所有bean如下:");
for (String beanName : context.getBeanDefinitionNames()){ System.out.println(beanName + ":" + context.getBean(beanName)); } } }
|
代码中会输出spring容器中所有bean的名称和其对应的bean对象。
运行输出
1 2
| createBeanByConstructor1:UserModel(name=我是通过UserModel的无参构造方法创建的!, age=0) createBeanByConstructor2:UserModel(name=我是通过UserModel的有参方法构造的对象!, age=30)
|
通过静态工厂方法创建bean对象
我们可以创建静态工厂,内部提供一些静态方法来生成所需要的对象,将这些静态方法创建的对象交给spring以供使用。
语法
1 2 3 4 5 6 7 8 9
| <bean id="bean名称" name="" class="静态工厂完整类名" factory-method="静态工厂的方法"> <constructor-arg index="0" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="1" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="2" value="bean的值" ref="引用的bean名称" /> .... <constructor-arg index="n" value="bean的值" ref="引用的bean名称" /> </bean>
|
class:指定静态工厂完整的类名
factory-method:静态工厂中的静态方法,返回需要的对象。
constructor-arg用于指定静态方法参数的值,用法和上面介绍的构造方法一样。
spring容器会自动调用静态工厂的静态方法获取指定的对象,将其放在容器中以供使用。
案例
定义静态工厂
创建一个静态工厂类,用于生成UserModel对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| package demo1;
public class UserStaticFactory {
public static UserModel buildUser1() {
System.out.println(UserStaticFactory.class + ".buildUser1()");
UserModel userModel = new UserModel(); userModel.setName("我是无参静态构造方法创建的!"); return userModel; }
public static UserModel buildUser2(String name, int age) {
System.out.println(UserStaticFactory.class + ".buildUser2()");
UserModel userModel = new UserModel(); userModel.setName(name); userModel.setAge(age); return userModel; }
}
|
beans.xml配置
1 2 3 4 5 6 7 8 9 10 11
| <bean id="createBeanByStaticFactoryMethod1" class="demo1.UserStaticFactory" factory-method="buildUser1"/>
<bean id="createBeanByStaticFactoryMethod2" class="demo1.UserStaticFactory" factory-method="buildUser2"> <constructor-arg index="0" value="通过工厂静态有参方法创建UerModel实例对象"/> <constructor-arg index="1" value="40"/> </bean>
|
上面配置中,spring容器启动的时候会自动调用UserStaticFactory中的buildUser1静态方法获取UserModel对象,将其作为createBeanByStaticFactoryMethod1名称对应的bean对象放在spring容器中。
会调用UserStaticFactory的buildUser2方法,并且会传入2个指定的参数,得到返回的UserModel对象,将其作为createBeanByStaticFactoryMethod2名称对应的bean对象放在spring容器中。
运行Client(代码不变)
1 2 3 4
| createBeanByStaticFactoryMethod1:UserModel(name=我是无参静态构造方法创建的!, age=0) createBeanByStaticFactoryMethod2:UserModel(name=通过工厂静态有参方法创建UerModel实例对象, age=40)
|
从输出中可以看出,两个静态方法都被调用了,createBeanByStaticFactoryMethod1对应的bean对象是通过buildUser1方法创建的;createBeanByStaticFactoryMethod2对应的bean对象是通过buildUser2方法创建的。
通过实例工厂方法创建bean对象
让spring容器去调用某些对象的某些实例方法来生成bean对象放在容器中以供使用。
语法
1 2 3 4 5 6 7
| <bean id="bean名称" factory-bean="需要调用的实例对象bean名称" factory-method="bean对象中的方法"> <constructor-arg index="0" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="1" value="bean的值" ref="引用的bean名称" /> <constructor-arg index="2" value="bean的值" ref="引用的bean名称" /> .... <constructor-arg index="n" value="bean的值" ref="引用的bean名称" /> </bean>
|
spring容器以factory-bean的值为bean名称查找对应的bean对象,然后调用该对象中factory-method属性值指定的方法,将这个方法返回的对象作为当前bean对象放在容器中供使用。
案例
定义一个实例工厂
内部写2个方法用来创建UserModel对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package demo3;
import demo1.UserModel;
public class UserFactory {
public UserModel buildUser1() { System.out.println("----------------------1"); UserModel userModel = new UserModel(); userModel.setName("bean实例方法创建的对象!"); return userModel; }
public UserModel buildUser2(String name, int age) { System.out.println("----------------------2"); UserModel userModel = new UserModel(); userModel.setName(name); userModel.setAge(age); return userModel; } }
|
beans.xml
1 2 3 4 5 6 7 8 9 10
| <bean id="userFactory" class="demo3.UserFactory"/>
<bean id="createBeanByBeanMethod1" factory-bean="userFactory" factory-method="buildUser1"/>
<bean id="createBeanByBeanMethod2" factory-bean="userFactory" factory-method="buildUser2"> <constructor-arg index="0" value="通过bean实例有参方法创建UserModel实例对象"/> <constructor-arg index="1" value="30"/> </bean>
|
createBeanByBeanMethod1对应的bean是通过userFactory的buildUser1方法生成的。
createBeanByBeanMethod2对应的bean是通过userFactory的buildUser2方法生成的。
运行Client
1 2
| createBeanByBeanMethod1:UserModel(name=bean实例方法创建的对象!, age=0) createBeanByBeanMethod2:UserModel(name=通过bean实例有参方法创建UserModel实例对象, age=30)
|
通过FactoryBean创建bean对象
前面我们学过了BeanFactory接口,BeanFactory是spring容器的顶层接口,而这里要说的是FactoryBean,也是一个接口,这两个接口很容易搞混淆,FactoryBean可以让spring容器通过这个接口的实现来创建我们需要的bean对象。
FactoryBean接口源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public interface FactoryBean<T> {
@Nullable T getObject() throws Exception;
@Nullable Class<?> getObjectType();
default boolean isSingleton() { return true; }
}
|
接口中有3个方法,前面2个方法需要我们去实现,getObject方法内部由开发者自己去实现对象的创建,然后将创建好的对象返回给Spring容器,getObjectType需要指定我们创建的bean的类型;
最后一个方法isSingleton表示通过这个接口创建的对象是否是单例的,如果返回false,那么每次从容器中获取对象的时候都会调用这个接口的getObject() 去生成bean对象。
语法
1 2 3
| <bean id="bean名称" class="FactoryBean接口实现类" />
|
案例
创建一个FactoryBean实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package demo3;
import demo1.UserModel; import org.springframework.beans.factory.FactoryBean;
public class UserFactoryBean implements FactoryBean {
int count = 1;
@Override public UserModel getObject() throws Exception { UserModel userModel = new UserModel(); userModel.setName("我是通过FactoryBean创建的第"+count+++ "对象"); return userModel; }
@Override public Class<?> getObjectType() { return UserModel.class; }
@Override public boolean isSingleton() { return true; } }
|
bean xml配置
1 2
| <bean id="createByFactoryBean" class="demo3.UserFactoryBean"/>
|
Client代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package demo3;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Client { public static void main(String[] args) { String beanXml = "classpath:/bean.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml);
System.out.println("spring容器中所有bean如下:");
for (String beanName : context.getBeanDefinitionNames()){ System.out.println(beanName + ":" + context.getBean(beanName)); }
System.out.println("--------------------------"); System.out.println("createByFactoryBean:" + context.getBean("createByFactoryBean")); System.out.println("createByFactoryBean:" + context.getBean("createByFactoryBean"));
} }
|
运行Client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class demo1.UserStaticFactory.buildUser1() class demo1.UserStaticFactory.buildUser2() ----------------------1 ----------------------2 spring容器中所有bean如下: helloWorld:demo.HelloWord@17b7b6 user1:demo.HelloWord@1063c0a user2:demo.HelloWord@6d1014 user3:demo.HelloWord@707e36 user4:demo.HelloWord@14ddd49 user5:demo.HelloWord@1554b06 createBeanByConstructor1:UserModel(name=我是通过UserModel的无参构造方法创建的!, age=0) createBeanByConstructor2:UserModel(name=我是通过UserModel的有参方法构造的对象!, age=30) createBeanByStaticFactoryMethod1:UserModel(name=我是无参静态构造方法创建的!, age=0) createBeanByStaticFactoryMethod2:UserModel(name=通过工厂静态有参方法创建UerModel实例对象, age=40) userFactory:demo3.UserFactory@14e1548 createBeanByBeanMethod1:UserModel(name=bean实例方法创建的对象!, age=0) createBeanByBeanMethod2:UserModel(name=通过bean实例有参方法创建UserModel实例对象, age=30) createByFactoryBean:UserModel(name=我是通过FactoryBean创建的第1对象, age=0) -------------------------- createByFactoryBean:UserModel(name=我是通过FactoryBean创建的第1对象, age=0) createByFactoryBean:UserModel(name=我是通过FactoryBean创建的第1对象, age=0)
|
注意最后4行输出,有3行输出的都是同一个createByFactoryBean,程序中通过getBean从spring容器中查找createByFactoryBean了3次,3次结果都是一样的,说明返回的都是同一个UserModel对象。