Spirng是什么?
大佬讲解点击急用
spirng是轻量级开源的j2ee框架 是一个容器框架,用来装javabean(java对象) 她不仅是容器框架还是中间层框架 实际还是利用装JavaBean aop这个功能 连接其他框架 structs和hibenate粘在一起使用 因为spring IOC帮我们造出对象 而不用我们自己去new 所以他能帮我们融合其他框架的对象 而不用沃尔玛呢一个个造出来
Spring发展到今天已经形成了一种开发的生态圈,Spring提供了若干个项目,每个项目用于完成特定的功能。
Spring已形成了完整的生态圈,也就是说我们可以完全使用Spring技术完成整个项目的构建、设计与开发。
Spring有若干个项目,可以根据需要自行选择,把这些个项目组合起来,起了一个名称叫全家桶,如下图所示
说明:
图中的图标都代表什么含义,可以进入https://spring.io/projects
网站进行对比查看。
这些技术并不是所有的都需要学习,额外需要重点关注Spring Framework
、SpringBoot
和SpringCloud
:
其他所有技术依赖他执行底层框架设计框架所有东西放在上面运行
除了上面的这三个技术外,还有很多其他的技术,也比较流行,如SpringData,SpringSecurity等,这些都可以被应用在我们的项目中。我们今天所学习的Spring其实指的是Spring Framework。
Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基。
Spring Framework的发展也经历了很多版本的变更,每个版本都有相应的调整 这里我们才有SpringFramework4.0技术
(1)核心层
Core Container:核心容器,这个模块是Spring最核心的模块,其他的都需要依赖该模块 对于容器而言就是装东西 java程序就一种东西可以装 就是对象 Spring就是用来管对象
(2)AOP层 aop依赖核心容器执行core container
aop是教你程序应该如何做
它是真正实现了aop
(3)数据层
(4)Web层
(5)Test层
介绍完Spring的体系结构后,从中我们可以得出对于Spring的学习主要包含四部分内容,分别是:
要想解答这个问题,就需要先分析下目前咱们代码在编写过程中遇到的问题:
(1)业务层需要调用数据层的方法,就需要在业务层new数据层的对象
(2)如果数据层的实现类发生变化,那么业务层的代码也需要跟着改变,发生变更后,都需要进行编译打包和重部署
(3)所以,现在代码在编写的过程中存在的问题是:耦合度偏高
针对这个问题,该如何解决呢?
我们就想,如果能把框中的内容给去掉,不就可以降低依赖了么,但是又会引入新的问题,去掉以后程序能运行么?
答案肯定是不行,因为bookDao没有赋值为Null,强行运行就会出空指针异常。
所以现在的问题就是,业务层不想new对象,运行的时候又需要这个对象,该咋办呢?
针对这个问题,Spring就提出了一个解决方案:
使用对象时,在程序中不要主动使用new产生对象,转换为由"外部"提供对象
这种实现思就是Spring的一个核心概念
原来是new出来的 现在不能new的 来个ioc容器 把对象放入ioc容器中。
由ioc容器帮你创建对象 对象由ioc容器提供 dao对象bookdao可以放入 bookserviceimp也能放入啊 IOC容器可以管理大量对象创建和初始化 你对象不用自己造 我帮你造,我造给你的对象叫bean对象 我给你
现在我们程序运行需要Service对象 IOC容器直接调用Service对象 你把程序运行起来看看 这个程序有问题 你的service方法需要dao对象调用的方法 而你的save方法需要dao对象方法才能运行 你运行还是报错 IOC看到你的Service对象依赖dao对象运行 巧了 这两对象都在ioc容器中 所以ioc容器把这活给你干了 也就是service和dao对象的依赖关系帮你干了 也就是绑定上
也就是
你现在要的dao对象直接给到你 这样你就能直接运行了 这种思想叫IDI 依赖注入
容器中如果bean与bean之间存在依赖关系 则IOC容器自动帮你绑定好 绑定关系的过程叫依赖注入
(1)什么是控制反转呢?
new
的别人[外部]
来创建对象别人[外部]
就反转控制了数据层对象的创建权(2)Spring和IOC之间的关系是什么呢?
别人[外部]
指的就是Spring的IOC容器由主动new出对象转换为IOC容器提供对象
(3)IOC容器的作用以及内部存放的是什么?
(4)当IOC容器中创建好service和dao对象后,程序能正确执行么?
1)什么是依赖注入呢?
new
的别人[外部其实指的就是IOC容器]
来给注入进来(2)IOC容器中哪些bean之间要建立依赖关系呢?
这个需要程序员根据业务需求提前建立好关系,如业务层需要依赖数据层,service就要和dao建立依赖关系
介绍完Spring的IOC和DI的概念后,我们会发现这两个概念的最终目标就是:充分解耦,具体实现靠:
使用IOC容器管理bean(IOC)
在IOC容器内将有依赖关系的bean进行关系绑定(DI)
最终结果为:使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系.
这节比较重要,重点要理解什么是IOC/DI思想
、什么是IOC容器
和什么是Bean
:
(1)什么IOC/DI思想?
(2)什么是IOC容器?
Spring创建了一个容器用来存放所创建的对象,这个容器就叫IOC容器
(3)什么是Bean?
容器中所存放的一个个对象就叫Bean或Bean对象
idea中source目录和resource目录的作用 resource添加依赖 source主要用来保存java文件且打包后汇编编译成class文件 而resource则是直接复制不会变成class文件
(1)Spring是使用容器来管理bean对象的,那么管什么?
(2)如何将被管理的对象告知IOC容器?
(3)被管理的对象交给IOC容器,要想从容器中获取对象,就先得思考如何获取到IOC容器?
(4)IOC容器得到后,如何从容器中获取bean?
(5)使用Spring导入哪些坐标?
用别人的东西,就需要在pom.xml添加对应的依赖
applicationContext.xml 文件配置
项目结构
*
BookDaoImpl
public class BookDaoImpl implements BookDao {public void save() {System.out.println("book dao save ...");}
}
BookServiceImpl
public class BookServiceImpl implements BookService {private BookDao bookDao = new BookDaoImpl();public void save() {System.out.println("book service save ...");bookDao.save();}
}
App2.java
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App2 {public static void main(String[] args) {
// 步骤6:获取IOC容器 创建 ApplicationContext接口的实现类 括号内填写配置文件路径配置对应的容器 getBean 方法的参数要和 spring-config.xml 配置文件中的 id 对应ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 步骤7:从容器中获取对象进行方法调用 获取bean
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// bookDao.save();BookService bookService = (BookService) ctx.getBean("bookService");bookService.save();}
}
book service save …
book dao save …
(1)要想实现依赖注入,必须要基于IOC管理Bean
(2)Service中使用new形式创建的Dao对象是否保留?
(3)Service中需要的Dao对象如何进入到Service中?
(4)Service与Dao间的关系如何描述?
需求:基于IOC入门案例,在BookServiceImpl类中删除new对象的方式,使用Spring的DI完成Dao层的注入
1.删除业务层中使用new的方式创建的dao对象
2.在业务层提供BookDao的setter方法
3.在配置文件中添加依赖注入的配置
4.运行程序调用方法
在BookServiceImpl类中,删除业务层中使用new的方式创建的dao对象
BookServiceimpl.java
public class BookServiceImpl implements BookService {//5.删除业务层中使用new的方法创建的dao对象private BookDao bookDao;public void save() {System.out.println("book service save ...");bookDao.save();}//6.提供对应的set方法 这个方法是谁调用的?重点 这个set方法是容器执行的public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}
}
在BookServiceImpl类中,为BookDao提供setter方法
public class BookServiceImpl implements BookService {//5.删除业务层中使用new的方法创建的dao对象private BookDao bookDao;public void save() {System.out.println("book service save ...");bookDao.save();}//6.提供对应的set方法 这个方法是谁调用的?重点 这个set方法是容器执行的public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}
}
在配置文件中添加依赖注入的配置
注意:配置中的两个bookDao的含义是不一样的
bookDao
的作用是让Spring的IOC容器在获取到名称后,将首字母大写,前面加set找对应的setBookDao()
方法进行对象注入bookDao
的作用是让Spring能在IOC容器中找到id为bookDao
的Bean对象给bookService
进行注入
这其中需要大家重点掌握的是:bean标签的id和class属性的使用。
思考:
BookDao
的类全名呢?答案肯定是不行,因为接口是没办法创建对象的。
环境准备好后,接下来就可以在这个环境的基础上来学习下bean的别名配置,首先来看下别名的配置说明:
打开spring的配置文件applicationContext.xml
public class AppForName {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");//此处根据bean标签的id属性和name属性的任意一个值来获取bean对象BookService bookService = (BookService) ctx.getBean("service4");bookService.save();}
运行结果
关于bean的作用范围是bean属性配置的一个重点内容。
看到这个作用范围,我们就得思考bean的作用范围是来控制bean哪块内容的?
我们先来看下`bean作用范围的配置属性
同一个bean获取两次,将对象打印到控制台,看打印出的地址值是否一致。
* public class AppForScope {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookDao bookDao1 = (BookDao) ctx.getBean("bookDao1");BookDao bookDao2 = (BookDao) ctx.getBean("bookDao1");System.out.println(bookDao1);System.out.println(bookDao2);// 这里是运行结果//com.itheima.dao.impl.BookDaoImpl@25bbe1b6//com.itheima.dao.impl.BookDaoImpl@25bbe1b6 也就是说Spring默认的是单例模式// com.itheima.dao.impl.BookDaoImpl@25bbe1b6
// com.itheima.dao.impl.BookDaoImpl@5702b3b1 若applicationContext.xml 中 改为scope="prototype"则不是单例模式创建的是两个对象}
}
获取到结论后,问题就来了,那如果我想创建出来非单例的bean对象,该如何实现呢?
在Spring配置文件中,配置scope属性来实现bean的非单例创建
的scope属性singleton
scope属性默认是singleton 单例模式默认创建一个对象 改为prototype之后每次获取就创建一个新的对象
介绍完scope
属性以后,我们来思考几个问题:
对象已经能交给Spring的IOC容器来创建了,但是容器是如何来创建对象的呢?
就需要研究下bean的实例化过程
,在这块内容中主要解决两部分内容,分别是
构造方法
,静态工厂
和实例工厂
在讲解这三种创建方式之前,我们需要先确认一件事:
bean本质上就是对象,对象在new的时候会使用构造方法完成,那创建bean也是使用构造方法完成的。
基于这个知识点出发,我们来验证spring中bean的三种创建方式,
在上述的环境下,我们来研究下Spring中的第一种bean的创建方式构造方法实例化
:
准备一个BookDao和BookDaoImpl类
public interface BookDao {public void save();
}public class BookDaoImpl implements BookDao {public void save() {System.out.println("book dao save ...");}}
public class AppForInstanceBook {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookDao bookDao = (BookDao) ctx.getBean("bookDao");bookDao.save();}
}
在BookDaoImpl类中添加一个无参构造函数,并打印一句话,方便观察结果。
public class BookDaoImpl implements BookDao {//public BookDaoImpl(int i) { 报错了 spring 创建bean的时候调用的是无参构造方法// System.out.println("book dao constructor is running ....");// }private BookDaoImpl() {System.out.println("book dao constructor is running ....");}public void save() {System.out.println("book dao save ...");}
}
public class BookDaoImpl implements BookDao {private BookDaoImpl(int i) {System.out.println("book dao constructor is running ....");}public void save() {System.out.println("book dao save ...");}}
运行程序,
程序会报错,说明Spring底层使用的是类的无参构造方法。
接下来,我们主要研究下Spring的报错信息来学一学如阅读。
() 引起
,即出现错误的原因没有这样的方法异常
():哪个类的哪个方法没有被找到导致的异常,
()指定是类的构造方法,即该类的无参构造方法如果最后一行错误获取不到错误信息,接下来查看第二层:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.itheima.dao.impl.BookDaoImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.itheima.dao.impl.BookDaoImpl.
()
引发
bean实例化异常
看到这其实错误已经比较明显,给大家个练习,把倒数第三层的错误分析下吧:
Exception in thread “main” org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘bookDao’ defined in class path resource [applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.itheima.dao.impl.BookDaoImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.itheima.dao.impl.BookDaoImpl.
()。
至此,关于Spring的构造方法实例化就已经学习完了,因为每一个类默认都会提供一个无参构造函数,所以其实真正在使用这种方式的时候,我们什么也不需要做。这也是我们以后比较常用的一种方式。
接下来研究Spring中的第二种bean的创建方式静态工厂实例化
:
在讲这种方式之前,我们需要先回顾一个知识点是使用工厂来创建对象的方式:
(1)准备一个OrderDao和OrderDaoImpl类
public interface OrderDao {public void save();
}public class OrderDaoImpl implements OrderDao {public void save() {System.out.println("order dao save ...");}
}
(2)创建一个工厂类OrderDaoFactory并提供一个静态方法
//静态工厂创建对象
public class OrderDaoFactory {public static OrderDao getOrderDao(){return new OrderDaoImpl();}
}
(3)编写AppForInstanceOrder运行类,在类中通过工厂获取对象
public class AppForInstanceOrder {public static void main(String[] args) {//通过静态工厂创建对象OrderDao orderDao = OrderDaoFactory.getOrderDao();orderDao.save();}
}
这就要用到Spring中的静态工厂实例化的知识了,具体实现步骤为:
(1)在spring的配置文件application.properties中添加以下内容:
class:工厂类的类全名
factory-mehod:具体工厂类中创建对象的方法名
对应关系如下图:
(2)在AppForInstanceOrder运行类,使用从IOC容器中获取bean的方法进行运行测试
public class AppForInstanceOrder {public static void main(String[] args) {//通过静态工厂创建对象
// OrderDao orderDao = OrderDaoFactory.getOrderDao(); 个人体会就是调用new ClassPathXmlApplicationContext对象后帮我们创建这个dao对象的 因为调用无参方法就是这样的
// orderDao.save();ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");orderDao.save();}
}
(3)运行后,可以查看到结果
项目结构
接下来继续来研究Spring的第三种bean的创建方式实例工厂实例化
:
项目结构
(1)准备一个UserDao和UserDaoImpl类
public interface UserDao {public void save();
}public class UserDaoImpl implements UserDao {public void save() {System.out.println("user dao save ...");}
}
(2)创建一个工厂类OrderDaoFactory并提供一个普通方法,注意此处和静态工厂的工厂类不一样的地方是方法不是静态方法
public class UserDaoFactory {public UserDao getUserDao(){return new UserDaoImpl();}
}
(3)编写AppForInstanceUser运行类,在类中通过工厂获取对象
public class AppForInstanceUser {public static void main(String[] args) {//创建实例工厂对象UserDaoFactory userDaoFactory = new UserDaoFactory();//通过实例工厂对象创建对象UserDao userDao = userDaoFactory.getUserDao();userDao.save();
}
(4)运行后,可以查看到结果
具体实现步骤为:
(1)在spring的配置文件中添加以下内容:
实例化工厂运行的顺序是:
创建实例化工厂对象,对应的是第一行配置
调用对象中的方法来创建bean,对应的是第二行配置
factory-bean:工厂的实例对象
factory-method:工厂对象中的具体创建对象的方法名,对应关系如下:
factory-mehod:具体工厂类中创建对象的方法名
(2)在AppForInstanceUser运行类,使用从IOC容器中获取bean的方法进行运行测试
public class AppForInstanceUser {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");UserDao userDao = (UserDao) ctx.getBean("userDao");userDao.save();}
}
(3)运行后,可以查看到结果
实例工厂实例化的方式就已经介绍完了,配置的过程还是比较复杂,所以Spring为了简化这种配置方式就提供了一种叫FactoryBean
的方式来简化开发。
具体的使用步骤为:
(1)创建一个UserDaoFactoryBean的类,实现FactoryBean接口,重写接口的方法
public class UserDaoFactoryBean implements FactoryBean {//代替原始实例工厂中创建对象的方法public UserDao getObject() throws Exception {return new UserDaoImpl();}public Class> getObjectType() {return UserDao.class;}//改变工厂默认创建单例的对象方法 默认工厂就是true/*public boolean isSingleton() {return true;}*/
}
(2)在Spring的配置文件中进行配置
方式四:使用FactoryBean实例化Bean
(3)AppForInstanceUser运行类不用做任何修改,直接运行
这种方式在Spring去整合其他框架的时候会被用到,所以这种方式需要大家理解掌握。
查看源码会发现,FactoryBean接口其实会有三个方法,分别是:
方法一:getObject(),被重写后,在方法中进行对象的创建并返回
方法二:getObjectType(),被重写后,主要返回的是被创建类的Class对象
方法三:没有被重写,因为它已经给了默认值,从方法名中可以看出其作用是设置对象是否为单例,默认true,从意思上来看,我们猜想默认应该是单例,如何来验证呢?
思路很简单,就是从容器中获取该对象的多个值,打印到控制台,查看是否为同一个对象。
public class AppForInstanceUser {public static void main(String[] args) {
/* //创建实例工厂对象UserDaoFactory userDaoFactory = new UserDaoFactory();//通过实例工厂对象创建对象UserDao userDao = userDaoFactory.getUserDao();userDao.save();*/ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");UserDao userDao1 = (UserDao) ctx.getBean("userDao");UserDao userDao2 = (UserDao) ctx.getBean("userDao");System.out.println(userDao1);System.out.println(userDao2);// userDao.save();}
}
通过验证,会发现默认是单例,那如果想改成单例具体如何实现?
只需要将isSingleton()方法进行重写,修改返回为false,即可
//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean {//代替原始实例工厂中创建对象的方法public UserDao getObject() throws Exception {return new UserDaoImpl();}public Class> getObjectType() {return UserDao.class;}public boolean isSingleton() {return false;}
}
从结果中可以看出现在已经是非单例了,但是一般情况下我们都会采用单例,也就是采用默认即可。所以isSingleton()方法一般不需要进行重写。
(1)bean是如何创建的呢?
构造方法
(2)Spring的IOC实例化对象的三种方式分别是:
这些方式中,重点掌握构造方法
和FactoryBean
即可。
需要注意的一点是,构造方法在类中默认会提供,但是如果重写了构造方法,默认的就会消失,在使用的过程中需要注意,如果需要重写构造方法,最好把默认的构造方法也重写下。