一、IOC(控制翻转)
- 什么是 IOC?
把对象的创建、初始化、销毁等工作交给 Spring 容器来做。 - 创建对象的方式
Bean类:
@Data
public class User {
private Integer id;
private String username;
private String password;
public User(){
System.out.print("用户构造器\n");
}
}
A. 构造器
@Data
public class User {
private Integer id;
private String username;
private String password;
public User(){
System.out.print("用户构造器\n");
}
}
配置:
<!--构造注入-->
<bean id="user0" class="com.neuedu.entity.User">
<property name="username" value="测试一下spring"/>
</bean>
B. 静态工厂
public class UserStaticFactory {
public static User getInstance() {
User user=new User();
user.setUsername("张三");
return user;
}
}
配置:
<!--静态工厂注入-->
<bean id="user1" class="com.neuedu.factory.UserStaticFactory" factory-method="getInstance">
</bean>
C. 实例工厂
public class UserInstanceFactory {
public User getInstance(){
User user=new User();
user.setUsername("张三");
return user;
}
}
配置:
<!--实例工厂注入-->
<bean id="userFactory" class="com.neuedu.factory.UserInstanceFactory">
</bean>
<bean id="user2" factory-bean="userFactory" factory-method="getInstance">
</bean>
- 别名
<bean id="userFactory"
class="com.neuedu.UserInstanceFactory"></bean>
<!--
factory-bean:指向工厂bean
factory-method:指向工厂方法
-->
<bean id="user" factory-bean="userFactory" factorymethod="getInstance"></bean>
<alias name="user" alias="abc"/>
给对象 user 起个别名叫张三。
测试:
@Test
public void testTest() {
User user = (User)applicationContext.getBean("abc");
user.setUserName("XXX");
user.output();
}
二、对象的创建时机
当 spring 容器启动的时候创建对象便会根据 bean 配置创建相应对象,有几个 bean 就会创建几次对象。
<bean id="user" lazy-init="default" class="com.neuedu.User"></bean>
lazy-init 属性:
Default 相当于 false
在 spring 容器启动的时候,创建对象
True 在 context.getBean 时创建对象;
False 在 spring 容器启动的时候创建对象;
如果把 lazy-init 设置为 true,则当 spring 容器启动的时候,检测不到任何错误,这样会存在很大的安全性隐患,所以一般情况下应该设置 lazy-init 为 default/false。但是如果一个 bean中有一个属性,该属性含有大量的数据,这个时候不希望该 bean 过早的停留在内存中。
这个时候需要用到 lazy-init 为 true。
三、对象的 scope 作用域
默认情况(scope=singleton)
@Test
public void testTest() {
User user1 = (User)applicationContext.getBean("user");
User user2 = (User)applicationContext.getBean("user");
System.out.println(user1);
System.out.println(user2);
}
结果:
构造器方式创建对象
com.neuedu.User@52a86356
com.neuedu.User@52a86356
在默认情况下放入到 spring 中的 bean 是单例的
将来 service 层和 dao 层所有的类将放入到 spring 容器中,所以默认情况下这两个层的
类的实例都是单例的,所以不能把数据声明到属性中。如果声明在属性中,将会成为共享的。
Scope 为 prototype
<bean id="user" scope="prototype" class="com.neuedu.User"></bean>
测试:
@Test
public void testTest() {
User user1 = (User)applicationContext.getBean("user");
User user2 = (User)applicationContext.getBean("user");
System.out.println(user1);
System.out.println(user2);
}
结果:
构造器方式创建对象
构造器方式创建对象
com.neuedu.User@544fe44c
com.neuedu.User@31610302
四、创建时机和 scope 的结合
- Scope 为 prototype时,只有在context.getBean 时创建对象。
- Scope 为 prototype,lazy-init 为 true,在 context.getBean 时创建对象。
- Scopse 为 prototype,lazy-init 为 false在 context.getBean 时创建对象,lazy-init 为 false 失效;
- 当 scpose 为 prototype 时,始终在 context.getBean 时创建对象。
<!--构造注入-->
<bean id="user" scope="prototype" class="com.neuedu.entity.User">
</bean>
测试:
User user = (User) applicationContext.getBean("user");
五、Init 和 destroy
@Data
public class User {
private Integer id;
private String username;
private String password;
public User(){
System.out.print("用户构造器\n");
}
public void init(){
System.out.print("初始化方法\n");
}
public void destory(){
System.out.print("销毁方法\n");
}
}
配置:
<bean id="user" init-method="init" destroy-method="destory" class="com.neuedu.entity.User">
<property name="username" value="测试一下spring"/>
</bean>
测试:
@Test
public void testSpring() {
//关闭Spring容器
ClassPathXmlApplicationContext
application=(ClassPathXmlApplicationContext)applicationContext;
application.close();
}
说明:
1、 init 方法是由 spring 内部执行的;
2、 只有当 spring 容器关闭以后才能执行 destroy 方法,spring 容器一般情况下是不会关闭的。只有当 web 容器销毁掉的时候才可能关闭掉,所以只要一个对象在 spring容器中,在 spring 容器关闭之前,会一直保留。
3、 如果一个 bean 的配置是 scope 为”prototype”,则 spring 容器不负责销毁。