三天教你学会spring
一,前言:
- 传统的Wen开发存在硬编码所造成的程序过渡耦合,(例如,在sevice层中有Dao层的属性对象);
- 部分JAVAEE的API 较为复杂,使用的效率低(例如JDBC的开发步骤);
- 侵入性强,移植性差(这其实就是耦合性太高带来的,如,Dao层实现更换的话,在sevice和controller层都要在对应的代码上进行相应的更改);
二, 框架
2.1 概念:
- Spring是一个项目管理框架 , 同时也是一套JAVAEE 解决方案;
- Spring同时也是众优秀的设计模式的组合(工厂,单例,代理,适配器,包装器,观察者,模版,策略);
- Spring并未代替现有的框架产品,而是对现有的框架产品进行有机整合,简化企业级开发,俗称“胶水框架”;
2.2 访问和下载:
官方网站:https://spring.io/
下载地址:http://repo.spring.io/release/org/springframework/spring/
三,spring架构组成:
spring 框架由 很多的模块组成 , 可分类为:
- 核心技术为: 依赖注入 , 事件 , 资源 ,i18n , 验证, 数据绑定, 类型转换 ,SpEL , AOP
- 测试: 模拟对象 , TestContext框架 , Spring MVC 测试 ,WebTestClient
- 数据访问: 事务 , jdbc , DAO支持 ,ORM, 封送XML
- SpringMVC 和Spring WebFlux Web框架
- 集成: 远程处理 , JMS , JCA , JMX , 电子邮件 ,任务 ,调度 ,缓存
- 语言: Kotlin , Groovy , 动态语言;
GroupId | ArtifactId | 说明 |
---|---|---|
org.springframework | spring-beans | Beans 支持,包含 Groovy |
org.springframework | spring-aop | 基于代理的AOP支持 |
org.springframework | spring-aspects | 基于AspectJ 的切面 |
org.springframework | spring-context | 应用上下文运行时,包括调度和远程抽象 |
org.springframework | spring-context-support | 支持将常见的第三方类库集成到 Spring 应用上下文 |
org.springframework | spring-core | 其他模块所依赖的核心模块 |
org.springframework | spring-expression | Spring 表达式语言,SpEL |
org.springframework | spring-instrument | JVM 引导的仪表(监测器)代理 |
org.springframework | spring-instrument-tomcat | Tomcat 的仪表(监测器)代理 |
org.springframework | spring-jdbc | 支持包括数据源设置和 JDBC 访问支持 |
org.springframework | spring-jms | 支持包括发送/接收JMS消息的助手类 |
org.springframework | spring-messaging | 对消息架构和协议的支持 |
org.springframework | spring-orm | 对象/关系映射,包括对 JPA 和 Hibernate 的支持 |
org.springframework | spring-oxm | 对象/XML 映射(Object/XML Mapping,OXM) |
org.springframework | spring-test | 单元测试和集成测试支持组件 |
org.springframework | spring-tx | 事务基础组件,包括对 DAO 的支持及 JCA 的集成 |
org.springframework | spring-web | web支持包,包括客户端及web远程调用 |
org.springframework | spring-webmvc | REST web 服务及 web 应用的 MVC 实现 |
org.springframework | spring-webmvc-portlet | 用于 Portlet 环境的MVC实现 |
org.springframework | spring-websocket | WebSocket 和 SockJS 实现,包括对 STOMP 的支持 |
org.springframework | spring-jcl | Jakarta Commons Logging 日志系统 |
总结:spring框架的特点:
- 项目管理框架
- 对象工厂
- 提供了IOC/DI 过程
- 提供了AOP切面编程
四, 自定义工厂:
4.1 , 配置文件:
userDAO=com.qf.dao.UserDAOImpl
userService=com.qf.service.UserServiceImpl
4.2 ,工厂类:
package com.itluma.myshop.factory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* 对象工厂,提供各种项目所需要的对象
*/
public class UserFactory {
private Properties properties = new Properties();
private Map<String, Object> container = new HashMap<>();
public UserFactory() {
//1.将配置文件中的所有内容读取到集合中
InputStream resource = UserFactory.class.getResourceAsStream("/obj.properties");
try {
//java.lang.NullPointerException
//key(name)=value
properties.load(resource);//将obj.properties文件中的key=value读取到properties集合中
//2.构造具体的实例对象
//2.1 遍历Properties集合
Enumeration<?> enumeration = properties.propertyNames();
while (enumeration.hasMoreElements()) {
//2.2 构造具体实例对象
String beanName = (String) enumeration.nextElement();
String classBeanName = (String) properties.get(beanName);
//通过反射构造对象
Class<?> aClass = Class.forName(classBeanName);
Object objectBean = aClass.newInstance();
container.put(beanName, objectBean);
}
System.out.println(container);
} catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
//根据beanName返回容器中的具体实例对象
public Object getBean(String beanName) {
return container.get(beanName);
}
}
五,构建Maven项目:
5.1 新建项目:
5.2 选择Maven目录:
5.3 GAV 坐标:
六,Spring环境搭建:
什么是javaBean?
- 必须存在一个无参的构造方法;
- 字段需要私有化
- 需要提供公共的get/set属性
class Person{
private String name;//字段
private Integer age;//字段
public Person(){
}
public String getName(){//name属性
return this.name;
}
public void setName(String name){
this.name = name;
}
public double getSalary(){//salary属性
return 1.0;
}
...
}
6.1 pom.xml中引入spring常用的依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qf</groupId>
<artifactId>hello-spring</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- Spring常用依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
</dependencies>
</project>
6.2 创建spring配置文件:
命名无限制,约定俗成命名有:spring-context.xml、applicationContext.xml、beans.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">
</beans>
七, spring工厂编码:
定义目标bean的类型
public class MyClass{
public void show(){
System.out.println("HelloWorld");
}
}
spring-context.xml 中的
<beans >
内部配置bean 标签:
<!-- 配置实例(id:“唯一标识” class="需要被创建的目标对象全限定名") -->
<bean id="mc" class="com.qf.spring.part1.factory.MyClass" />
调用Spring工厂API(ApplicationContext接口)
public class TestFactory{
/**
* 程序中的对象都交由Spring的ApplicationContext工厂进行创建。
*/
public static void main(String[] args){
//1. 读取配置文件中所需创建的bean对象,并获得工厂对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
//2. 通过id获取bean对象
MyClass mc = (MyClass) ctx.getBean("mc");
//3. 使用对象
mc.show();
}
}
八,依赖与配置文件详解:
spring 框架 包含多个模块 ,每个模块各司其职 ,可结合相关需求 引入相关依赖jar包,实现功能;
8.1 spring 依赖关系:
Spring常用功能的Jar包依赖关系 |
---|
8.2 schema:
配置文件中的顶级标签中 包含了语义化标签的相关信息:
- xmlns: 语义化标签所在的命名空间
- xmlns:xsi: SMLSchema-instance 标签遵循Schema标签标准;
- xsi:schemaLocation:xsd文件位置,用以描述标签语义、属性、取值范围等。
九, IOC(Inversion of Control ) 控制反转
Inversion of Control : 控制反转
反转了依赖关系的满足方式,由之前的自己创建依赖对象 , 到由工厂推送(变主动为被动 , 即为反转);
解决了具有相互依赖关系的组件之间的强耦合性,是的项目形态更加的稳健;
9.1 项目中强耦合问题:
public class UserDAOImpl implements UserDAO{....}
public class UserServiceImpl implements UserService {
// !!!强耦合了UserDAOImpl!!!,使得UserServiceImpl变得不稳健!!
private UserDAO userDAO= new UserDAOImpl();
@Override
public User queryUser() {
return userDAO.queryUser();
}
....
}
9.2 解决方案:
// 不引用任何一个具体的组件(实现类),在需要其他组件的位置预留存取值入口(set/get)
public class UserServiceImpl implements UserService {
// !!!不再耦合任何DAO实现!!!,消除不稳健因素!!
private UserDAO userDAO;
// 为userDAO定义set/get,允许userDAO属性接收spring赋值
//Getters And Setters
@Override
public User queryUser() {
return userDAO.queryUser();
}
....
}
<bean id="userDAO" class="com.qf.spring.part1.injection.UserDaoImpl"></bean>
<!-- UserServiceImpl组件 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl">
<!-- 由spring为userDAO属性赋值,值为id="userDAO"的bean -->
<property name="userDAO" ref="userDAO"/>
</bean>
此时,如果需要更换其他UserDAO实现类,则UserServiceImpl不用任何改动!
则此时的UserServiceImpl组件变得更加稳健!
十,DI(Dependency Injection) 依赖注入:
10.1 概念:
在spring创建对象的同时,为其属性赋值, 被称为 依赖注入;
10.2 set注入:
创建对象时, spring工厂会通过set方法为其属性赋值;
- 定义目标Bean类型:
@Data
public class User {
private Integer id;
private String password;
private String sex;
private Integer age;
private Date bornDate;
private String[] hobbys;
private Set<String> phones;
private List<String> names;
private Map<String,String> countries;
private Properties files;
//Getters And Setters
}
- 构建对象: 基本类型 + 字符串类型 + 日期类型
<bean id="u1" class="com.qf.spring.part1.injection.User">
<!--base field-->
<property name="id" value="1001" />
<property name="password" value="123456" />
<property name="sex" value="male" />
<property name="age" value="20" />
<property name="bornDate" value="1990/1/1" /><!--注意格式"/"-->
</bean>
: 容器类型:
<bean id="u1" class="com.qf.spring.part1.injection.User">
<!--Array-->
<property name="hobbys">
<array>
<value>Run</value>
<value>Swim</value>
<value>Climb</value>
</array>
</property>
<!--Set-->
<property name="phones">
<set>
<value>13777777777</value>
<value>13888888888</value>
<value>13999999999</value>
</set>
</property>
<!--List-->
<property name="names">
<list>
<value>tom</value>
<value>jack</value>
<value>marry</value>
</list>
</property>
<!--Map-->
<property name="countries">
<map>
<entry key="CN" value="China" />
<entry key="US" value="America" />
<entry key="KR" value="Korea" />
</map>
</property>
<!--Properties-->
<property name="files">
<props>
<prop key="first">One</prop>
<prop key="second">Two</prop>
<prop key="third">Three</prop>
</props>
</property>
</bean>
自建类型:
<!--次要bean,被作为属性-->
<bean id="addr" class="com.qf.spring.part1.injection.Address">
<property name="position" value="北京市海淀区" />
<property name="zipCode" value="100001" />
</bean>
<!--主要bean,操作的主体-->
<bean id="u2" class="com.qf.spring.part1.injection.User">
<property name="address" ref="addr" /><!--address属性引用addr对象-->
</bean>
10.3 构造注入:
创建对象时 ,spring 工厂会 通过构造方法为对象的属性赋值;
10.3.1 定义目标Bena类型
@Data
public class Student {
private Integer id;
private String name;
private String sex;
private Integer age;
//Constructors
public Student(Integer id , String name , String sex , Integer age){
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}
}
10.3.2 注入:
<!--构造注入-->
<bean id="u3" class="com.qf.zcg.spring.day1.t2.ioc.Student">
<constructor-arg name="id" value="1234" /> <!-- 除标签名称有变化,其他均和Set注入一致 -->
<constructor-arg name="name" value="tom" />
<constructor-arg name="age" value="20" />
<constructor-arg name="sex" value="male" />
</bean>
10.4 自动注入
不用在配置中,指定为哪个属性赋值 ,赋什么值;
有spring自动根据某个“原则”,在工厂中查找一个bean,为属性注入属性值;
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
//Getters And Setters
....
}
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!-- 为UserServiceImpl中的属性基于类型自动注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byType"></bean>
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!-- 为UserServiceImpl中的属性基于类型自动注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byName"></bean>
十一,Bean细节:
11.1 控制简单对象的单例, 多例:
<!--
singleton(默认):容器第一次启动时,构造对象。
prototype:每次获取对象时构造对象。
-->
<bean id="mc" class="com.qf.zcg.spring.day1.t1.basic.MyClass" scope="singleton" />