目录
一、spring framework
1.IoC控制反转(Inversion of Control)
2.DI依赖注入(Dependency Injection)
3.bean基础配置
4.bean实例化
4.1构造方法
4.2静态工厂
4.3实例工厂
5.bean的生命周期
springframework 是spring 里面的一个基础开源框架,主要用于javaee的企业开发。
图源
不需要自己主动创建对象,由外部提供对象,对象创建控制权由程序转移到外部,称为控制反转。spring提供一个容器,称为IoC容器,IoC容器负责创建对象、初始化等一系列工作,被创建或管理的对象在IoC容器中统称为Bean
IoC 在其他语言中也有应用,并非 Spirng 特有。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。
在容器中建立bean和bean之间依赖关系的整个过程,称为依赖注入
‘高内聚,低耦合’
项目中每个模块之间相互联系的紧密程度,模块之间联系越紧密,耦合性越高,模块的独立性就越差
模块中各个元素之间的联系的紧密程度,如果各个元素(语句、程序段)之间的联系程度越高,内聚性越高
而我们设计软件需要的是“高内聚,低耦合”
使用IOC容器管理Bean,在IOC容器中把有依赖关系的都进行绑定,在使用对象时就可以之间从IOC容器中获取,并且所有的bean已经绑定好依赖关系,降低了耦合性,修改代码的时候不需要全部更改
spring默认提供的bean是单例的
想要修改成不是单例的可以在配置文件中修改
singleton默认为单例 prototype为非单例
scope="prototype"
为什么bean默认为单例?
bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象 bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高
bean在容器中是单例的,会不会产生线程安全问题?
如果对象是有状态对象,即该对象有成员变量可以用来存储数据的, 因为所有请求线程共用一个bean对象,所以会存在线程安全问题。 如果对象是无状态对象,即该对象没有成员变量没有进行数据存储的, 因方法中的局部变量在方法调用完成后会被销毁,所以不会存在线程安全问题。
实例化bean的三种方式,构造方法,静态工厂和实例工厂
bean本质上就是对象,对象在new的时候会使用构造方法完成,那创建bean也是使用构造方法完成 的。
Spring底层使用的是类的无参构造方法。
先创建接口BookDao和类BookDaoImpl
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
applicationContext.xml
编写运行程序
public class AppForLifeCycle {
public static void main( String[] args ) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao1 = (BookDao) ctx.getBean("bookDao");
bookDao1.save();
}
}
先创建接口BookDao和类BookDaoImpl
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
创建一个工厂类BookDaoFactory并提供一个静态方法
public class BookDaoFactory {
public static BookDao getOrderDao(){
return new BookDaoImpl();
}
}
配置文件
class:工厂类的类全名 factory-mehod:具体工厂类中创建对象的方法名
编写AppForLifeCycle运行类,在类中通过工厂获取对象
public class AppForLifeCycle {
public static void main( String[] args ) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao orderDao = (BookDao) ctx.getBean("bookDao");
orderDao.save();
}
}
在工厂的静态方法中,我们除了new对象还可以做其他的一些业务操作,
先创建接口BookDao和类BookDaoImpl
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
创建一个工厂类BookDaoFactory并提供一个方法 -----此时不是静态方法
public class BookDaoFactory {
public BookDao getOrderDao(){
return new BookDaoImpl();
}
}
配置文件
实例化工厂运行的顺序是:
创建实例化工厂对象,对应的是第一行配置
调用对象中的方法来创建bean,对应的是第二行配置
factory-bean:工厂的实例对象 factory-method:工厂对象中的具体创建对象的方法名
编写AppForLifeCycle运行类
public class AppForLifeCycle {
public static void main( String[] args ) {
BookDaoFactory bookDaoFactory = new BookDaoFactory();
BookDao bookDao = bookDaoFactory.getOrderDao();
bookDao.save();
}
}
以Spring为了简化这种配置方 式就提供了一种叫FactoryBean的方式来简化开发。
创建一个BookDaoFactoryBean的类,实现FactoryBean接口,重写接口的方法
public class BookDaoFactoryBean implements FactoryBean {
//代替原始实例工厂中创建对象的方法
public BookDao getObject() throws Exception {
return new BookDaoImpl();
}
//返回所创建类的Class对象
public Class> getObjectType() {
return BookDao.class;
}
}
配置文件
别的不需要更改
getObject(),被重写后,在方法中进行对象的创建并返回
getObjectType(),被重写后,主要返回的是被创建类的Class对象
isSingleton(),设置对象是否为单例,默认是true单例
项目中添加BookDao、BookDaoImpl、BookService和BookServiceImpl类
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destroy(){
System.out.println("destroy...");
}
}
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
为BookDao添加生命周期的控制方法,具体的控制有两个阶段:
bean创建之后,想要添加内容,比如用来初始化需要用到资源
bean销毁之前,想要添加内容,比如用来释放用到的资源
init-method="init" destroy-method="destroy"
运行方法
public class AppForLifeCycle {
public static void main( String[] args ) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
init方法执行了,但是destroy方法却未执行
Spring的IOC容器是运行在JVM中 运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方 法执行 main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了 所以没有调用对应的destroy方法
解决办法1close关闭容器
想要执行destroy方法,ApplicationContext中没有close方法 需要将ApplicationContext更换成ClassPathXmlApplicationContext,实例化对象ctx之后,调用close()方法
public class AppForLifeCycle {
public static void main( String[] args ) {
ClassPathXmlApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
ctx.close();
}
}
解决办法1注册钩子关闭容器
将ApplicationContext更换成ClassPathXmlApplicationContext,实例化对象ctx之后,调用registerShutdownHook()方法
public class AppForLifeCycle {
public static void main( String[] args ) {
ClassPathXmlApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
相同点:这两种都能用来关闭容器
不同点:close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭。
close()强制退出
事实上还有更简便的方法,Spring提供了两个接口来完成生命周期的控制,好处是可以不用再进行配置init-method和 destroy-method
修改BookServiceImpl类,添加两个接口InitializingBean, DisposableBean并实现接口中的两个方法afterPropertiesSet和destroy
初始化方法会在类中属性设置之后执行
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean{
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void destroy() throws Exception {
System.out.println("service destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}