1、我们先看一下通过spring创建的实例,是单实例的还是多实例的?
UserServlet us1=ioc.getBean("userServlet",UserServlet.class);
UserServlet us2=ioc.getBean("userServlet",UserServlet.class);
System.out.println(us1==us2);//true
通过代码实现,我们发现他是单实例的,默认情况下,spring管理的bean是单实例的
所以,在多线程的情况下,有线程安全问题,你修改了一个bean,会影响其他的bean
//例 单例实的bean 引发的问题
public static void main(String[] args) {
ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
UserServlet servlet1=ioc.getBean("userServlet_name", UserServlet.class);
UserInfo user=new UserInfo();
user.setUserName("赵明明");
user.setPassword("123");
servlet1.user=user;
UserServlet servlet2=ioc.getBean("userServlet_name", UserServlet.class);
System.out.println(servlet2.user); //可以看到,对 servlet1的修改,影响到了servlet2 (实际上它们就是同一个对象)
System.out.println(servlet1==servlet2); //true
}
如果是多线程情况下,显然这是有问题的
因此,spring利用作用域,说你想要单例的就给你单例,想要多例的就给你多例的
一、bean的作用域:可以通过配置文件设置,不设置的话就是sigleton的
<bean name="userServlet" class="com.servlet.UserServlet" scope="prototype">
<property name="userdao" ref="userDaoImpl"></property>
</bean>
1)sigleton 单例的(默认就是)
2)prototype 多例的
3)request
4)session
如果配置文件改成了scope=prototype上面的单实例的例子创建出来的对象就不是单例的了,而是多实例的
1)sigleton 单例的(默认就是)
对spring管理的bean,默认就是单实例的
这些单实例的bean是什么时候创建的呢?
默认是在容器初始化的时候创建的(容器初始化就是加载配置文件的时候)、
这个创建时间也可以设置(lazy-init="true")、不设置的话就是default,设置为true就是懒加载
<bean name="userServlet_name" class="com.servlet.UserServlet" lazy-init="true" >
...
</bean>
经过上面的配置,这个bean不会在容器初始化的时候创建,而是在我们向容器要这个bean的时候才创建
如果所有的bean ,都想这样,可以在 beans 标签上加 default-lazy-init="true" ,如下:
<beans default-lazy-init="true" ... >
验证一下:真的是在容器加载的时候就创建对象了吗
(1)配置文件:没有配置scope,是单实例的
<bean name="userServlet" class="com.servlet.UserServlet" scope="prototype">
<property name="userdao" ref="userDaoImpl"></property>
</bean>
(2)UserServlet中:构造方法
public class UserServlet {
//依赖对象
private UserDao userdao;
public UserServlet() {
System.out.println("对象创建了");
}
public void service() {
userdao.addUser();
userdao.delUser();
userdao.updateUser();
}
public void setUserdao(UserDao userdao) {
this.userdao=userdao;
}
}
(3)测试文件中:只加载,不调用ioc创建对象
public class Test {
public static void main(String[] args) {
//spring给我们提供的一个类,这个类能从类路径(src下或者你建的那个文件夹就是源文件夹也叫类路径下)下加载我们的spring的配置文件
ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
(4)控制台输出结果:我们发现即使没有用Ioc创建对象,也调用了构造方法,这是因为单实例的bean,spring默认在容器加载的时候,就为我们创建好对象
2)prototype 多例的
多实例的自然就没有lazy-init属性了
在 bean 上加 scope="prototype" 如下:
<bean name="userServlet_name" class="com.servlet.UserServlet" scope="prototype" >
<property name="dao" ref="userDaoImpl_name" />
</bean>
思考:什么时候用单实例的bean,什么时候用多实例的bean?
没有线程安全问题的时候,用单实例的,否则用多实例的
一般来说, dao层多数用单实例的, 控制层一般用多实例的,但也不是绝对
如果一个对象的构造方法私有化了?spring还能不能创建出这个对象的实例呢?
可以,即使对象构造方法私有化了,spring也能帮我们创建出这个对象的实例
二、Bean的init-Method和destroy-method方法
单实例的bean中:
(1)UserInfo中
public class UserInfo {
private int id;
private String userName;
private String password;
private String note;
...
public void initXXX() {
System.out.println("initXXX 调用了,主要用于初始化");
}
public void destoryXXX() {
System.out.println("destoryXXX 调用了,主要用于清理");
}
}
2)配置文件中只要加上init-method和destroy-method属性
<bean name="userInfo_name" class="com.beans.UserInfo" init-method="initXXX" destroy-method="destoryXXX">
<property name="id" value="1" />
<property name="userName" value="赵明明" />
<property name="password" value="123" />
<property name="note" value="这是spring创建的对象" />
</bean>
3)测试:
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
UserInfo user1=ioc.getBean("userInfo_name", UserInfo.class);
UserInfo user2=ioc.getBean("userInfo_name", UserInfo.class);
UserInfo user3=ioc.getBean("userInfo_name", UserInfo.class);
ioc.close();
}
}
4)输出
总结:
对于单实例的bean,会在创建实例的时候调用init-method,在销毁的时候调用destroy-method
对于多实例的bean,创建的时候每个都会调用init-method,但在销毁的时候,不会调用destroy-method,因为多实例的bean,spring在创建以后,就不再对他们的生命周期负责了
三、集合类型的装配
1、set类型的集合装配,在配置文件中做一个set集合的装配
2、list集合的装配
3、map集合的装配
4、properties :键值对结构,map的一个子类