Java框架(三)--Spring IoC(3)--bean scope属性及bean的生命周期

五、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='欧洲'}
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值