SSM复习总结-Spring
Spring介绍
Spring是一个
轻量级的控制反转和面向切面的容器
框架,用来解决企业项目开发的复杂问题-解耦
- 轻量级:体积小,对代码没有入侵性
- 控制反转:
IOC(Inverse of Control)
,把创建对象的工作交由Spring完成,Spring在创建对象的时候同时可以完成对象属性赋值(DI) - 面向切面:
AOP(Aspect Oriented Programming)
面向切面编程,可以在不改变原有业务逻辑的情况下实现对业务的增强 - 容器:实例的容器,管理创建的对象
Spring架构
- Spring Boot 工具框架
- Spring Framework (Spring IOC AOP)
- Spring Cloud 微服务架构
- Spring Data (Spring提供的数据访问的客户端数据库 jpa redis)
- Spring Security 安全框架
Core Container
Spring容器组件,用于完成实例的创建和管理
- core
- beans 实例管理
- context Spring上下文
AOP、Aspects
Spring AOP组件,实现面向切面编程
- aop
- aspects
web
Spring web组件实际指的是SpringMVC框架,实现web项目的实际控制
- web(Spring对web项目的支持)
- webmvc(SpringMVC)
Data Access
- Spring 数据访问组件,也是基于JDBC封装的持久层框架(即使没有mybatis,Spring也可以完成持久化操作)
- Transactions
Test
Spring的单元测试组件,提供了Spring环境下的单元测试支持
- test
Spring IOC
Spring IOC容器组件,可以完成对象的创建、对象属性赋值、对象管理
Spring框架部署(IOC)
创建Maven工程
- java
- Web
Spring IOC使用
添加springIOC依赖
- core
- beans
- aop
- expression
context
(传递依赖core beans,aop,expression的jar包)
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.19.RELEASE</version>
</dependency>
</dependencies>
创建Spring配置文件
通过配置文件告诉
Spring容器创建什么对象,给对象属性赋什么值
- 在resources目录下创建名
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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--对于一个xml文件如果作为框架的配置文件,需要遵守框架的配置规则
通常一个框架为了让开发者能够正确的配置,都会提供xml的规范文件(dtd/xsd)
-->
<!--通过bean将实体类配置给Spring进行管理,id表示实体类的唯一表示-->
<bean id="stu" class="com.qfedu.ioc.bean.Student">
<property name="stuAge" value="21"/>
<property name="stuNum" value="10001"/>
<property name="stuName" value="李斯"/>
<property name="enterenceTime" ref="date"/>
</bean>
<bean id="date" class="java.util.Date"/>
</beans>
实体类
package com.qfedu.ioc.bean;
import java.util.Date;
/**
* @author Helen
* @version 1.0
* @createTime 2022/1/5 7:20
* @Description
*/
public class Student {
private String stuNum;
private String stuName;
private int stuAge;
/**入学时间*/
private Date enterenceTime;
public String getStuNum() {
return stuNum;
}
public void setStuNum(String stuNum) {
this.stuNum = stuNum;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getStuAge() {
return stuAge;
}
public void setStuAge(int stuAge) {
this.stuAge = stuAge;
}
public Date getEnterenceTime() {
return enterenceTime;
}
public void setEnterenceTime(Date enterenceTime) {
this.enterenceTime = enterenceTime;
}
@Override
public String toString() {
return "Student{" +
"stuNum='" + stuNum + '\'' +
", stuName='" + stuName + '\'' +
", stuAge=" + stuAge +
", enterenceTime=" + enterenceTime +
'}';
}
}
初始化Spring对象工厂,获取对象
package com.qfedu.ioc.test;
import com.qfedu.ioc.bean.Student;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Helen
* @version 1.0
* @createTime 2022/1/5 7:34
* @Description
*/
public class Test {
public static void main(String[] args) {
/**通过Spring容器创建Student对象*/
/**初始化Spring容器,加载Spring配置文件*/
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
/**通过Spring容器获取Student对象*/
Student object=context.getBean("stu", Student.class);
System.out.println(object);
}
}
IOC和DI
- IOC(Inverse of Control)控制反转,通过Spring对象工厂完成对象的创建
- DI(Dependency injection)依赖注入,在Spring完成对象创建的同时依赖Spring容器完成对象属性的赋值
IOC
当我们需要通过Spring对象工厂创建某个类的对象时候,需要将这个交给Spring管理-- 通过bean标签配置
<!--通过bean将实体类配置给Spring进行管理,id表示实体类的唯一表示-->
<bean id="stu" class="com.qfedu.ioc.bean.Student">
<property name="stuAge" value="21"/>
<property name="stuNum" value="10001"/>
<property name="stuName" value="李斯"/>
<property name="enterenceTime" ref="date"/>
</bean>
DI
通过Spring容器给创建的对象属性赋值
<!--通过bean将实体类配置给Spring进行管理,id表示实体类的唯一表示-->
<bean id="stu" class="com.qfedu.ioc.bean.Student">
<property name="stuAge" value="21"/>
<property name="stuNum" value="10001"/>
<property name="stuName" value="李斯"/>
<property name="enterenceTime" ref="date"/>
</bean>
依赖注入
依赖注入三种方式
Spring容器加载配置文件之后,通过反射创建类的对象,并给属性赋值;Spring容器通过反射实现属性注入方式
- set方法注入
构造器注入
接口注入(不常用)
package com.qfedu.ioc.test;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author Helen
* @version 1.0
* @createTime 2022/1/5 19:45
* @Description
*/
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> c =Class.forName("com.qfedu.ioc.bean.Student");
/**通过反射创建对象*/
Object obj=c.newInstance();
System.out.println(obj);
/**通过反射获取类中的属性*/
Field[]fields=c.getDeclaredFields();
for (Field field:fields){
String fieldName = field.getName();
String setMethodName = "set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
System.out.println(fieldName+"--------------------"+setMethodName);
if("stuNum".equals(fieldName)){
Method setMethod = c.getDeclaredMethod(setMethodName,field.getType());
setMethod.invoke(obj,"10001");
}
}
System.out.println(obj);
}
}
set 方法注入
在bean标签中通过配置
property
标签给属性赋值,实际上就是通过反射掉用set方法完成属性的注入
简单类型及字符串
直接通过property 标签的value属性赋值
<!--通过bean将实体类配置给Spring进行管理,id表示实体类的唯一表示-->
<bean id="stu" class="com.qfedu.ioc.bean.Student">
<!--简单类型-->
<property name="stuAge" value="21"/>
<property name="stuNum" value="10001"/>
<!--字符串类型-->
<property name="stuName" value="李斯"/>
</bean>
日期类型
- 方式一:在
property
标签中同ref
引用Spring容器中的一个对象
<bean id="stu" class="com.qfedu.ioc.bean.Student">
<!--日期类型-->
<property name="enterenceTime" ref="date"/>
</bean>
<bean id="date" class="java.util.Date">
<property name="year" value="2021"/>
<property name="month" value="1"/>
<property name="date" value="6"/>
</bean>
- 方式二:在
property
中添加子标签bean
来指定对象
<bean id="stu" class="com.qfedu.ioc.bean.Student">
<!--日期类型-->
<property name="enterenceTime">
<bean class="java.util.Date"/>
</property>
</bean>
自定义对象类型
- 方式一:在
property
标签中同ref
引用Spring容器中的一个对象
<bean class="com.qfedu.ioc.bean.Book" id="book">
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="32.4f"/>
</bean>
<bean id="stu" class="com.qfedu.ioc.bean.Student">
<!-- 自定义对象类型-->
<property name="book" ref="book"/>
</bean>
- 方式二:在
property
中添加子标签bean
来指定对象
<bean id="stu" class="com.qfedu.ioc.bean.Student">
<property name="book">
<bean class="com.qfedu.ioc.bean.Book">
<property name="name" value="1"/>
<property name="price" value="32.4f"/>
</bean>
</property>
</bean>
集合类型
- List
List<String>
List中的元素是字符串或者简单类型的封装类
<property name="hobbies" value="旅游,美食"/>
List<Object>
List中的元素是对象类型
<property name="hobbies">
<list>
<value>打羽毛球</value>
<value>打篮球</value>
</list>
</property>
<property name="books">
<list>
<bean class="com.qfedu.ioc.bean.Book"/>
<bean class="com.qfedu.ioc.bean.Book"/>
</list>
</property>
<property name="books">
<list>
<ref bean="book"/><!-- 引用容器中的bean-->
</list>
</property>
- Set
<property name="sets">
<!--和list元素注入方式一样-->
<set>
<value>美食</value>
<value>旅游</value>
</set>
</property>
- Map
<property name="map">
<map>
<entry key="英语" value="87"/>
<entry key="数学" value="96"/>
</map>
</property>
- Properties
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
package com.qfedu.ioc.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.*;
/**
* @author Helen
* @version 1.0
* @createTime 2022/1/5 7:20
* @Description
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {
private String stuNum;
private String stuName;
private int stuAge;
/**入学时间*/
private Date enterenceTime;
private Book book;
private List<String>hobbies;
private Set<String>sets;
private Map<String,Object>map;
private Properties properties;
}
Spring配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--对于一个xml文件如果作为框架的配置文件,需要遵守框架的配置规则
通常一个框架为了让开发者能够正确的配置,都会提供xml的规范文件(dtd/xsd)
-->
<!--通过bean将实体类配置给Spring进行管理,id表示实体类的唯一表示-->
<bean class="com.qfedu.ioc.bean.Book" id="book">
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="32.4f"/>
</bean>
<bean id="stu" class="com.qfedu.ioc.bean.Student">
<!--简单类型-->
<property name="stuAge" value="21"/>
<property name="stuNum" value="10001"/>
<!--字符串类型-->
<property name="stuName" value="李斯"/>
<!--日期类型-->
<property name="enterenceTime">
<bean class="java.util.Date"/>
</property>
<property name="book">
<bean class="com.qfedu.ioc.bean.Book">
<property name="name" value="1"/>
<property name="price" value="32.4f"/>
</bean>
</property>
<property name="hobbies" value="旅游,美食"/>
<property name="sets">
<!--和list元素注入方式一样-->
<set>
<value>美食</value>
<value>旅游</value>
</set>
</property>
<property name="map">
<map>
<entry key="英语" value="87"/>
<entry key="数学" value="96"/>
</map>
</property>
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
测试
package com.qfedu.ioc.test;
import com.qfedu.ioc.bean.Student;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Helen
* @version 1.0
* @createTime 2022/1/5 7:34
* @Description
*/
public class Test {
public static void main(String[] args) {
/**通过Spring容器创建Student对象*/
/**初始化Spring容器,加载Spring配置文件*/
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
/**通过Spring容器获取Student对象*/
Student object=context.getBean("stu", Student.class);
System.out.println(object);
}
}
结果
Student(stuNum=10001, stuName=李斯, stuAge=21, enterenceTime=Thu Jan 06 20:03:06 CST 2022, book=Book(name=1, price=32.4), hobbies=[旅游,美食], sets=[美食, 旅游], map={英语=87, 数学=96}, properties={password=123456, username=root})
构造器注入
简答类型、字符串、对象、集合类型属性
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="book" class="com.qfedu.ioc.bean.Book">
<property name="price" value="32.5f"/>
<property name="name" value="红楼梦"/>
</bean>
<bean class="java.util.Date" id="date"/>
<bean id="stu" class="com.qfedu.ioc.bean.Student">
<!--constructor-arg name,name:指定属性名-->
<!--字符串类型-->
<constructor-arg name="stuName" value="小明"/>
<!--对象类型-->
<constructor-arg name="enterenceTime" ref="date"/>
<constructor-arg name="book" ref="book"/>
<!--简单类型-->
<constructor-arg name="stuAge" value="21"/>
<constructor-arg name="stuNum" value="10001"/>
<constructor-arg name="weight" value="22.0"/>
<!--集合类型-->
<constructor-arg name="hobbies">
<list>
<value>旅游</value>
<value>美食</value>
</list>
</constructor-arg>
<constructor-arg name="sets">
<set>
<value>111</value>
<value>222</value>
</set>
</constructor-arg>
<constructor-arg name="map">
<map>
<entry key="英语" value="27"/>
<entry key="数学" value="28"/>
</map>
</constructor-arg>
<constructor-arg name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</constructor-arg>
</bean>
</beans>
bean的作用域
在
bean
标签可以通过scope属性指定对象的作用域
scope="singleton"
表示当前bean是单例模式(默认饿汉模式,Spring容器初始化阶段就会完成此对象的创建;当在bean标签中设置lay-init="true"
变为懒汉模式)
scope="prototype"
表示当前bean为非单例模式,每次通过Spring容器获取此bean的对象时都会创建一个新的对象
- 单例
<bean id="stu" class="com.qfedu.ioc.bean.Student" scope="singleton" lazy-init="true">
</bean>
- 多例
<bean id="stu" class="com.qfedu.ioc.bean.Student" scope="prototype">
</bean>
bean的生命周期方法
- 实体类
package com.qfedu.ioc.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.*;
/**
* @author Helen
* @version 1.0
* @createTime 2022/1/5 7:20
* @Description
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {
private String stuNum;
private String stuName;
private int stuAge;
private double weight;
/**入学时间*/
private Date enterenceTime;
private Book book;
private List<String>hobbies;
private Set<String>sets;
private Map<String,Object>map;
private Properties properties;
/**
* 初始化方式:在创建当前类对象时调用的方法,进行资源的准备
*/
public void init(){
System.out.println("-------init");
this.stuName="李斯";
this.stuAge=21;
}
/**
* 销毁方法:在Spring容器销毁对象时调用此方法,进行一些资源回收性的操作
*/
public void destroy(){
System.out.println("--------destroy");
this.stuName="";
this.stuAge=0;
}
}
- Spring 配置方法
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--在bean标签中通过init-method属性指定当前bean的初始化方法,初始化方法在构造器执行之后执行-->
<!--在bean标签中通过destroy-method属性指定当前bean的销毁方法,销毁方法在对象销毁之前执行-->
<bean id="stu" class="com.qfedu.ioc.bean.Student" scope="prototype" init-method="init" destroy-method="destroy">
</bean>
</beans>
自动装配
自动装配:Spring在实例化当前bean的时候从Spring容器中找到匹配的实例赋值给当前bean的属性
自动装配策略有两种:
byName
byType
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="book" class="com.qfedu.ioc.bean.Book">
<property name="name" value="红楼梦"/>
<property name="price" value="32.5f"/>
</bean>
<!--自动装配:Spring在实例化当前bean的时候从Spring容器中找到实例赋值给当前bean属性
byName 根据当前Bean的属性名在Spring容器中寻找匹配的对象,如果根据name找到了bean但是类型不匹配抛出异常
byType 根据当前Bean的属性类型在Spring容器中寻找匹配的对象,如果根据类型找到了多个bean也会抛出异常
-->
<bean id="stu" class="com.qfedu.ioc.bean.Student" autowire="byName">
</bean>
</beans>
IOC工作原理
SpringIoc -基于注解
SpringIoc的使用,需要我们通过XML将类声明给Spring容器进行管理,从而通过Spring工厂完成对象的创建及属性值的注入
Spring除了提供基于XML的配置方式,同时提供了基于注解的配置,直接在实体类中添加注解声明给Spring容器管理,以简化开发步骤。
创建Spring配置文件
- 因为 Spring容器初始化时,只会加载applicationContext.xml,那么我们在实体类中添加的注解就不会被Spring扫描,所以我们需要
在applicationContext.xml声明Spring的扫描范围
,以达到Spring初始化时扫描带有注解的实体类并完成初始化工作。
<?xml version="1.0" encoding="UTF-8"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--声明使用注解配置-->
<context:annotation-config/>
<!--声明Spring工厂注解的扫描范围-->
<context:component-scan base-package="com.qfedu.ioc.bean"/>
</beans>
常用注解
@Component
- 类注解,声明此类被Spring容器进行管理,相当于bean标签的作用
@Component(value="stu")
value属性用于指定当前bean的id,相当于bean标签的id属性;value属性也可以省略,如果省略当前类的id默认为类名首字母小写@Service @Controller @Repository
这三个注解也可以将类声明给Spring管理,主要时语义上的区别- @Controller注解主要声明将控制器类配置给Spring管理,例如Servlet
- @Service注解主要声明业务处理类配置给Spring管理,Service接口的实现类
- @Repsitory 直接主要声明持久化类配置给Spring管理,DAO接口
- @Component除了控制器、service和DAO之外的类一律使用此注解声明
@Scope
- 类注解,用于声明当前单例模式还是非单例模式,相当于bean标签的scope属性
- @Scope(value = “prototype”)表示声明当前类为非单例模式(默认单例模式)
- @Scope(value = “singleton”):单例模式
@Lazy
- 类注解,用于声明一个单例模式的Bean是否为饿汉模式
- @Lazy(value = true)表示声明为懒汉模式,默认为饿汉模式
@PostConstruct
- 方法注解,声明一个方法为当前类的初始化方法(在构造器之后执行),相当于bean标签的init-method属性
@PreDestroy
- 方法注解,声明一个方法为当前类的销毁化方法(在对象从容器中释放之前执行),相当于bean标签的destroy-method属性
@Autowired
- 属性注解、方法注解(set方法),声明当前属性自动装配,默认byType
- @Autowired(required = false)通过required属性设置当前自动装配是否为必须(默认必须-如果没有找到类型与属性类型匹配的bean则抛出异常)
- byType
- ref引用 @Qualifier注解引用的bean的id
@Autowired
public void setClazz(@Qualifier("c1") Clazz clazz) {
this.clazz = clazz;
}
@Resource
- 属性注解,也用于声明属性自动装配
- 默认装配方式为byName,如果根据byName没有找到对应的bean,则继续根据byType寻找对应的bean,根据byType如果依然没有找到或者找到不止一个类型匹配的bean,则抛出异常。