我们于2021/08/16 的学习目标是:Spring框架,核心任务为:
1、学习技术:
1)、Spring的概念
2)、Spring的环境搭建
3)、Spring IOC 容器 Bean 对象实例化模拟
4)、Spring IOC 配置文件加载
5)、Spring IOC 注入
6)、Spring IOC 扫描器
7)、Bean的作用域
8)、Bean的生命周期
2、文档总结
1)、Spring的概念
Spring是众多开源Java项目中的一员,基于分层的JavaEE应用一站式轻量级开源框架,主要核心是IOC(控制反转或依赖注入)和AOP(面向切面)两大技术,实现项目在开发过程中的轻松解耦,提高项目的开发效率。
在项目中引入Spring有以下好处:
- 降低组件之间的耦合度,实现软件各层之间的解耦。
- 可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。
- 当我们使用容器管理事务时,开发人员就不再需要手工控制事务,也不需处理复杂的事务传播。
- 容器提供单例模式支持,开发人员不再需要自己编写实现代码。
- 容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能。
Spring源码架构:
- 核心容器
- Spring-AOP
- Spring Data Access
- Web模块
- 报文发送
- 单元测试
2)、Spring的环境搭建
环境要求:
- JDK1.7及以上版本
- Spring 5.x版本
步骤:
新建Maven的普通Java项目
org.apache.maven.archetypes:maven-archetype-quickstart
设置项目的位置、名称和附加信息
设置项目的Maven环境
设置项目的Maven环境
调整项目环境:
修改JDK版本
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 修改JDK版本 -->
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
修改单元测试的JUnit版本
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version> <!-- 修改JUnit版本 -->
<scope>test</scope>
</dependency>
删除build标签中的pluginManagement标签
<build>
</build>
<!-- 删除此标签 -->
添加 Spring 框架的依赖坐标
<!-- 添加至dependencies标签内 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.14.RELEASE</version>
</dependency>
编写Bean对象
package com.sdf.service;
public class UserService {
public void test(){
System.out.println("UserService.test()");
}
}
新建资源目录,在此目录下配置spring.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">
<!--
xmlns 即 xml namespace xml使用的命名空间
xmlns:xsi 即xml schema instance xml 遵守的具体规范
xsi:schemaLocation 本文档xml遵守的规范 官方指定
-->
<bean id="userService" class="com.sdf.service.UserService"></bean>
</beans>
在spring.xml中配置Bean对象
<!--
id:bean对象的id,唯一标识。一般是Bean对象的名称的首字母小写
class:bean对象的类路径
-->
<bean id="userService" class="com.xxxx.service.UserService"></bean>
加载配置文件,获取实例化对象
package com.sdf;
import com.sdf.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppTest{
public static void main(String[] args){
//获取Spring上下文环境
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml")
//通过getBean方法得到Spring容器中实例化好的Bean对象
//(实例化Bean对象)
//userService代表的是配置文件中bean标签的id属性值
UserService userService = (UserService) ac.getBean("userService");
//调用方法
userService.test();
}
}
3)、Spring IOC 容器 Bean 对象实例化模拟
思路:
- 定义Bean工厂接口,提供获取Bean方法
- 定义Bean工厂接口实现类,解析配置文件,实例化Bean对象
- 实现获取Bean方法
定义Bean属性对象
package com.sdf.javabean;
import java.util.Objects;
public class MyBean {
private String id;
private String clazz;
public MyBean() {
System.out.println("MyBean.MyBean()");
}
public MyBean(String id, String clazz) {
System.out.println("MyBean.MyBean(String id, String clazz)");
this.id = id;
this.clazz = clazz;
}
public String getId() {
System.out.println("MyBean.getId");
return id;
}
public MyBean setId(String id) {
System.out.println("MyBean.setId");
this.id = id;
return this;
}
public String getClazz() {
System.out.println("MyBean.getClazz");
return clazz;
}
public MyBean setClazz(String clazz) {
System.out.println("MyBean.setClazz");
this.clazz = clazz;
return this;
}
@Override
public boolean equals(Object o) {
System.out.println("MyBean.equals");
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyBean myBean = (MyBean) o;
return Objects.equals(id, myBean.id) &&
Objects.equals(clazz, myBean.clazz);
}
@Override
public int hashCode() {
System.out.println("MyBean.hashCode");
return Objects.hash(id, clazz);
}
@Override
public String toString() {
System.out.println("MyBean.toString");
return "MyBean{" +
"id='" + id + '\'' +
", clazz='" + clazz + '\'' +
'}';
}
}
添加dom4j坐标依赖
<!-- dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!-- XPath -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
准备自定义配置文件
spring.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id="userService" class="com.sdf.service.UserService"></bean>
</beans>
定义Bean工厂接口
package com.sdf.factory;
public interface MyFactory {
public Object getBean(String id);
//通过id值来获取对象
}
定义Bean接口的实现类
package com.sdf;
import com.sdf.javabean.MyBean;
import org.dom4j.io.SAXReader;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.core.ResolvableType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.*;
import java.net.URL;
public class MyClassPathXmlApplicationContext implements BeanFactory {
//实例化后的对象放入Map
private Map beans = new HashMap();
//存放已读取bean配置信息
private List<MyBean> myBeans;
//空构造
public MyClassPathXmlApplicationContext() {
}
//1.通过构造器得到相关配置信息
public MyClassPathXmlApplicationContext(String fileName){
//2.通过dom4j解析xml文件,得到List
//存放id和class
this.parseXml(fileName);
//3.通过反射实例化得到对象Class.forname(类路径).newInstance();
//通过Map存储
this.instanceBean();
}
private void parseXml(String fileName) {
// 1、获取解析器
SAXReader reader = new SAXReader();
// 2、得到配置文件的URL
URL url = this.getClass().getClassLoader().getResource(fileName);
try {
// 3、通过解析器解析xml文件(spring.xml)
Document document = reader.read(url);
// 4、通过xpath语法,获取beans标签下的所有bean标签
XPath xPath = document.createXPath("beans/bean");
// 通过指定语法解析文档对象,返回集合
List<Element> list = xPath.selectNodes(document);
// 判断集合是否为空,遍历集合
if (list != null && list.size() > 0) {
myBeans = new ArrayList<>();
for(Element el : list) {
// 获取标签元素中的属性
String id = el.attributeValue("id"); // id 属性值
String clazz = el.attributeValue("class"); // class 属性值
System.out.println(el.attributeValue("id"));
System.out.println(el.attributeValue("class"));
// 得到Bean对象
MyBean bean = new MyBean(id, clazz);
// 将Bean对象设置到集合中
myBeans.add(bean);
}
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
private void instanceBean() {
// 判断bean集合是否为空,不为空遍历得到对应Bean对象
if (myBeans != null && myBeans.size() > 0) {
for (MyBean bean : myBeans) {
try {
// 通过类的全路径实例化对象
Object object = Class.forName(bean.getClazz()).newInstance();
// 将id与实例化对象设置到map对象中
beans.put(bean.getId(), object);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Override
public Object getBean(String s) throws BeansException {
Object object = beans.get(s);
return object;
}
@Override
public <T> T getBean(String s, Class<T> aClass) throws BeansException {
return null;
}
@Override
public Object getBean(String s, Object... objects) throws BeansException {
return null;
}
@Override
public <T> T getBean(Class<T> aClass) throws BeansException {
return null;
}
@Override
public <T> T getBean(Class<T> aClass, Object... objects) throws BeansException {
return null;
}
@Override
public <T> ObjectProvider<T> getBeanProvider(Class<T> aClass) {
return null;
}
@Override
public <T> ObjectProvider<T> getBeanProvider(ResolvableType resolvableType) {
return null;
}
@Override
public boolean containsBean(String s) {
return false;
}
@Override
public boolean isSingleton(String s) throws NoSuchBeanDefinitionException {
return false;
}
@Override
public boolean isPrototype(String s) throws NoSuchBeanDefinitionException {
return false;
}
@Override
public boolean isTypeMatch(String s, ResolvableType resolvableType) throws NoSuchBeanDefinitionException {
return false;
}
@Override
public boolean isTypeMatch(String s, Class<?> aClass) throws NoSuchBeanDefinitionException {
return false;
}
@Override
public Class<?> getType(String s) throws NoSuchBeanDefinitionException {
return null;
}
@Override
public Class<?> getType(String s, boolean b) throws NoSuchBeanDefinitionException {
return null;
}
@Override
public String[] getAliases(String s) {
return new String[0];
}
}
测试自定义IOC容器
创建与配置文件中对应的Bean对象
准备UserService.java
public class UserService {
public void test(){
System.out.println("UserService.test");
}
}
准备AccountService.java
package com.sdf.service;
public class AccountService {
public void test(){
System.out.println("AccountService.test");
}
}
测试是否可以获取实例化的Bean对象
package com.sdf;
import com.yjxxt.spring.MyFactory;
import com.yjxxt.spring.MyClassPathXmlApplicationContext;
import com.yjxxt.service.AccountService;
import com.yjxxt.service.UserService;
public class App {
public static void main(String[] args) {
MyFactory factory = new
MyClassPathXmlApplicationContext("spring.xml");
// 得到实例化对象
UserService userService = (UserService) factory.getBean("userService");
userService.test();
UserService userService2 = (UserService) factory.getBean("userService");
System.out.println(userService+"=====" + userService2);
AccountService accountService (AccountService)factory.getBean("accountService");
accountService.test();
}
}
Spring容器在启动时读取xml信息,并对配置的Bean进行实例化(仅供理解),同时通过上下文对象提供的getBean()方法拿到我们配置的Bean对象,从而实现外部容器自动化维护并创建Bean效果。
4)、Spring IOC 配置文件加载
根据相对路径加载资源
Application ac = new ClassPathXmlApplicationContext("spring.xml");
根据绝对路径加载资源
Application ac = new FileSystemXmlApplicationContext("S:/d/f/3/4/5/1/9/9/9/IdeaWorkspace/spring01/src/main/resources/spring.xml");
Spring多配置文件加载
Spring框架启动时可以加载多个配置文件到环境中。
对于比较复杂的项目,可能对应的配置文件有多个,项目在启动部署时会将多个配置文件同时加载到进程中。
service.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">
<bean id="userService" class="com.xxxx.service.UserService"></bean>
</beans>
dao.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">
<bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
</beans>
可变参数,可传入多个文件名
//可同时加载多个资源文件
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml","dao.xml")
通过总的配置文件导入其他配置文件
spring.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">
<!--导入需要包含的资源文件-->
<import resource="service.xml"/>
<import resource="dao.xml"/>
</beans>
加载时只需要加载总配置文件即可
//加载总的资源文件
Application ac = new ClassPathXmlApplicationContext("spring.xml");
5)、Spring IOC 注入
- set方法注入
- 构造器注入
- 静态工厂注入
- 实例化工厂注入
开发项目中首选set方式注入。
@Autowired注解实现自动化注入:
默认通过类型(Class类型)查找Bean对象
与属性字段的名称无关
属性可以提供set方法,也可不提供
注解可以声明在属性级别或set方法级别
可以添加@Qualifier结合使用,通过value属性值查找bean对象
(value属性值必须要设置,且值要与bean标签的id属性值对
应)
@Autowired 与 @Resource的区别
- @Autowired 来自 Spring框架,@Resource 来自 javax包
- @Autowired 根据类型装配,@Resource根据名称装配
- 一般@Autowired若遇到同一类型的数据不唯一,可以使用@Qualifier(value="")指定具体的对象名称
- @Resource根据名称装配,若根据名称有多个类型的对象,可指定具体的对象
6)、Spring IOC 扫描器
作用:bean对象通用进行管理,简化开发配置,提高开发效率
使用:
1.设置自动化扫描的范围
如果bean对象未在指定包范围,即使声明的注解,也无法实例化
2.使用指定的注解(声明在类级别)
bean对象的id属性默认是类名首字母为小写的类
Dao层:@Reposition
Service层:@Service
Controller层:@Controller
任意类:@Component
注意:
开发时建议按照指定规则声明注解
7)、Bean的作用域
- singleton作用域
- prototype作用域
8)、Bean的生命周期
- 容器启动装载并实例化servlet类
- 初始化Servlet
- 调用Servlet方法
- 销毁Servlet