Ioc和DI
Ioc(Inversion of Contorl)控制反转---->一种编程思想
为了降低程序的耦合性,我们由主动new一个对象转换为由外部提供对象。
此过程中对象创建控制权由程序转移到外部,这种思想叫做控制反转。
Spring技术对这种思想进行了实现。
Spring提供了一个容器,称之为“Ioc容器”充当Ioc思想中的外部。
Ioc容器负责对象的创建、初始化等一系列操作,被创建或者管理的容器在Ioc容器中成为bean。
DI(dependency Injection)依赖注入
在容器中建立bean与bean之间的依赖关系的整个过程,称之为依赖注入。
Ioc入门
1、导入maven坐标
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
2、创建Spring配置文件
bean标签表示配置bean
id属性表示给bean起名字
class属性表示给bean定义类型
注意:之前的new我们可以理解为自己做菜,而这里面的bean相当于告诉计算机菜单,要求计算机给你做哪些菜。同时对于bean,我们可以在不同的bean中间建立起联系。
<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对应的依赖坐标-->
<!--2、配置bean-->
<bean id="BookDao" class="com.tsj.dao.impl.BookDaoImpl"/>
<bean id="BookService" class="com.tsj.service.impl.BookServiceImpl"/>
</beans>
3、获取Ioc容器
4、通过Ioc容器获取bean
public class APP2 {
public static void main(String[] args) {
//3、获取Ioc容器
ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
//4、获取bean
//此处利用了接口多态,即编辑看左,运行看右边,创建的对象实际是实现类对象,但是类型是接口(向上转换)
BookDao BookDao=(BookDao) act.getBean("BookDao_test");
//调用了子类中重写的方法,且向上转换只能调用子类重写的方法
BookDao.save();
}
}
DI入门(基于Ioc管理bean)
为了将service中通过new创建dao对象的代码删除,我们需要提供在service中创建dao对象的方法。同时,我们需要在配置文件中描述service对象和dao对象之间的关系。
5、去除new
6、创建set方法提供dao对象
public class BookServiceImpl implements BookService {
//5、去除new
private BookDao bookDao;
@Override
public void save() {
System.out.println("BookServiceImpl is saving");
bookDao.save();
}
//6.提供对应的set方法
//set方法是容器在调用,谁要创建对象谁调用
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
7、配置sever与dao的关系
请注意:第一个name对应的bookDao指的是方法形参,用来对应创建对象。
第二个ref对应的bookDao指的是关联其他bean的id,(其实关联其他bean的name别名也可以起到同样的效果,但是我们一般不这样使用)。
<bean id="bookService" name="service" class="com.tsj.service.impl.BookServiceImpl" scope="prototype">
<property name="bookDao" ref="bookDao"/>
</bean>
bean详解
1、bean的基础配置
格式:<beans>
<bean></bean>
</beans>
属性:id:容器根据id获取对应的bean,一个容器id值唯一
class:bean的类型,即配置bean的全路径类名
2、bean的作用范围
名称:scope
功能:控制bean创建的对象是否单例(多次创建是否是同一个对象)
singleton:单列
prototypr:非单列
<bean id="BookService" class="com.tsj.service.impl.BookServiceImpl" scope="prototype"/>
为什么Spring创建的对象大多都是单列的?
这是因为Spring所创建的bean主要是复用的对象,即拿一次用一次,这样才会更加节省资源。
3、bean的同名配置
名称:name
功能:定义bean的别名,可以有多个,可以用逗号,分号,空格隔开。
<bean id="BookDao" name="BookDao_test" class="com.tsj.dao.impl.BookDaoImpl"/>
bean实列化的三种方法
bean的本质:bean是一个对象,创建对象通过无参数的构造方法创建。
方法一:通过可访问的无参数构造方法在实现类中创建对象
其实写不写构造方法是一样的,如果你不写虚拟机会自动提供。
无参构造方法如果不存在,将会抛出BeanCreationException。
//创建构造方法
public BookDaoImpl(){
System.out.println("book dao constructor is running");
}
方法二:静态工厂创建对象
创建工厂返回对象,可以提前做出一些配置,比如说sout
public class OrderDaoFactory {
//通过类名调用静态方法
public static OrderDao getOrderDao(){
System.out.println("factory is setting up");
//通过工厂返回方法创建一个对象
return new OrderDaoImpl();
}
}
配置文件
<!--方法二:使用静态工厂实例化bean-->
<!--因为我们想要调用工厂的方法返回对象,所以我们需要设置factory-method-->
<bean id="orderDao" class="com.tsj.dao.factory.OrderDaoFactory" factory-method="getOrderDao"/>
主页app
public class APP {
public static void main(String[] args) {
ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
//5、获取bean
//此处利用了接口多态,即编辑看左,运行看右边,创建的对象实际是实现类对象,但是类型是接口(向上转换)
OrderDao OrderDao=(OrderDao) act.getBean("orderDao");
//调用了子类中重写的方法,且向上转换只能调用子类重写的方法
OrderDao.save();
}
}
方法三:非静态工厂创建对象
public class UserFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
第一行的UserFactory实际上并没有意义,仅仅作为第二个bean的变量存在。
第二个bean中的方法名每次都不固定,所以这种方法并不实用。
<bean id="UserFactory" class="com.tsj.dao.factory.UserFactory" />
<bean id="UerDao" factory-method="getUserDao" factory-bean="UserFactory"/>
方法四:方法三的改良
public class UserFactoryBean implements FactoryBean<UserDao> {
//代替原始实列中创建对象的方法
@Override
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
//对象的返回值是什么类型
@Override
public Class<?> getObjectType() {
return UserDao.class;
}
//是否为单列对象
@Override
public boolean isSingleton(){
return true;
}
}
这里的对象造出的不是FactoryBean的对象,这里造出来的是Object对象。
<bean id="userdao" class="com.tsj.dao.factory.UserFactoryBean"/>
创建对象页面
public static void main(String[] args) {
UserFactoryBean userFactoryBean = new UserFactoryBean();
try {
UserDao object = userFactoryBean.getObject();
object.save();
} catch (Exception e) {
e.printStackTrace();
}
}
管理第三方bean(案例)
Bean的生命周期
生命周期:从创建到销毁的完整过程
bean生命周期:bean从创建到销毁的整体过程
bean生命周期控制:bean创建后到销毁前做的一些事情
初始化容器
1、创建对象(内存分配)
2、执行构造方法
3、执行属性注入(set操作)
4、执行bean初始化方法
使用bean
1、执行业务操作
关闭/销毁容器
1、执行bean销毁方法
2、注意:一般情况下虚拟机运行结束会自动关闭,来不及执行销毁方法,我们可以手动关闭容器。
方法一:
将Ioc容器对象改变成其子类,以调用子类方法
ClassPathXmlApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
act.close();
方法二:
关闭流
ClassPathXmlApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
act.registerShutdownHook();
bean生命周期的两种控制方法
方法一:通过提供方法,并且在配置文件中配置
//表示bean初始化的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前的操作
public void destroy(){
System.out.println("destory....");
}
<bean id="bookDao" name="BookDao_test" class="com.tsj.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
方法二:通过实现接口的方式
实现InitializingBean, DisposableBean这两个接口
public class BookServiceImpl implements BookService , InitializingBean, DisposableBean {
//5、去除new
private BookDao bookDao;
@Override
public void save() {
System.out.println("BookServiceImpl is saving");
bookDao.save();
}
//6.提供对应的set方法
//set方法是容器在调用,谁要创建对象谁调用
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void destroy() throws Exception {
System.out.println("service destory");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}