*核心概念:
IOC(Inversion of Control)控制反转:
目的:为了降低程序间的耦合度
含义:把程序内主动new创造对象的过程交给外部程序去做,创建对象的过程中控制权由程序部转到了*外部*去实现。
Spring对Ioc
思想进行了实现:其提供了IOC
容器来充当IOC
思想的“外部”,IOC
负责创建和管理对象,被创建和管理的对象在IOC
中称为Bean
。DI(Dependence Injection) 依赖注入:
含义:在容器中建立bean之间的依赖关系。效果
:使用对象是不仅可以直接从容器中取,还能获取到bean绑定的所有依赖关系。
1:IOC入门案例:
- 在
pom.xml
配置文件中导入依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency>
- 在
resourse
文件夹中建立Spring配置文件applicationContext.xml
:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--1:导入spring的坐标spring-context,对应版本为5.2.10.RELEASE--> <!--2:配置bean--> <!--bean:配置bean--> <!--id:给bean起的别名--> <!--class:给bean定义类型--> <bean id="bookDao" class="com.ysj.dao.impl.BookDaoImpl"> </bean> <bean id="bookService" class="com.ysj.service.impl.BookServiceImpl"> </bean> </beans>
- 在测试类中:
//3:加载配置文件,获取IOC容器对象 ApplicationContext ext = new ClassPathXmlApplicationContext("applicationContext.xml"); //4:获取bean // BookDao bookDao = (BookDao) ext.getBean("bookDao"); // bookDao.save();; BookService bookService = (BookService) ext.getBean("bookService"); bookService.save();
- 入门案例中,此时在业务层实现中,仍存在new创建对象,耦合度相对来说仍然较高,接下来就到
DI(Dependence Injection)
登场了。
2:DI(Dependence Injection)入门案例:
//7:删除new private BookDao bookDao; public void save() { System.out.println("book service save ..."); bookDao.save(); } //8:设置setter方法:容器创建对象会调用setter方法 public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; }
<bean id="bookService" class="com.ysj.service.impl.BookServiceImpl"> <!-- 配置server与dao的关系(dao对象在server中创建,所以在server中配置)--> <!-- property:配置当前bean的属性,即对应类中的属性--> <!-- name:当前bean所对应的类中的具体属性--> <!-- ref:表示参照哪个bean进行配置--> <property name="bookDao" ref="bookDao"></property> </bean>
3:bean
3:bean的基础配置
3.1:name属性:给bean起别名,多个别名间用空格隔开
<bean id="bookDao" name="dao ss ss1" class="com.ysj.dao.impl.BookDaoImpl">
3.2:bean默认是单例模式
<!-- scope:选择bean是否为单例模式 prototype:多例 singleton:单例--> <bean id="bookDao" name="dao ss ss1" scope="prototype" class="com.ysj.dao.impl.BookDaoImpl">
3.3🏖bean默认是单例模式的原因
如果默认不是单例,那么创造的bean对象将会无穷无尽,增加了Spring的负担 ##适合交给容器进行管理的bean 1:表现层对象 2:业务层对象 3:数据层对象 4:工具类对象 ##不适合交给容器进行管理的bean 封装实体类的域对象
3.4:常见报错
//原因:没有命名为‘ss2’的bean //方法;检查bean容器别名和自己书写哪里不一致 NoSuchBeanDefinitionException: No bean named 'ss2' available
4:bean的实例化的三种方式
4.1:构造方法(常用)
##提供可访问的构造方法:无参(bean容器创建对象调用无参构造方法) ##如果没有无参构造方法将报‘BeanCreationException’,‘java.lang.NoSuchMethodException’异常
4.2:Spring报错处理方法
#从后往前看
4.3:静态工厂(了解)
//静态工厂创建对象 public class OrderDaoFactory { public static OrderDao getOrderDao(){ System.out.println("factory setup...."); return new OrderDaoImpl(); } }
<!-- 方式二:使用静态工厂实例化bean,记得配置工厂造对象的具体方法--> <bean id="orderDao" class="com.ysj.factory.OrderDaoFactory" factory-method="getOrderDao"/>
4.4:实例工厂
4.4.1:实例工厂实例化(了解)
- 第一个bean仅仅是为了配合使用,创造对象,除此之外无其他意义
- factory-method:如果这样配置,方法名不固定,每次配置bean都要配置
<!-- 方式三:使用实例工厂实例化bean--> <bean id="userFactory" class="com.ysj.factory.UserDaoFactory"/> <!--factory-bean:配置工厂类的bean--> <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
4.4.2:FactoryBean
(实用)
//FactoryBean创建对象 public class UserDaoFactoryBean implements FactoryBean<UserDao> { //代替原始实例工厂中创建对象的方法,bean中不必再配置factory-method,统一使用该方法创建对象 public UserDao getObject() throws Exception { return new UserDaoImpl(); } public Class<?> getObjectType() { return UserDao.class; } //true:创建对象是单例 //false:创建对象非单例 public boolean isSingleton() { return false; } }
<!--方式四:使用FactoryBean实例化bean--> <bean id="userDao" class="com.ysj.factory.UserDaoFactoryBean"/>
5:bean的生命周期
5.1:bean的初始化和销毁方法的配置
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 destory(){ System.out.println("destroy..."); } }
<!--init-method:设置bean初始化生命周期回调函数--> <!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象--> <bean id="bookDao" class="com.ysj.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
配置完后运行程序,会发现destroy方法没有运行,这时你大叫:“Why?”
其实是因为:我们这些程序运行在虚拟机上,当IOC
容器加载完配置后,bean也初始化了,接着运行程序,
然而当程序运行完后,虚拟机退出了,俺类destroy并没有机会执行,呜呜呜呜~~
public static void main( String[] args ) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); }
那么,如何让俺滴销毁方法执行呢?
有如下两个方法:
5.2:让销毁执行起来
注意把在加载IOC
容器时定义ClassPathXmlApplicationContext
对象
5.2.1:手动close(太暴力了,直接就停了)
用这个要注意使用的位置
public static void main( String[] args ) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); //关闭容器 ctx.close(); }
5.2.3:注册关闭钩子函数
虚拟机会在退出之前调用此函数,进而关闭容器
public static void main( String[] args ) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器 ctx.registerShutdownHook(); }
5.2:接口控制(了解)
按照Spring官方给的接口和规范进行配置
实现InitializingBean, DisposableBean
接口
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean { private BookDao bookDao; //在资源加载完后运行,但是在调用方法之前 public void afterPropertiesSet() throws Exception { System.out.println("service init"); } public void setBookDao(BookDao bookDao) { System.out.println("set ....."); this.bookDao = bookDao; } public void save() { System.out.println("book service save ..."); bookDao.save(); } public void destroy() throws Exception { System.out.println("service destroy"); } }
5.3:生命周期历程
- 初始化容器
- 创建对象(内存分配,类似于new,在内存中分配了空间)
- 执行构造方法(对象创建完成)
- 执行属性注入(set操作)
- 执行bean的初始化方法
- 使用bean
执行业务层 - 关闭/销毁容器
执行bean的销毁方法
5.4:小记
所有bean在IOC
容器加载完配置后就被初始化了