spring两大核心技术 IoC AOP
Spring可以整合目前市面上大部分的框架
MyBatis
MyBatis-plus
Struts
Struts2
Hibernate
Spring官网展示了Spring包含的技术,发展到今天,Spring已经形成了一种开发的生态圈,Spring提供的若干个项目,每个项目用于完成特定的功能。
Spring Framework:作为底层架构,运行的基础
Spring Boot:简化开发,加快开发速度
Spring Cloud:分布开发工具
Spring发展史:Spring1.0 to Spring5.0
Spring4.0架构图
IoC(Inversion of Control:控制反转)
在目前的代码书写中,业务层和数据层的耦合度偏高
数据层定义类(BookDaoImpl)继承自接口(BookDao),类中定义了实现的方法(save), 业务层实例化类的一个对象(bookdao),对象调用方法。
但是如果类中实现方法改变了(BookDaoImpl),这时就需要对业务层代码进行改变,此时需要重新部署,编译。
IoC的思想是:使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象的控制权由程序转移到外部,此思想称为控制反转
Spring技术对IoC进行了实现
IoC,IoC容器,Bean,DI(Dependency Injection:依赖注入)
IoC实现的目标是充分解耦
IoC容器和DI是实现手段
IoC实现的效果是:使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系
1.导入Spring的坐标Spring-context,对应版本,pom.xml文件中导入dependency
2.创建Spring配置文件,在resource文件夹里
3.获取IoC容器,获取Bean
5.删除实现类使用new方法生成的对象
6.这时就没有对象了,使用setter方法来创建一个对象
7. 在配置文件中配置Bean的关系
name和ref虽然一样,但是两者表示意义不同,name表示现在实现类的属性的名称,作用是去找到bookDao的属性,并且调用setter方法进行对象注入,ref表示在配置文件中的Bean的id,作用是是让Spring在IoC容器中找到id是bookDao的bean对象,给bookService注入bookDao对象
bean的id必须是唯一的
获取bean可以通过id,name来获取
IoC容器中默认对象是单例的,同一个bean创造出来的对象是同一个地址,是相同的。
如果想要创建一个非单例的对象,就需要修改bean的scope属性
scope属性默认为singleton(单例)
设置属性为prototype后,一个bean创造出来的两个对象就是两个对象了。
bean的这种单例属性适合需要复用的对象
Spring底层启用的是反射,即使类中的构造方法是private属性的,也可以访问使用。注意构造方法必须是无参的,否则Spring在访问方法时会出现错误。这种方法很常用
工厂类:使用工厂来创建对象,创建一个工厂类,并定义一个静态方法
- //静态工厂创建对象
- public class OrderDaoFactory {
- public static OrderDao getOrderDao(){
- return new OrderDaoImpl();
- }
- }
使用静态工厂创建一个对象
- public class AppForInstanceOrder {
- public static void main(String[] args) {
- //通过静态工厂创建对象
- OrderDao orderDao = OrderDaoFactory.getOrderDao();
- orderDao.save();
- }
- }
在Spring中怎么使用静态工厂呢
在Spring配置文件中加入以下内容,如果不加入factory-method,那么只能产生一个factory对象,不能产生我们想要的orderDao对象
class:工厂类的类全名 factory-mehod:具体工厂类中创建对象的方法名
这种方法可以在工厂里面添加其他的业务操作,这些操作用工厂类方式比较方便,如果只是我们自己new一个新对象出来,只能new一个对象,无法执行业务操作。静态工厂方法主要在以前的老系统操作常见,目前了解即可
与静态工厂类似,创建一个工厂类,但是提供一个实例方法,
- public class UserDaoFactory {
- public UserDao getUserDao(){
- return new UserDaoImpl();
- }
- }
创建一个运行类,在类中创建一个实例工厂对象,再通过实例工厂对象来创建一个对象
- public class AppForInstanceUser {
- public static void main(String[] args) {
- //创建实例工厂对象
- UserDaoFactory userDaoFactory = new UserDaoFactory();
- //通过实例工厂对象创建对象
- UserDao userDao = userDaoFactory.getUserDao();
- userDao.save();
- }
实例工厂创建类怎么通过Spring来实现呢
在Spring配置文件中加入以下代码
在运行类中,运行以下代码,会从IoC容器中取出对应bean
- public class AppForInstanceUser {
- public static void main(String[] args) {
- ApplicationContext ctx = new
- ClassPathXmlApplicationContext("applicationContext.xml");
- UserDao userDao = (UserDao) ctx.getBean("userDao"); //在IoC中找到id为userDao的bean,接着Spring管理实例化工厂开始运行
- userDao.save();
- }
- }
Spring管理实例化工厂还是比较麻烦
所以Spring为了简化这种配置方式就提供了一种叫FactoryBean的方式来简化开发
- //创建一个类实现FactoryBean接口
- public class UserDaoFactoryBean implements FactoryBean<UserDao> {
- //代替原始实例工厂中创建对象的方法
- public UserDao getObject() throws Exception {
- return new UserDaoImpl();
- }
- //返回所创建类的Class对象
- public Class> getObjectType() {
- return UserDao.class;
- }
- }
和实例工厂的方法看着类似,但是在Spring配置文件中可以看出两者的不同,使用FactoryBean方式的配置代码简单很多
FactoryBean接口中有三个方法
- T getObject() throws Exception; //:getObject(),被重写后,在方法中进行对象的创建并返回
- Class> getObjectType(); //getObjectType(),被重写后,主要返回的是被创建类的Class对象
-
- default boolean isSingleton() {
- return true;
- }
- //没有被重写,因为它已经给了默认值,从方法名中可以看出其作用是设置对象是否为单例,默认true为单例
这种方法的应用性很广。很实用
创建bean之后,为bean添加生命周期的控制方法如下
bean创建之后,想要添加内容,比如用来初始化需要用到资源
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("destory...");
- }
- }
在配置文件中添加生命周期
id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" - destroy-method="destory"/>
运行运行文件后,结果如下
从结果中可以看出,init方法执行了,但是destroy方法却未执行,这是为什么呢?
Spring的IOC容器是运行在JVM中 运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方法执行,main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了 所以没有调用对应的destroy方法
提供以下方法
close关闭容器
ApplicationContext中没有close方法
需要将ApplicationContext更换成ClassPathXmlApplicationContext
- ClassPathXmlApplicationContext ctx = new
- ClassPathXmlApplicationContext("applicationContext.xml");
再调用ctx的close()方法
ctx.close()
此时再运行文件,destory中的内容可以被运行
注册钩子关闭容器
在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器
调用ctx的registerShutdownHook()方法
两种方法的作用相同,都可以关闭容器
不同点:close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭。
但在类中添加初始化和销毁代码,还要再Spring中添加配置,比较麻烦,所以Spring中自带了两个接口来实现以上操作,不需要再配置init和destory配置
在BookServiceImpl类中添加两个接口
- public class BookServiceImpl implements BookService,InitializingBean,
- DisposableBean
- //两个接口的实现方法
- @Override
- public void destroy() throws Exception {
- System.out.println("Service destory");
- }
-
- @Override
- public void afterPropertiesSet() throws Exception {
- System.out.println("Service init");
- }
运行之后,