哈喽大家好,今天继续肝 Spring 框架,从最基础的环境、设计模式,一路冲到IoC 控制反转 和DI 依赖注入,全是干货,直接当笔记抄~
一、先搞懂:Spring 是什么?
- 轻量级、开源、JavaEE 一站式解决方案
- 核心目的:让 JavaEE 开发更简单
- 非侵入式、体积小、不挑运行环境
二、前置技能(必须会)
- JavaSE
- 数据库(MySQL/Oracle)
- Web 基础(HTML/JSP/Servlet)
- Maven
- 持久层框架(MyBatis/Hibernate 可选)
三、Spring 用到的核心设计模式
1. 工厂模式
作用:解耦,不用 new 对象,通过工厂反射创建
- 支持 properties 配置
- 支持 XML 配置
- 底层:反射 + 配置文件
- 我们只需要告诉工厂类我们需要的工件名,工厂就会给我们生产对应的工件,避免了硬编码
简单手写一个工厂模式:
这是读取xml文件的工厂模式,Spring源码中是通过获取set方法来进行属性赋值操作的,而我是通过field获取access权限之后,直接赋值的;
java
package com.djw.user;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
/**
* @author djw
*/
public class XMLBeanFactory {
public static Object getDaoImpl(String key){
SAXReader reader = new SAXReader();
try {
Document document = reader.read("D:\\workspace\\SpringFrameWork\\day01\\target\\classes\\bean.xml");
Element rootElement = document.getRootElement();
List<Element> elements = rootElement.elements();
for (Element element : elements) {
if(key.equals(element.attributeValue("id"))){
String clazz = element.attributeValue("class");
Class<?> aclass = Class.forName(clazz);
Object o = aclass.getConstructor().newInstance();
List<Element> elements1 = element.elements();
if(elements1.size() > 0){
for(Element e : elements1){
String s = e.attributeValue("name");
Field field = aclass.getDeclaredField(s);
field.setAccessible(true);
field.set(o,e.attributeValue("value"));
}
}
return o;
}
}
} catch (DocumentException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
return null;
}
public static void main(String[] args) {
Boy boy = (Boy) XMLBeanFactory.getDaoImpl("boy");
System.out.println(boy);
}
}
2. 单例模式
一个类只产生一个对象
- 饿汉式:类加载就创建
- 懒汉式:用到才创建
- Spring Bean默认单例
这里我也简单手搓了一个单例模式的例子
java
//饿汉模式
public class Sington {
private static Sington single = new Sington();
private Sington() {}
public static Sington getInstance() {
return single;
}
}
java
//懒汉模式
public class Singleton{
private static Singleton st = null;
private Singleton(){};
private getInstance(){
if(st==null){
st = new Singleton();
}
return st;
}
}
四、Spring 入门程序(标准步骤)
1. Maven 依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.15</version>
</dependency>
2. 编写 bean.xml
<beans ...>
<bean id="userDao" class="com.xzit.user.UserDaoJdbcImpl"></bean>
<bean id="userDao1" class="com.xzit.user.UserDaoMybatisImpl"></bean>
</beans>
3. 测试类(重点规范)
public class Test {
public static void main(String[] args) {
// 只在main/入口类加载Spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
// 从容器拿bean
UserDao dao = (UserDao) ctx.getBean("userDao1");
System.out.println(dao);
}
}
- Spring 容器(ApplicationContext)只在 main 方法、启动类等入口创建一次
- 业务类(Service/Dao)绝对不能出现 new ClassPathXmlApplicationContext
- 业务类需要对象,靠注入,不要自己拿容器
五、属性赋值(set 注入)
1. 基本类型
<bean id="boy" class="com.xzit.user.Boy">
<property name="name" value="李四"></property>
<property name="age" value="20"></property>
</bean>
2. 引用类型
<bean id="girl" class="com.xzit.user.Girl">
<property name="name" value="李某"></property>
</bean>
<bean id="boy" class="com.xzit.user.Boy">
<property name="girl" ref="girl"></property>
</bean>
六、核心:IoC & DI 到底啥意思?
1. IoC 控制反转
- 以前:自己
new UserDao()→ 自己控制对象生命周期 - 现在:对象交给 Spring 容器创建、管理
- 控制权:从程序员 → 反转给 Spring 容器
一句话:IoC 就是容器帮你管对象
2. DI 依赖注入
- 作用:给对象的属性自动赋值
- 方式:set 注入、构造注入、自动装配
- 前提:必须开启 IoC
一句话:DI 就是容器帮你自动填属性
七、DI 依赖注入(常用写法)
1. set 注入(最常用)
<property name="name" value="李四"></property>
<property name="girl" ref="girl"></property>
2. 构造方法注入
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="age" value="20"></constructor-arg>
3. 自动注入
-
byName:按属性名匹配 bean id
-
byType:按类型匹配(同类型只能有一个 Bean)
<bean id="student" class="com.xzit.auto.Student" autowire="byName"></bean>