spring5
1 spring概述
1.1 spring框架是什么
Spring 是于 2003 年兴起的一个轻量级的 Java 开发框架,它是为了解决企业应用开发的复杂性而创建的。
Spring 的核心是控制反转(IoC)和面向切面编程(AOP)。Spring 是可以在 Java SE/EE 中使用的轻量级开源框架
spring官网地址:https://spring.io/
spring官网下载地址:https://repo.spring.io/release/org/springframework/spring/
GitHub : https://github.com/spring-projects
1.2 spring的优点
- Spring是一个开源的免费的框架(容器)。
- spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能(AOP 编程的支持)
- 支持事务的处理,对框架整合的支持。
- Spring 不排斥各种优秀的开源框架,相反 Spring 可以降低各种框架的使用难度(方便集成各种优势框架)
- Spring 框架运行占用的资源少,运行效率高,不依赖其他 jar(轻量),非侵入式的框架。
- 提供了 Ioc 控制反转,由容器管理对象及对象的依赖关系(针对接口编程,解耦合)
1.3 spring体系结构
Spring 由 20 多个模块组成,它们可以分为数据访问/集成(Data Access/Integration)、Web、面向切面编程(AOP, Aspects)、提供JVM的代理(Instrumentation)、消息发送(Messaging)、核心容器(Core Container)和测试(Test)
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 .
- 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开
- Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
- Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
- Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
- Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
- Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
- Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
2 spring第一个程序
2.1 环境搭建
- 创建maven工程
2.2 导入依赖
<dependencies>
<!--spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<!--maven插件-->
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
2.3 定义接口和实现类
- 接口
public interface UserService {
public void addUser();
}
- 实现类
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("执行了底层增加用户的方法!");
}
}
2.4 创建spring配置文件
在 src/main/resources/目录现创建一个 xml 文件,文件名可以随意,但 Spring 建议的名称为 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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置service
bean: 配置需要创建的对象,一个实例对应一个 bean元素
id:该属性是 Bean 实例的唯一标识,程序通过 id 属性访问 Bean,用于之后从spring容器获得实例时使用的
class:需要创建实例的全限定类名,注意这里只能是类,不能是接口
-->
<bean id="userService" class="com.zwh.service.UserServiceImpl"></bean>
</beans>
2.5定义测试类
public class MyTest {
@Test
public void test() {
// 指定spring配置文件的位置和名称
String resource = "applicationContext.xml";
// 创建spring容器的对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(resource);
// 从spring容器中获取对象,使用id
UserService userService = (UserServiceImpl) context.getBean("userService");
// 执行对象的业务方法
userService.addUser();
}
}
测试结果:
执行了底层增加用户的方法!
2.6 使用 spring 创建非自定义类
spring 配置文件的class属性直接加全限定类名即可
<bean id="myDate" class="java.util.Date" />
2.7 容器中bean的作用域
当通过 Spring 容器创建一个 Bean 实例时,不仅可以完成 Bean 的实例化,还可以通过scope 属性,为 Bean 指定特定的作用域,Spring 支持 5 种作用域。
- singleton:单态模式。即在整个 Spring 容器中,使用 singleton 定义的 Bean 将是单例的,只有一个实例。默认为单态的。
- prototype:原型模式。即每次使用 getBean 方法获取的同一个bean的实例都是一个新的实例。
- request:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例。
- session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 实例。
- global session:每个全局的 HTTP session 对应一个 Bean 实例。典型情况下,仅在使用portlet 集群时有效,多个 Web 应用共享一个 session。一般应用中,global-session 与 session是等同的。
注意:
- 对于 scope 的值 request、session 与 global session,只有在 Web 应用中使用 Spring 时,该作用域才有效。
- 对于 scope 为 singleton 的单例模式,该 Bean 是在容器被创建时即被装配好了。
- 对于 scope 为 prototype 的原型模式,Bean 实例是在代码中使用该 Bean 实例时才进行装配的。
<bean id="myDate" class="java.util.Date" scope="prototype"></bean>
<bean id="myDate" class="java.util.Date" scope="singleton"></bean>
2.8 bean的生命周期
Bean 实例从创建到最后销毁,需要经过很多过程,执行很多生命周期方法。
- 调用无参构造器,创建实例对象。
- 调用参数的 setter,为属性注入值。
- 若 Bean 实现了 BeanNameAware 接口,则会执行接口方法 setBeanName(String beanId),使 Bean 类可以获取其在容器中的 id 名称。
- 若 Bean 实现了 BeanFactoryAware 接口,则执行接口方法 setBeanFactory(BeanFactory factory),使 Bean 类可以获取到 BeanFactory 对象。
- 若 定义并注册了 Bean 后 处 理 器 BeanPostProcessor , 则 执 行 接 口 方 法postProcessBeforeInitialization()。
- 若 Bean 实现了 InitializingBean 接口,则执行接口方法 afterPropertiesSet ()。该方法在 Bean 的所有属性的 set 方法执行完毕后执行,是 Bean 初始化结束的标志,即 Bean 实例化结束。
- 若设置了 init-method 方法,则执行。
- 若 定 义 并 注 册 了 Bean 后 处 理 器 BeanPostProcessor , 则 执 行 接 口 方 法postProcessAfterInitialization()。
- 执行业务方法。
- 若 Bean 实现了 DisposableBean 接口,则执行接口方法 destroy()。
- 若设置了 destroy-method 方法,则执行。
3 IOC控制反转
3.1 IOC概念和原理
什么是 IOC:
- 控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理
- 使用 IOC 目的:为了降低耦合度
- IOC 底层原理:xml 解析、工厂模式、反射
spring底层原理:
3.2 BeanFactory接口
IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂
Spring 提供 IOC 容器实现两种方式:(两个接口)
- BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员使用,加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
- ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用,加载配置文件时候就会把在配置文件对象进行创建
3.3 spring之DI注入
3.3.1 基于 XML 的DI注入
DI注入定义:bean 实例在调用无参构造器创建对象后,就要对 bean 对象的属性进行初始化。初始化是由容器自动完成的,称为注入。
根据注入方式的不同,常用的有两类:set 注入、构造注入。
3.3.1.1 第一种注入方式set 注入(掌握)
set 注入也叫设值注入是指,通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在 Spring 的依赖注入中大量使用。
创建实体类,定义属性和对应的 set 方法
在 spring 配置文件配置对象创建,配置属性注入
- 简单类型的set注入
<!--简单类型使用set注入-->
<bean id="student" class="com.zwh.pojo.Student">
<!--使用 property 完成属性注入
name:类里面属性名称
value:向属性注入的值
-->
<property name="sname" value="张三"/>
<property name="sage" value="19"/>
</bean>
- 引用类型的set注入
注意:
当指定 bean 的某属性值为另一 bean 的实例时,通过 ref 指定它们间的引用关系,ref的值必须为某 bean 的 id 值。
3.3.1.2 第二种注入方式构造器注入(理解)
<!--使用有参数构造进行注入 -->
<bean id="student2" class="com.zwh.pojo.Student">
<!--
name:指定参数名称
value:向属性注入的值
-->
<constructor-arg name="sname" value="李四"/>
<constructor-arg name="sage" value="29"/>
</bean>
注意:
index:指明该参数对应着构造器的第几个参数,从 0 开始。不过,该属性不要也行,但要注意,若参数类型相同,或之间有包含关系,则需要保证赋值顺序要与构造器中的参数顺序一致。
3.3.1.3 外部bean注入
在 service 调用 dao 里面的方法
<!--service与dao之间的关联注入-->
<bean id="userService2" class="com.zwh.service.UserServiceImpl">
<!--注入 userDao 对象
name 属性:类里面属性名称
ref 属性:创建 userDao 对象 bean 标签 id 值
-->
<property name="userDao" ref="userDao"/>
</bean>
<!--userDao-->
<bean id="userDao" class="com.zwh.dao.UserDao"/>
3.3.1.4 内部bean注入
在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
<!--内部 bean-->
< bean id= "emp" class= "com.zwh.spring5.bean.Emp">
<!--设置两个普通属性-->
< property name= "ename" value= "lucy"></ property>
< property name= "gender" value=" " 女" "></ property>
<!--设置对象类型属性-->
< property name= "dept">
< bean id= "dept" class= "com.zwh.spring5.bean.Dept">
< property name= "dname" value=" " 安保部" "></ property>
</ bean>
</ property>
</ bean>
3.3.1.5 集合注入
- 注入数组类型属性
- 注入 List 集合类型属性
- 注入 Map 集合类型属性
创建类,定义数组、list、map、set 类型属性,生成对应 set 方法:
@Data
public class Collect {
private String[] str;
private List<String> strings;
private Set<String> mySet;
private Map<String, Integer> myMap;
private Properties myPro;
}
- 在 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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--集合类型属性注入-->
<bean id="collect" class="com.zwh.pojo.Collect">
<!--数组注入-->
<property name="str">
<array>
<value>java</value>
<value>mysql</value>
</array>
</property>
<!--list类型属性注入-->
<property name="strings">
<list>
<value>张三</value>
<value>李四</value>
</list>
</property>
<!--set属性注入-->
<property name="mySet">
<set>
<value>mysql</value>
<value>redis</value>
</set>
</property>
<!--map属性注入-->
<property name="myMap">
<map>
<entry key="height" value="192"/>
<entry key="weight" value="120"/>
</map>
</property>
<!--为 Properties 注入值-->
<property name="myPro">
<props>
<prop key="tel">119</prop>
<prop key="address">江西</prop>
</props>
</property>
</bean>
</beans>
- 测试
@Test
// 测试集合注入
public void test7() {
// 指定spring配置文件的位置和名称
String resource = "bean-coll.xml";
// 创建spring容器的对象
BeanFactory context = new ClassPathXmlApplicationContext(resource);
// 从spring容器中获取对象,使用id
Collect coll = (Collect) context.getBean("collect");
System.out.println(coll);
}
}
3.3.1.6 引用类型 属性自动注入
对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为<bean/>
标签设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自入引用类型属性)。
根据自动注入判断标准的不同,可以分为两种:
- byName:根据名称自动注入
当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 实体类的属性名相同时,可使用byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入
<!--声明Student对象-->
<bean id="student" class="com.zwh.pojo.Student">
<property name="sname" value="zs"/>
<property name="sage" value="10"/>
</bean>
<bean id="myUsers" class="com.zwh.pojo.User" autowire="byName">
<property name="name" value="user"/>
<property name="age" value="23"/>
<!--传统set方式注入还需要引用Student的bean,但是使用byName,会自动查找-->
<!-- <property name="student" ref="student"/>-->
</bean>
- byType: 根据类型自动注入
使用 byType 方式自动注入。
<!--声明Student对象-->
<bean id="student1" class="com.zwh.pojo.Student">
<property name="sname" value="zs"/>
<property name="sage" value="10"/>
</bean>
<bean id="myUsers" class="com.zwh.pojo.User" autowire="byType">
<property name="name" value="user"/>
<property name="age" value="23"/>
</bean>
要求:
配置文件中被调用者 bean 的 class 属性指定的类,要与代码中调用者 bean 类的某引用类型属性类型同源。
即要么相同,要么有 is-a 关系(子类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配哪一个了。
使用byType时IDEA爆红,但是不影响结果。
3.3.1.7 命名空间注(了解)
有对于设值注入与构造注入,在配置文件中,除了使用<property/>
或<constructor-arg/>
标签外,还可使用命名空间注入的方式,让注入的值以<bean/>
标签属性的方式出现。
根据注入实现方式的不同,分为 p 命名空间注入与 c 命名空间注入。
p 命名空间注入:采用设值注入方式,故需要有相应的 setter
c 命名空间注入:采用构造注入方式,故需要有相应的构造器
- p 命名空间注入
修改配置文件头,即添加相应约束xmlns:p="http://www.springframework.org/schema/p"
<bean id="cStudent" class="com.zwh.pojo.Student" p:sname="zszs" p:sage="110"></bean>
- c 命名空间注入
修改配置文件头,即添加相应约束xmlns:c="http://www.springframework.org/schema/c"
<bean id="cStudent" class="com.zwh.pojo.Student" c:sname="hello" c:sage="120"></bean>
3.3.1.8 其他注入
- null 值注入
<!--null 值-->
< property name= "address">
< null/>
</property>
- 特殊符号注入
<!--属性值包含特殊符号
1 把<>进行转义 < >
2 把带特殊符号内容写到 CDATA
-->
< property name= "address">
< value><![CDATA[<<南京>>]]></ value>
</ property>
**3.3.1.9 **SpEL
SPEL,Spring Expression Language,即 Spring EL 表达式语言。
在 Spring 配置文件中为 Bean 的属性注入值时,可直接使用 SPEL 表达式计算的结果。
SPEL 表达式以#开头,后跟一对大括号。用法:<bean id="abc" value="#{…}"/>
。
随机生成年龄:
<?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">
<bean id="spelStu" class="com.zwh.pojo.Student">
<property name="sname" value="张三"></property>
<!--生成随机数的年龄-->
<property name="sage" value="#{T(java.lang.Math).random()*30}"></property>
</bean>
</beans>
- 其他用法
1、<property name="school" value="#{mySchool}"/>
引用另一个 bean。指定 school 的值为另一个 Bean 实例 mySchool。
2、<property name="schoolName" value="#{mySchool.name.toUpperCase()}"/>
使用指定属性,并使用其方法。指定 schoolName 的值为 mySchool 的 name 属性值,并将其字母均转换为大写字母(toUpperCase()方法)。
3.3.1.10 引入外部属性文件
1、直接配置数据库信息
- 配置德鲁伊连接池
<!--直接配置连接池-->
< bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource">
< property name ="driverClassName" value ="com.mysql.jdbc.Driver"></ property>
< property name ="url" value ="jdbc:mysql://localhost:3306/userDb"></ property&