前提:要求Spring管理的类都要提供 公开的无参的构造。
通过Bean标签告诉Spring该用什么方式获得类的对象
首先写一个pojo类
public class User {
private Integer id;
private String name;
public User(){
System.out.println("调用默认构造");
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
然后告诉Spring如何管理
<bean id = "user" class="org.buaa.pojo.User">
bean>
最后使用它
public void testUser(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user);
/* 结果
调用默认构造
User{id=null, name='null'}
*/
}
静态工厂方法: 在一个类中书写静态方法,再这个方法中返回某个 Bean 的对象。
首先写一个基本的工厂
public class UserFactory {
public static User getUserInstance(){
return new User();
}
}
告诉Spring如何配置
<bean id = "user" class = "org.buaa.factory.UserFactory" factory-method="getUserInstance">bean>
实际上Spring管理的不是UserFactory类,而是User类
编写测试
public void testStaticFactory(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 这个方法最终得到的是一个User对象,所以应该接收一个User对象
// 通过静态工厂方法得到User
User user = (User) context.getBean("user");
System.out.println(user);
/*
调用默认构造
调用默认构造
User{id=null, name='null'}
*/
}
可以看到构造方法执行了两次。原因: 在加载核心配置文件时,Spring会加载每一个标签,而我们没有删除 #1.1 中的标签,所以目前核心配置文件如下。可以看到Spring管理了两个User,都会初始化一次,所以会调用两次构造。
<bean id = "user" class="org.buaa.pojo.User">bean>
<bean id = "userFactory" class = "org.buaa.factory.UserFactory" factory-method="getUserInstance">bean>
实际上,我们仅书写加载核心配置文件的代码,也会出现调用两次构造的情况。
所以,核心配置文件只应加载一次。但是一个Spring的核心容器中可以管理多个相同的class而new出来的对象
实例工厂方法:和静态工厂类似,但工厂本身是一个实例。
在类中提供非静态的方法,在这个方法中返回需要获取的Bean对象
实例工厂
public class InstanceFactory {
public User getUserInstance(){
return new User();
}
}
配置
<bean id = "instanceFactory" class = "org.buaa.factory.InstanceFactory">bean>
<bean id = "user2" factory-method="getUserInstance" factory-bean="instanceFactory">bean>
测试
public void testInstanceFactory(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user2");
System.out.println(user);
}
经常面试到
是一种实例化Bean的方式。
首先编写自定义类,实现 FactoryBean接口
/**
* 使用 Spring 底层提供的 FactoryBean接口 来实例化某个类的对象
* 自定义一个类,实现 FactoryBean接口
*/
public class UserInstance implements FactoryBean<User> {
// getObject方法中创建出需要管理的Bean对象
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
配置
<bean id = "user3" class = "org.buaa.factory.UserInstance">bean>
测试
FactoryBean:是用来创建指定的一个Bean实例的接口,用来告诉Spring如何实例化一个具体的类的对象
BeanFactory:是管理Bean的,它是Spring中最的顶层接口之一(ApplicationContext 是它的子接口的子接口),代表的是Spring容器加载spring核心配置文件的对象
在配置 bean 的时候,有一个标签为 scope,代表它的作用域
<bean id = "user4" class = "org.buaa.pojo.User" scope="singleton">bean>`
<bean id = "user5" class = "org.buaa.pojo.User" scope="prototype">bean>`
singleton下每次getBean,获取的结果都是同一个。
prototype下每次getBean,都会新建一个对象。
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user1 = (User) context.getBean("user4");
User user2 = (User) context.getBean("user4");
user1 == user2;// true
User user3 = (User) context.getBean("user5");
User user4 = (User) context.getBean("user5");
user3 == user4;// false
Bean在创建/销毁时,让它执行一些方法。
pojo如下:
public class User {
...
public void init(){
System.out.println("初始化时可以执行的方法");
}
public void destory(){
System.out.println("销毁时可以执行的方法");
}
...
}
配置
<bean id = "user5" class = "org.buaa.pojo.User" init-method="init" destroy-method="destory">bean>
测试
public void testUserInitAndDestory(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user5");
System.out.println(user);
/*
调用默认构造
初始化时可以执行的方法
User{id=null, name='null'}
*/
((ClassPathXmlApplicationContext)context).close();
/* 销毁时可以执行的方法 */
}
注意 并没有执行销毁的方法,想要执行它,需要手动关闭Spring容器,而ApplicationContext接口没有提供close方法,所以必须强制幻化为ClassPathXmlApplicationContext对象,然后调用close。
注意 如果Bean设置为prototype多例,那么即使手动关闭也不会执行。
缺点:在xml文件中写死了传入什么值。当然也可以改为"${}"通过引配置文件解决,但是很麻烦
pojo
public class User {
...
public User(Integer id, String name){
this.id = id;
this.name = name;
}
...
}
配置
<bean id = "car" class = "org.buaa.pojo.Car"/>
<bean id="user6" class = "org.buaa.pojo.User">
<constructor-arg name = "name" value = "jackl"/>
<constructor-arg index = "1" value ="1"/>
<constructor-arg name = "car" ref = "car"/>
bean>
首先要在pojo类中书写set方法,然后配置文件
pojo
public class Car {
...
private String color;
private Integer price;
private String type;
public void setColor(String color) {
this.color = color;
}
public void setPrice(Integer price) {
this.price = price;
}
public void setType(String type) {
this.type = type;
}
...
}
配置
<bean id = "car" class = "org.buaa.pojo.Car">
<property name = "Color" value = "黄色"/>
<property name = "Price" value = "100"/>
<property name = "Type" value = "黄色"/>
bean>
其实本质还是前两种注入方式,只是想注入集合有些不太一样
<bean id = "student" class = "org.buaa.pojo.Student">
<property name = "lists">
<list>
<value>爬山value>
<value>下海value>
list>
property>
<property name = "maps">
<map>
<entry key = "addr" value = "北京"/>
map>
property>
bean>
<bean id = "student" class = "org.buaa.pojo.Student">
<constructor-arg name = "set"/>
<set>
<value>爬山value>
<value>下海value>
set>
constructor-arg>
bean>
是bean的子标签,用于使用构造方法传入数据
是bean的子标签,用于使用set方法传入数据
如果注入的数据是集合,那么要使用特定的集合标签
<list>
<value>值value>
list>
<set>
<value>值value>
set>
<map>
<entry key = "k", value = "v"/>
map>
<array>
<value>11value>
<value>12value>
<value>13value>
array>
<props>
<prop key = "sex">男prop>
<prop key = "height">2.0prop>
props>