SSM框架学习(二)————Spring
一.Spring简介
我们一般说 Spring 框架指的都是 Spring Framework,Spring是一个开源框架,Spring是于2003年兴起的一个轻量级的Java开发框架,由Rod Johnson在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。
1.Spring一个开源的,用来简化企业级应用开发的应用开发框架。
2.使用Spring的目的:spring的本质是管理软件的对象,即如创建对象和维护对象之间的关系。
3.Spring的核心思想是IOC(控制反转)和AOP(面向切面编程),即不再需要程序员去显式地new
一个对象,而是让Spring框架帮你来完成这一切。
二.Spring框架
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,组成Spring的每一个模块都可以单独存在,或则与其他一个或多个模块联合实现。Spring框架7个模块如图:
每个模块的功能如下:
1.Spring Core:核心容器——核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
2.Spring Context:Spring上下文——Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。
3.Spring AOP:AOP(面向切面编程)——通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。
4.Spring DAO:Spring的Dao模块式Spring框架中对应持久层的解决方式,提供了对JDBC、Hibernate、JDO等DAO层支持。 Spring框架对JDBC进行了封装,完全抛弃了JDBC API。数据库连接、事务等也交给了Spring打点,开发者只需要使用封装好的JdbcTemplate执行SQL语句,然后得到需要的结果。
5.Spring ORM:ORM的全称是Object Relational Mapping,即对象关系映射。它的实现思想就是将关系数据库中表的数据映射成为对象,以对象的形式展现,这样开发人员就可以把对数据库的操作转化为对这些对象的操作。
6.Spring Web:Web 上下文模块建立在应用程序上下文模块之上,Web 模块简化了处理多部分请求以及将请求参数绑定到域对象的工作。web则对远程调用和远程服务的支持。
7.Spring Web MVC:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现,用于创建 Web 应用程序的可扩展 MVC 框架。webmvc主要是对mvc的支持,包括restful协议。
三.Spring开发具体步骤
步骤1:先导入指定jar包(5个,Spring的jar版本要统一,防止出问题,该jar包可以在maven官网下载):
- commons-logging.jar
- spring-beans-5.1.3.RELEASE.jar
- spring-context-5.1.3.RELEASE.jar
- spring-core-5.1.3.RELEASE.jar
步骤2:书写一个普通的实体类(例:UserBean)
步骤3:为这个实体类书写指定的配置文件applicationContext.xml
步骤4:写一个测试类获得UserBean实例
四.Spring容器简介及Bean配置与实例化
4.1 Spring容器
在Spring中,任何java类和javaBean都会被当作Bean处理,这些Bean通过Spring容器进行管理和应用,Spring容器实现了IOC和AOP机制,这些机制可以简化Bean的创建和Bean对象之间的解耦。Spring容器有BeanFactory和ApplicationContext两种类型。BeanFactory是Spring中比较原始的Factory,ApplicationContext继承自BeanFactory接口,拥有更多企业级方法,原始的BeanFactory无法支持Spring的许多插件,如AOP功能,Web应用。所以在实际中推荐使用ApplicationContext。
实例化ApplicationContext的方式有两种:
方式一:
通过ClassPathXmlApplicationContext加载配置文件并实例化(重点掌握):
其默认去默认路径下找配置文件,类路劲指的就是编译后.class文件所在位置的路径,普通文件在bin,web项目在web-info/classes中。// 单个配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //多个配置文件 ApplicationContext applicationContext2 = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml");
方式二:
通过FileSystemXmlApplicationContext加载配置文件并实例化//单个配置文件 ApplicationContext applicationContext3 = new FileSystemXmlApplicationContext("aaplicationContext.xml"); //多个配置文件 ApplicationContext applicationContext4 = new FileSystemXmlApplicationContext("applicationContext.xml","applicationContext2.xml");
4.2 Spring容器的Bean配置
从本质上来说BeanFactory和ApplicationContext仅仅知识一个维护Bean定义以及相互依赖关系的高级接口,我们可以通过他们的实例来获得我们需要的Bean实例。在实例化之前需要在容器的配置文件applicationContext.xml中添加对要用的Bean的定义。
例如:
<bean id="userInfo" class="cn.pluto.test.UserInfo"/>
或则:
<bean name="userInfo" class="cn.pluto.test.UserInfo">
其中id或name属性用于指定该Bean的名称,以便于从spring中查找该Bean,class用来指定该Bean的类型,即我们要实例化的类的全类名
然后我们就可以调用ApplicationContext实例的**getBean(“id或class属性”)**来获取Bean实例。
4.3 Bean实例化的方式
在Spring中实例化Bean一般有三种方式:
1.使用构造器实例化(使用最多)
2.使用静态工厂方法实例化
3.使用实例工厂方法实例化
3.3.1 构造器实例化
创建一个user类
package entity;
/**
* @author zqq
* @create 2019-08-03-14:41
*/
public class User {
private int id;
private String name;
private String phone;
public User() {
}
public User(int id, String name, String phone) {
this.id = id;
this.name = name;
this.phone = phone;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
1.无参构造器实例化:Spring容器会通过调用无参构造器来实例化该类,这个方式实例化Bean要求要实例化的类中一定要有无参构造器
<bean id="User" class="entity.User" />
2.带参构造器实例化:一定要有构造器
<bean id="User2" class="entity.User" > //index代表参数下标 <constructor-arg index="0" value="1001"/> <constructor-arg index="1" value="Alice"/> </bean>
实例化成功如下:
package test;
import entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* @author zqq
* @create 2019-08-03-10:42
*/
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext1 = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) applicationContext1.getBean("User");
user.setId(1001);
System.out.println("user = " + user.getId());
}
}
运行结果如下:
"C:\Program Files\Java\jdk1.8.0_211\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3\lib\idea_rt.jar=4755:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_211\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\rt.jar;D:\ProgramData\WorkPlace_idea\WebDemo\web\WEB-INF\classes;D:\ProgramData\WorkPlace_idea\WebDemo\web\WEB-INF\lib\commons-logging-1.1.3.jar;D:\ProgramData\WorkPlace_idea\WebDemo\web\WEB-INF\lib\spring-core-5.1.3.RELEASE.jar;D:\ProgramData\WorkPlace_idea\WebDemo\web\WEB-INF\lib\spring-beans-5.1.3.RELEASE.jar;D:\ProgramData\WorkPlace_idea\WebDemo\web\WEB-INF\lib\spring-context-5.1.3.RELEASE.jar;D:\ProgramData\WorkPlace_idea\WebDemo\web\WEB-INF\lib\spring-expression-5.1.3.RELEASE.jar" test.Test
user = 1001
Process finished with exit code 0
4.3.2 静态工厂方法实例化
public class UserFactory {
//静态工厂方法
public static User getInstance() {
return new User();//返回一个User对象
}
//实例化方法
public User createUser() {
return new User();//返回一个User对象
}
}
// factory-method属性指实现实例化类的静态方法
<bean id="userFactory" class="cn.goktech.Factory.UserFactory" factory-method="getInstance"></bean>
4.3.3 实例工厂方法实例化
// 配置第一个bean是先用构造器方法实例化工厂类UserBeanFactory
// 配置第二个bean的factory-bean的id值对应
// factory-method属性是第一个bean的实例工厂方法,最后调用getBean即可。
<bean id="userFactory" class="cn.goktech.Factory.UserFactory" ></bean>
<bean id="user" class="cn.goktech.entity.User" factory-bean="userFactory" factory-method="createUser" scope="singleton"></bean>
五.Bean的五个作用域
在bean有一个scope属性,通过设置该属性可以设置bean作用域
1.singleyon:单例模式,在整个Spring IOC容器中,使用singleton定义的Bean将只有一个实例。默认使用该作用域
2.prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例。
3.request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效。
4.session:对于每次Http Session 用法和使用时机同上
5.globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。一般用于Porlet应用环境,分布式系统存在全局session概念。如果不是porlet环境,globalSession 等同于Session。
六.生命周期和延迟实例化
通过为配置文件bean添加相应的init-method和destory-method属性,可以指定Bean中的某些方法为初始化方法和销毁方法。
延迟实例化:容器启动时不会实例化,在调用时才实例化<!-- 指定一个类的 初始化调用方法:init-method 和销毁方法:init-method 延迟实例化:lazy-init,当beans添加default-lazy-init="true"所有bean都会被延迟实例化 --> <bean id="cat" class="cn.goktech.entity.Cat" init-method="init" destroy-method="destory" lazy-init="true"></bean>
七.Spring IOC和Spring DI
IOC:控制反转,它不是一种技术,而时一种设计思想,即java程序中获取对象的方式发生反转,由最初的new方式创建,转变成由第三方框架创建,注入。IOC是Spring的框架的基础和核心,有了IOC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入对象,所以对象和对象之间是松散耦合。
DI:依赖注入,IOC的一个重点是在系统运行中,动态的像某个对象提供它所需要的其他对象,这一点就是通过DI来实现,即DI是实现IOC的主要技术途径。
创建一个Student类
public class Student { private String name; private Cat cat; public Student() { super(); } public Student(String name, Cat cat) { super(); this.name = name; this.cat = cat; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } }
依赖注入方式:
1.setter注入:使用property
2.构造器注入:使用constructor-arg<bean id="cat" class="cn.goktech.entity.Cat" init-method="init" destroy-method="destory" lazy-init="true"></bean> <!-- 依赖注入 1.setter注入:property2.构造器注入 :constructor-arg--> <bean id="student" class="cn.goktech.entity.Student"> <!-- property:name字段名 value指定值 ref依赖注入,使用给定类的id --> <!-- <property name="name" value="Clover"/> <property name="cat" ref="cat"/> --> <constructor-arg index="0" value="Franch"></constructor-arg> <constructor-arg index="1" ref="cat"></constructor-arg> </bean>
八.Spring参数注入
1.通过value属性实现基本类型数据注入
- setter注入
<bean id="user" class="cn.goktech.entity.User">
<property name="id" value="1001"></property>
<property name="name">
<value>Alice</value>
</property>
<property name="cat" ref="cat"></property>
</bean>
- 构造器注入
<bean id="user" class="cn.goktech.entity.User">
<constructor-arg index="0" value="1001"/>
<constructor-arg index="1" >
<value>Alice</value>
</constructor-arg>
<constructor-arg index="2" ref="cat"/>
</bean>
2.通过和
<!-- 测试集合框架 -->
<bean id="testCollection" class="cn.goktech.entity.TestCollection">
<property name="list">
<list>
<value>四川</value>
<value>北京</value>
<value>上海</value>
</list>
</property>
<property name="set">
<set>
<value>苹果</value>
<value>香蕉</value>
<value>葡萄</value>
</set>
</property>
<property name="map">
<map>
<entry key="科目一" value="语文"></entry>
<entry key="科目二" value="数学"></entry>
<entry key="科目三" value="英语"></entry>
</map>
</property>
</bean>
3.通过实现Properties类型参数值注入
<bean id="testProp" class="cn.goktech.entity.TestProp">
<property name="properties">
<props>
<prop key="driver">com.mysql.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306/test_db</prop>
//省略其他
</props>
</property>
</bean>
4.使用util标签
创建jdbc.properties
driver=com.jdbc.jdbc.Driver
url=jdbc:mysql//localhost:3306/test_db
username=root
password=123456
<!-- 使用本地配置文件 -->
<util:properties id="jdbc" location="classpath:jdbc.properties"/>
<bean id="testProp" class="cn.goktech.entity.TestProp">
<!--使用依赖注入-->
<constructor-arg index="0" ref="jdbc">
</constructor-arg>
</bean>
5.使用Spring表达式
<!-- 使用本地配置文件 -->
<util:properties id="jdbc" location="classpath:jdbc.properties"/>
<bean id="dbutil" class="first spring. DButil">
<!--使用SpringEL表达式像指定bean注入jdbc.properties文件信息-->
<property name="driver" value="#{jdbc.driver}"/>
<property name="url" value="#{jdbc.url}"/>
<property name="userName" value="#{jdbc.userName}"/>
<property name="password" value="#{jdbc.password}"/>
</bean>
九.自动装配
Spring能自动装配Bean与Bean之间的依赖关系,即无须使用ref属性显式地指定依赖Bean,而是由Spring容器检查XML配置文件内容。自动装配可以减少配置文件的工作量,但是降低了依赖关系的透明性和确定性。
通过设置autowire属性设置不同的装配方式
1.no:默认值,不适用自动装配,bean之间的依赖关系完全由ref定
2.byName:Spring容器以属性名作为id来查找相应的bean,调用set方法来完成注入<bean id="wt" class="ioc.Waiter"/> <bean id="restaurant1" class="ioc.Restaurant" autowire="byName"/> //Spirng 根据Restaurant 类中的setWt()找xml配置文件中id="wt”的bean,
- 注: Spring仅仅会根据名字去查找,即使类型不匹配也会发生注入,只是在注入的时候抛出类型转换异常。如果找不到bean 则注入 null。
3.byType:Spring容器查找与class属性一致的bean,然后调用set方法来注入
<bean id="wt" class="ioc.Waiter"/> <bean id="restaurant2" class="ioc.Restaurant" autowire="byType"/> //即通过Restaurant类中 setWt(Waiter wt) 形参类型去找对应的bean
- 如果在xml配置文件找到多个同类型bean,则抛出异常
4.constructor:容器查找与class属性一致的bean然后调用构造器完成
<bean id="wt" class="ioc.Waiter"/> <bean id="restaurant3" class="ioc.Restaurant" autowire="constructor"/> //即在 实例化Restaurant时,会根据其有参构造器实例化,然后将Waiter实例注入,构造器传参数类型也需要都在配置文件中进行bean定义,否则注入null。
十.组件扫描及相关注解
10.1组件扫描
组件扫描是我们指定一个包路径,Spring会自动扫描该包及其子包所有组件,当发现这些组件类前由特定的注解标记时,就将该组件拉进Spring容器,其等价于原来XML配置功能,只用组件扫描可以代替大量xml的定义,spring容器启动后,如果发现配置文件中包好了component-scan的配置信息,则spring容器会扫描指定包及其子包下面的所有的类,如果这些类包含了一些特定的注解,则容器会将其收纳入容器进行管理,相当于配置文件中添加了一个bean配置,对于扫描到的这些组件(类),Spring有它默认的取名规则,即类名首字母小写
配置方式如下:
<!-- 自动扫描注解配置 -->
<context:component-scan base-package="cn.goktech.anno" />
10.2 相关注解
1.@Component:通用注解,是所有受Spring管理组建的通用形式,但是一般来说不推荐使用该注解
//当spring扫描到该注解是,会自动生成该类的bean //该bean的标识默认为类名首字母小写,也可以在括号中自定义该值 @Component("dog") public class Dog { //具体实现 }
2.@Service注解:业务层注解,一般用是放在业务层上
3.@Autowire和@Qualaifier
- 这两个注解即支持set方式注入,也支持构造器注入,将@Autowire放在set方法前,或则添加到属性前,@Qualaifier的作用是知道被注入bean的id,按setter注入,不知道就按照byType注入,实际应用中还是直接写在属性上,不调用构造器或set方法。
4.@Resource只支持setter注入
- 后面可以加一个name属性 ,即 @Resource(name=“要注入bean的id”), 不加则按照byType方法注入, 该注解加在set方法前,也可加在属性值前
- set注入推荐使用@Resuource,构造器注入推荐使用@Autowire
5.关于生命周期的两个注解
- @PostConstruct:初始化注解
- @ PreDestroy:销毁注解
6.作用域注解**@Scope(“prototype”)(多例模式)
7.延时注解@Lazy(true)**
8.@value
- 注入基本类型
@Value("张三") private String name;
- 可以用该注解来使用spring表达式,该注解可以写在set方法前,也可在属性前。
@Value("#{config.pagesize}") public void setPageSize(String pageSize) { this.pageSize = pageSize; } // 用spring表达式来获取config.proerties里的值,再写入 Vlaue("xxx"),注入给pageSize