IOC容器——Bean
- Bean配置
- name别名属性
- Bean作用范围scope
- Bean的实例化
- 构造方法示例化
- 静态工厂实例化
- 实例工厂与FactoryBean
- 实例工厂
- FactoryBean
- bean的生命周期
Bean配置
name别名属性
Bean ID 唯一,而关于Spring别名,我们可以在配置文件中使用name来定义,解决命名时产生的分歧
注意哦“class”属性不能写接口如BookDao的类全名,因为接口是没办法创建对象的。
- NoSuchBeanDefinitionException:
这个异常可能是我们经常遇到的异常,需要特别注意哦,主要是因为无法获取到IOC中的Bean(不管是通过name还是id无法获取时都会抛出这个异常)
🍊个🌰:
很明显没有service2这个别名
诺就会爆下面这个错误咯:
Bean作用范围scope
先看一个图
很明显我们可以看出Spring为我们创建对象时是单例的,即只创建一个相同的对象,即scope=“singleton” 如果我们把属性切换为scope=“prototype”,便不再是单例。
那么为什么Spring管理的对象默认是单例的嘞,其实很容易想,如果不是单例的话,那就会创建无穷多个咯,bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,提高性能,所以IOC也更适合管理可复用的一些对象。比如:表现层对象 业务层对象 数据层对象 工具对象(更适合交给IOC管理);相反封装实例的域对象(实体类),因为会引发线程安全问题,所以不适合。
- 关于单例Bean的一些线程安全问题
如果对象是有状态对象,即该对象有成员变量可以用来存储数据的,因为所有请求线程共用一个bean对象,所以会存在线程安全问题。如果对象是无状态对象,即该对象没有成员变量没有进行数据存储的,因方法中的局部变量在方法调用完成后会被销毁,所以不会存在线程安全问题。
因为是单例的所以我们创建的类对象都是同一个类,如果我们根据这个bean创建了多个不同的类并且需要修改时,修改一个其他都会改变
Bean的实例化
通过前面的学习我们大概已经知道了,IOC如何管理对象,那么IOC中的对象又是如何进行创建的捏?
首先关于如何示例话bean,我们有三种方式:构造方法、静态工厂、实例工厂
构造方法示例化
首先我们做好一些准备
1、配置好Spring环境后,准备一个BookDao接口和BookDaoImpl类
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
2、既然我们说了是使用构造方法进行实例化那么何以见得捏
我们给它加一个构造方法观察它是否执行构造方法就好啦
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
甚至我们可以尝试把public修饰换成private,我们发现同样可以(暴力反射我们日后再提),如果我们再在构造方法加入参数我们会发现无法运行,经过尝试我们便可知道Spring创建Bean使用的是无参构造方法
静态工厂实例化
我们创建一个静态工厂并配置一下xml文件。
同时我们对他编写启动类进行启动测试
当然我们工厂类创造时一定要注意那个具体的实例方法即factory-method
实例工厂与FactoryBean
实例工厂
我们发现实例工厂与静态工厂及其相似不同点的话就是静态工厂中的方法是静态方法。
所以我们在修改配置文件时也要注意实例工厂造Bean时首先要把实例工厂这个Bean造出来
所以我们会发现userFactory被创建出来就是为了创造底下的bean,我们有什么办法再进行一下优化吗?——FactoryBean
FactoryBean
还是上面的实例工厂但是我们在创建实例工厂的时候,让这个Bean实现FactoryBean这个接口,同时他的范型为我们需要造的对象。
当然我们需要实现他的方法,默认会实现两个如下图所示
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
public Class<?> getObjectType() {
return UserDao.class;//要注意这里的类型
}
}
当然配置文件也要改咯
当然此时我们的创建对像依旧默认是单例的,如果我们在实例工厂时,多实现一个方法便可使其非单例,(当然配置文件也可当如果同时使用scope,则以下面这个方法为主)如下图所示:
bean的生命周期
通过添加init-method=“” 与destroy-method=""属性来控制初始化与关闭
值得注意的是Spring的IOC容器是运行在JVM中运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方法执行main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了所以没有调用对应的destroy方法,那如果我们需要关闭容器呢?因为ApplicationContext中没有close方法需要将ApplicationContext更换成ClassPathXmlApplicationContext便可在最后添加close执行关闭程序的方法内容。
当然close是暴力关闭,我们还可以注册关闭钩子
ctx.registerShutdownHook() :任何地方都可以在运行完后关闭钩子。
(意思就是close关闭属于暴力关闭后无法执行后面内容)
其实以上内容我们相对用的都较少,所以我们并没有加图片示意或者标注
我们更推荐service实现相应的接口与方法
当然顾名思义afterPropertiesSet方法会在类属性设置执行之后再执行