文章目录
五、bean scope属性详解
1、bean scope属性
bean scope属性用于决定对象何时被创建与作用范围。
bean scope配置将影响容器内对象的数量。
bean scope默认值singleton(单例),指全局共享同一个对象实例。
默认情况下bean会在IoC容器创建后自动实例化,全局唯一。
2、scope用法
3、bean scope属性清单
4、singleton单例示意图
singleton在容器是单例多线程执行,存在线程安全风险。
singleton的线程安全问题。
5、prototype多例示意图
prototype在容器中多实例,占用更多资源,不存在线程安全问题。
6、singleton与prototype对比
7、bean scope的实际应用
在com.ql.spring.ioc.dao包下创建类
package com.ql.spring.ioc.dao;
public class UserDao {
public UserDao() {
System.out.println("UserDao已创建:"+this);
}
}
然后在applicationContext.xml中添加配置
<bean id="userDao" class="com.ql.spring.ioc.dao.UserDao">
</bean>
然后在SpringApplication中获取容器
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
//UserDao已创建:com.ql.spring.ioc.dao.UserDao@2096442d
表明scope为单例模式(默认)时IoC初始化时就创建对象。
所有给bean添加属性scope="prototype"再执行就不会输入创建的信息了
<bean id="userDao" class="com.ql.spring.ioc.dao.UserDao" scope="prototype"/>
现在在SpringApplication中添加两个获取bean实例,就会创建两次对象了
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserDao userDao1 = context.getBean("userDao", UserDao.class);
UserDao userDao2 = context.getBean("userDao", UserDao.class);
/*
UserDao已创建:com.ql.spring.ioc.dao.UserDao@28feb3fa
UserDao已创建:com.ql.spring.ioc.dao.UserDao@42e26948
*/
在com.ql.spring.ioc.service包下创建UserService
package com.ql.spring.ioc.service;
import com.ql.spring.ioc.dao.UserDao;
public class UserService {
private UserDao userDao;
public UserService() {
System.out.println("UserService已创建:"+this);
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
System.out.println("调用setUserDao:"+userDao);
this.userDao = userDao;
}
}
然后在applicationContext.xml中添加配置
<bean id="userDao" class="com.ql.spring.ioc.dao.UserDao" scope="prototype"/>
<bean id="userService" class="com.ql.spring.ioc.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
然后在SpringApplication中获取容器
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
/*
UserService已创建:com.ql.spring.ioc.service.UserService@5a61f5df
UserDao已创建:com.ql.spring.ioc.dao.UserDao@5034c75a
调用setUserDao:com.ql.spring.ioc.dao.UserDao@5034c75a
*/
得出添加scope="prototype"属性后,只有被使用的时候才会被实例化。
如果applicationContext.xml改成如下
<bean id="userDao" class="com.ql.spring.ioc.dao.UserDao" scope="prototype"/>
<bean id="userService" class="com.ql.spring.ioc.service.UserService" scope="prototype">
<property name="userDao" ref="userDao"/>
</bean>
然后SpringApplication改成如下,输出为
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
System.out.println("========IoC容器已经被初始化========");
UserService userService1 = context.getBean("userService", UserService.class);
UserService userService2 = context.getBean("userService", UserService.class);
UserService userService3 = context.getBean("userService", UserService.class);
UserService userService4 = context.getBean("userService", UserService.class);
/**
========IoC容器已经被初始化========
UserService已创建:com.ql.spring.ioc.service.UserService@1753acfe
UserDao已创建:com.ql.spring.ioc.dao.UserDao@39c0f4a
调用setUserDao:com.ql.spring.ioc.dao.UserDao@39c0f4a
UserService已创建:com.ql.spring.ioc.service.UserService@27c20538
UserDao已创建:com.ql.spring.ioc.dao.UserDao@72d818d1
调用setUserDao:com.ql.spring.ioc.dao.UserDao@72d818d1
UserService已创建:com.ql.spring.ioc.service.UserService@6e06451e
UserDao已创建:com.ql.spring.ioc.dao.UserDao@59494225
调用setUserDao:com.ql.spring.ioc.dao.UserDao@59494225
UserService已创建:com.ql.spring.ioc.service.UserService@6e1567f1
UserDao已创建:com.ql.spring.ioc.dao.UserDao@5cb9f472
调用setUserDao:com.ql.spring.ioc.dao.UserDao@5cb9f472
*/
在实际项目中,Dao、Service、Controller具体的类为单例的,因为Dao类作为Service类属性,在Service类中是稳定不变的,所以并不会出现线程安全的问题。
六、bean的生命周期
首先在com.ql.spring.ioc.entity包下创建Order实体类
package com.ql.spring.ioc.entity;
public class Order {
private Float price;
private Integer quantity;
private Float total;
public Order() {
System.out.println("创建Order对象,"+this);
}
public void init(){
System.out.println("执行init()方法");
total = price * quantity;
}
public void pay(){
System.out.println("订单金额为:"+total);
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
System.out.println("设置price为:"+price);
this.price = price;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
System.out.println("设置quantity为:"+quantity);
this.quantity = quantity;
}
public Float getTotal() {
return total;
}
public void setTotal(Float total) {
this.total = total;
}
public void destroy(){
System.out.println("释放与订单对象相关的资源");
}
}
然后在applicationContext.xml中配置
<bean id="order1" class="com.ql.spring.ioc.entity.Order" init-method="init" destroy-method="destroy">
<property name="price" value="19.8"/>
<property name="quantity" value="1000"/>
</bean>
然后SpringApplication中获取容器和bean
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
System.out.println("========IoC容器已经被初始化========");
Order order1 = context.getBean("order1", Order.class);
order1.pay();
((ClassPathXmlApplicationContext)context).registerShutdownHook();
/**
创建Order对象,com.ql.spring.ioc.entity.Order@52af6cff
设置price为:19.8
设置quantity为:1000
执行init()方法
========IoC容器已经被初始化========
订单金额为:19800.0
释放与订单对象相关的资源
*/
七、实现极简IoC容器
1、打开IDEA创建新的maven工程,在com.ql.spring.ioc.entity包下创建Apple实体类
package com.ql.spring.ioc.entity;
public class Apple {
private String title;
private String color;
private String origin;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
@Override
public String toString() {
return "Apple{" +
"title='" + title + '\'' +
", color='" + color + '\'' +
", origin='" + origin + '\'' +
'}';
}
}
2、在resources目录下创建配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id="sweetApple" class="com.ql.spring.ioc.entity.Apple">
<property name="title" value="红富士"/>
<property name="color" value="红色"/>
<property name="origin" value="欧洲"/>
</bean>
</beans>
3、在com.ql.spring.ioc.context包下创建ApplicationContext接口和它的实现ClassPathXmlApplicationContext
package com.ql.spring.ioc.context;
public interface ApplicationContext {
public Object getBean(String beanId);
}
package com.ql.spring.ioc.context;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class ClassPathXmlApplicationContext implements ApplicationContext{
private Map iocContainer = new HashMap<>();
public ClassPathXmlApplicationContext() {
try {
String filePath = this.getClass().getResource("/applicationContext.xml").getPath();
filePath = new URLDecoder().decode(filePath, "UTF-8");
SAXReader reader = new SAXReader();
Document document = reader.read(new File(filePath));
List<Node> beans = document.getRootElement().selectNodes("bean");
for (Node node : beans){
Element element = (Element) node;
String id = element.attributeValue("id");
String className = element.attributeValue("class");
Class c = Class.forName(className);
Object obj = c.newInstance();
List<Node> properties = element.selectNodes("property");
for(Node p : properties){
Element property = (Element) p;
String proName = property.attributeValue("name");
String proValue = property.attributeValue("value");
String setMethodName = "set" + proName.substring(0,1).toUpperCase() + proName.substring(1);
System.out.println("准备执行"+setMethodName+"方法注入数据");
Method method = c.getMethod(setMethodName, String.class);
method.invoke(obj, proValue);//通过setter方法注入数据
}
iocContainer.put(id, obj);
}
System.out.println("IoC容器初始化完毕");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Object getBean(String beanId) {
return iocContainer.get(beanId);
}
}
4、在com.ql.spring.ioc包下创建入口类Application,然后执行代码
package com.ql.spring.ioc;
import com.ql.spring.ioc.context.ApplicationContext;
import com.ql.spring.ioc.context.ClassPathXmlApplicationContext;
import com.ql.spring.ioc.entity.Apple;
public class Application {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext();
Apple sweetApple = (Apple)context.getBean("sweetApple");
System.out.println(sweetApple);
}
}
/*
准备执行setTitle方法注入数据
准备执行setColor方法注入数据
准备执行setOrigin方法注入数据
IoC容器初始化完毕
Apple{title='红富士', color='红色', origin='欧洲'}
*/