SSM框架
第一章 初识Spring
1.1SpringFrameWork 系统架构
Spring FrameWork是Spring生态圈中最基础的项目,是其他项目的根基
1.2核心概念
未使用Spring前
代码书写现状 :代码的耦合度偏高
解决方案:使用对象时,在程序中不要主动使用new产生对象,转换为由外部(Ioc容器)提供对象
使用Spring后
IoC (Inversion of Control)控制反转:对象的创建控制权由程序转移到外部,这种思想称为控制反转。
Spring技术对IoC思想进行了实现
1.Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的外部、
2.IoC容器负责对象的创建、初始化等一系列工作,被创建或者被管理的对象在IoC容器中统称为Bean(在Java中的对象在IoC中被称 为Bean)
DI(Dependency Injection)依赖注入
在容器中建立Bean与Bean之间的依赖关系的过程,称为依赖注入
目标:充分解耦
1.使用IoC容器管理Bean(IoC)
2.在IoC容器内将有依赖关系的Bean进行关系绑定(DI)
最终效果
使用对象时不仅可以直接从IoC容器中获取,并且获取的Bean已经绑定了所有的依赖关系
1.3 IoC的初步使用
1.在pom文件中引入Spring-Context坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
2.在resources文件夹下创建applicationContext的xml文件
其中Bean中id为自行设置的名称,而class对应的是需要被IoC容器管理的类(不能是接口,应为接口不可以被创建对象)
<?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-Context坐标-->
<bean id="write" class="com.SharkyCake.dao.Impl.writeImpl">
</bean>
</beans>
3和4.获取IoC容器以及获取所需的Bean
//3.获取IoC容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//4.获取Bean
writeImpl write = (writeImpl)ctx.getBean("write");
write.writeSentence();
1.4 DI入门案例
思路:
1.基于IoC管理Bean
2.Service中使用new形式创建的Dao对象是否保留(否)
3.Service中需要的Dao对象如何进入到Service中?(提供方发)
4.Service与Dao之间的关系如何描述?(配置)
5.将业务层中new出来dao的代码删除
6.创建对应的setter方法
package com.SharkyCake.service.Impl;
import com.SharkyCake.dao.Impl.writeImpl;
import com.SharkyCake.service.writeService;
public class writeServiceImpl implements writeService {
//5.删除业务层中使用new的方式创建的dao对象
private writeImpl writeDao /*= new writeImpl()*/;
@Override
public void writeServiceSentence() {
writeDao.writeSentence();
System.out.println("Write Service Sentence......");
}
//6.提供对应的set方法
public void setWriteDao(writeImpl writeDao){
this.writeDao = writeDao;
};
}
7.在applicationContext中修改对应属性
<!--7.配置service与dao之间的关系 -->
<!--property表示配置当前Bean的属性-->
<!--name表示配置哪一个具体的属性(此处的属性值为对应writeService Bean中的属性值)
ref属性表示name参照的是哪一个Bean-->
<bean id = "writeService" class="com.SharkyCake.service.Impl.writeServiceImpl">
<property name="writeDao" ref="write"/>
</bean>
第二章 Bean
2.1 Bean的别名
类别 | 描述 |
---|---|
名称 | name |
类型 | 属性 |
所属 | bean标签 |
功能 | 定义Bean 的别名,可以定义多个,使用逗号(,)分号(;)空格( )分割 |
范例 |
注意事项
获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常
NoSuchBeanDefinitionExceptionNoSuchBeanDefinitionException: No bean named 'bookServiceImpl' available
2.2 Bean的作用范围
类型 | 描述 |
---|---|
名称 | scope |
类型 | 属性 |
所属 | bean标签 |
功能 | 定义bean的作用范围,可选范围如下 singleton:单例(默认)prototype:非单例 |
范例 |
为什么bean默认设置为单例?
适合交给容器进行管理的bean
- 表现层对象
- 业务层对象
- 数据层对象
- 工具对象
不适合交给容器进行管理的Bean
- 封装实体的域对象
2.2Bean的实例化
实例化Bean的三种方式——构造方法(常用)
即在Bean对应的类中创建可访问的(public和private都可以使用)无参构造方法(或者不写类会自动创建无参构造)
人如果无参构造方法不存在,将会抛出异常BeanCreationException
实例化Bean的三种方式——静态工厂(了解)
首先在factory包下创建对应的factory工厂类
import com.SharkyCake.dao.Impl.writeImpl;
public class writeDaoFactory {
//创建工厂对象
public static writeImpl getWriteDao(){
return new writeImpl();
}
}
在Bean中创建所需的Dao对象 与普通方法不同的是
class属性要改为对应使用的工厂类
factory-method:对应所需的创建实体类的方法
<bean id="writeDao" class="com.SharkyCake.factory.writeDaoFactory" factory-method="getWriteDao"/>
实例化Bean的三种方式——实例工厂(了解)
实例工厂与静态工厂不同的地方就在于,静态工厂他对应的工厂对象不需要创建对象即可获取对应Dao对象,但是实例工厂就需要创建 实例的工厂对象来获取对应的Dao对象,以至于需要创建Factory的Bean对象(冗余)
import com.SharkyCake.dao.Impl.writeImpl;
public class writeFactory {
public writeImpl getwriteImpl(){
return new writeImpl();
}
}
<!--3.通过实例工厂创建bean-->
<!--1先创建对应的实例工厂对象-->
<bean id="writeDaoFactory" class="com.SharkyCake.factory.writeFactory"/>
<!--通过实例工厂对象来获取对应的Dao-->
<bean id="writeDao" factory-method="getwriteImpl" factory-bean="writeDaoFactory"/>
实例化Bean的第四种方式——FactoryBean(重点)
此时创建工厂对象要实现FactoryBean这个接口,而且这个接口还是个泛型,需要填写所需返回的Dao对象
import com.SharkyCake.dao.Impl.writeImpl;
import com.SharkyCake.dao.write;
import org.springframework.beans.factory.FactoryBean;
public class writeFactoryBean implements FactoryBean<writeImpl> {
/**
* 返回所需的Dao对象
* @return
* @throws Exception
*/
@Override
public writeImpl getObject() throws Exception {
return new writeImpl();
}
/**
* 返回对应的类字节码
* @return
*/
@Override
public Class<?> getObjectType() {
return writeImpl.class;
}
/**
* 设置bean 是否为单例模式 默认为单例模式
* @return
*/
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
<!--方法四:通过FactoryBean创建对象-->
<bean id="writeImpl" class="com.SharkyCake.factory.writeFactoryBean"/>
2.3 bean的生命周期
bean的创建以及销毁
第一种方式,在对应class中创建Init和Destory方法海表Bean的创建以及销毁时要进行的操作
package com.sharkyCake.service.Impl;
import com.sharkyCake.service.bookService;
public class bookServiceImpl implements bookService {
public void init(){
System.out.println("init.....");
}
public void readBook(){
System.out.println("Read.....");
}
public void destroy(){
System.out.println("destroy....");
}
}
并且在配置文件中使用 init_method 和 destroy-method 来绑定对应的init和destroy方法
<bean id="Book" class="com.sharkyCake.service.Impl.bookServiceImpl" init-method="init" destroy-method="destroy"/>
要注意:destroy方法不会自动执行,在JVM虚拟机退出时不会销毁bean,
执行bean的销毁操作需要IoC容器关闭时才会进行销毁(此方法暴力关闭)
或者注册一个钩子函数,不论在哪一出代码都可以执行
import com.sharkyCake.service.Impl.bookServiceImpl;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class springTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
bookServiceImpl book = (bookServiceImpl)context.getBean("Book");
book.readBook();
//context.close();
context.registerShutdownHook();
}
}
第二种方法(了解)在对应得class中继承InitializingBean, DisposableBean两种接口并实现对应的方法,即可不用再配置文件中绑定
init-method 和 destroy-method方法
bean的销毁时机
容器关闭前触发bean的销毁
关闭容器方式:
1.手工关闭容器 ConfigurationApllicationContext接口close()操作
2.注册关闭钩子,在虚拟机退出前先关闭容器再推出虚拟机
ConfigurationApplicationContext接口registerShutDownHook() 操作
第三章 依赖注入
2.1 setter注入
2.1.1普通数据类型注入
setter注入的意思就是再class中有对应得属性值的set方法,并且在配置文件中创建对应的属性来对bean中的值进行控制:
例子如下所示:
public class bookDaoImpl {
private int bookNum;
private String BookName;
public void readByDao (){
System.out.println("readByDao....."+bookNum+BookName);
}
public void setBookNum(int bookNum) {
this.bookNum = bookNum;
}
public void setBookName(String bookName) {
BookName = bookName;
}
}
<bean id="BookDao" class="com.sharkyCake.dao.Impl.bookDaoImpl">
value属性的意思为set前面的某一个普通数据类型所设的值
<property name="bookName" value="数据结构与算法"/>
<property name="bookNum" value="100"/>
</bean>
2.1.2引用类型注入
在一个类中如果引用了其他类,并且创建了对象,则要在Bean中同样加入property属性并且在property中的ref写出所引用的类的Bean创建时的Name值
要注意这里的ref指代的是private bookDaoImpl bookDao;中的bookDao而不是set方法中的形参
例如:
import com.sharkyCake.dao.Impl.bookDaoImpl;
import com.sharkyCake.dao.bookDao;
import com.sharkyCake.service.bookService;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class bookServiceImpl implements bookService, InitializingBean, DisposableBean {
private bookDaoImpl bookDao;
public void setBookDao(bookDaoImpl bookDao) {
this.bookDao = bookDao;
}
public void init(){
System.out.println("init.....");
}
public void readBook(){
bookDao.readByDao();
System.out.println("Read.....");
}
public void destroy(){
System.out.println("destroy....");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Init through InitializingBean");
}
/*@Override
public void destroy() throws Exception {
}*/
<bean id="BookDao" class="com.sharkyCake.dao.Impl.bookDaoImpl">
<property name="bookName" value="数据结构与算法"/>
<property name="bookNum" value="100"/>
</bean>
<bean id="Book" class="com.sharkyCake.service.Impl.bookServiceImpl" init-method="init" destroy-method="destroy">
在这里要注意 尽管在上面的实现类中可以将BookDaoImpl创建为接口类型的,但是在这里的ref就会报错
要求bookDao的对象类型和后面ref的对象类型一致
<property name="bookDao" ref="BookDao"/>
</bean>
2.2 构造器注入
构造器注入与setter注入基本相同,需要改变的地方就是将class中的set方法修改变成构建对象的方法,并且在配置文件中修改property为constructor-arg 此时的name指的是java文件中constructor方法的形式参数的名称。
<bean id="BookDao" class="com.sharkyCake.dao.Impl.bookDaoImpl">
<constructor-arg name="bookName" value="fuk"/>
<constructor-arg name="bookNum" value="1"/>
</bean>
public class bookDaoImpl {
private int bookNum;
private String BookName;
public bookDaoImpl(int bookNum, String bookName) {
this.bookNum = bookNum;
BookName = bookName;
}
public void readByDao (){
System.out.println("readByDao....."+bookNum+BookName);
}
public void setBookNum(int bookNum) {
this.bookNum = bookNum;
}
public void setBookName(String bookName) {
BookName = bookName;
}
}
但是这种方法属于紧耦合,形参名字改变导致bean中字段也要改变
2.3 依赖注入方式的选择
1.强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
2.可选以来使用setter注入进行,灵活性强
3.Spring框架倡导使用构造器,第三方框架大多数采用构造器注入的形式进行数据初始化,相对严谨
4.如果有必要可以两者同时使用,使用构造器完成强制依赖的注入,使用setter注入完成可选依赖的注入
5.实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
6.自己开发的模块建议使用setter注入
2.4 依赖自动装配
如何使用自动装配
配置使用bean标签autowire属性设置自动装配的类型
<bean id="BookDao" class="com.sharkyCake.dao.Impl.bookDaoImpl" auto-wire="byType">
<constructor-arg name="bookName" value="fuk"/>
<constructor-arg name="bookNum" value="1"/>
<property name="bookName" value="数据结构与算法"/>
<property name="bookNum" value="100"/>
</bean>
依赖自动装配的特征(也需要提供set方法)
- 自动装配用于引用类型依赖注入,不能对简单类型进行进行操作。
- 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一(即会按照bean中引用的对象类型来寻找对应的bean),推荐使用
- 试图用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
- 自动装配优先级低于setter与构造器注入,同时出现是自动装配配置失效
2.5 集合注入
集合注入的几种形式array,list,map,properties
首先定义这几个集合类型
private int[] a;
private List<String> list;
private Map<String,String> map;
private Properties properties;
public void setA(int[] a) {
this.a = a;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
其次在配置文件中进行配置
<property name="a">
<array>
<value>1</value>
<value>2</value>
<value>3</value>
</array>
</property>
<property name="list">
<list>
<value>w</value>
<value>e</value>
<value>e</value>
</list>
</property>
<property name="map">
<map>
<entry key="1" value="2"/>
<entry key="1" value="2"/>
<entry key="1" value="2"/>
</map>
</property>
<property name="properties">
<props>
<prop key="1">2</prop>
<prop key="1">2</prop>
<prop key="1">2</prop>
</props>
</property>
2.6 加载properties配置信息
如何加载properties文件的信息
首先要修改appliactionContext文件的头信息,创建出一个Context域来存放读取的数据
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
其次读取文件即可,读取出来的文件使用${}通配符获取数据
<context:property-placeholder location="jdbc.properties"/>
<!--不加载系统属性-->
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
<!--加载多个properties文件-->
<context:property-placeholder location="jdbc.properties,applicationContext.xml"/>
<!--加载所有properties文件-->
<context:property-placeholder location="*.properties"/>
<!--加载properties文件标准格式-->
<context:property-placeholder location="classpath:*.properties"/>
<!--从类路径或者jar包中搜索并加载properties文件-->
<context:property-placeholder location="classpath*:*.properties"/>
<bean name="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
2.7 容器
容器相关
- BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象是,加载的bean延迟加载
- ApplicationContext接口时Spring容器的核心接口,初始化bean时立即加载
- ApplicationContext接口提供基础的bean操作相关方法,通过其他接口拓展其功能
- ApplicationContext接口常用初始化类
-
- ClassPathXmlApplicationContext
- FilesystemXmlApplicationContext
bean相关
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Oy2YRmDc-1657452083855)(C:\Users\86150\Desktop\笔记\img_SSM\image-20220710174021346.png)]
依赖注入相关
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c396D2Z0-1657452083856)(C:\Users\86150\Desktop\笔记\img_SSM\image-20220710174418232.png)]
第四章 注解开发
4.1 注解开发bean
在使用注解开发bean时,将注解直接写在对应的类文件的头部
使用**@Component()**注解,括号内可以写String类型的名字,写的名字对应就是在applicationContext中的id
括号中不写内容也可,但在getBean是就要使用Class名来获取对应的Bean
例子:
1.首先要修改Spring的头文件(创建Context域)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
2.在要创建Bean的类中使用注解开发
3.在核心配置文件中通过组件扫描加载bean
@Component("BookDao")
public class Impl implements bookService {
public void bookRead(){
System.out.println("readBook......");
}
}
扫描包
<context:component-scan base-package="com.sharkyCake" />
- Spring还提供@Component注解的三个衍生注解
- @Controller:用于表现层bean定义
- @Service:用于业务层bean定义
- @Repository :用于数据层bean定义