第一章、Spring框架的介绍
1. 自定义Bean工厂解耦
知识补充:
JDK的类:
java.util.ResourceBundle:专门用来读取bean.properties
方法:
(1) ResourceBundle类静态方法 getBundle(配置文件名)返回本类对象
(2) ResourceBundle对象的方法getString(配置文件的键)返回值
方法测试demo
public static void main(String[] args) { //读取bean.properties //JDK的类,java.util.ResourceBundle 专门对付bean.properties //ResourceBundle类静态方法 getBundle(配置文件名)返回本类对象 ResourceBundle bundle = ResourceBundle.getBundle("bean"); //bundle对象的方法getString(配置文件的键)返回值 String userService = bundle.getString("UserService"); System.out.println("userService = " + userService); }
(1)dao层
public interface UserDao {
} public class UserDaoImpl implements UserDao {
}
(2)service层
public interface UserService {
} public class UserServiceImpl implements UserService { }
(3)bean工厂类
/* BeanFactory:读取配置文件,创建对象 * */ public class BeanFactory implements Serializable { /* 定义静态方法,传递接口类型,传递接口的class对象 返回个接口的实现类对象 Class<T> clazz 传递接口的Class对象,泛型T就是接口类型 * */ public static <T> T getInstance(Class<T> clazz){ T obj = null; try { ResourceBundle bundle = ResourceBundle.getBundle("bean"); //传递键获取值,一个类的全路径名 //Class类的方法,getSimpleName,获取class对象的类的简称 String string = bundle.getString(clazz.getSimpleName()); //反射创建对象 Class cla = Class.forName(string); obj = (T)cla.newInstance(); } catch (Exception e) { e.printStackTrace(); } return obj; } }
(4)bean.properties文件
UserService=com.atguigu.service.impl.UserServiceImpl
UserDao=com.atguigu.dao.impl.UserDaoImpl
(5)测试类
public class MainTest { @Test public void testMyIOC() { //调用BeanFactory的静态方法getInstance(接口名) 返回实现类对象 UserService userService = BeanFactory.getInstance(UserService.class); System.out.println("userService = " + userService); UserDao instance = BeanFactory.getInstance(UserDao.class); System.out.println("instance = " + instance); } }
第二章、SpringIOC
1. IOC容器的概念和作用
(1)概念:inverse of control (反转控制/控制反转),我们之前在一个java类中通过new的方式去引入外部资源(其他类等),这叫正向;现在Spring框架帮我们去new,你什么时候需要你去问Spring框架要,这就是反转(创建对象权利的一个反转)
(2)作用:IOC解决程序耦合问题
2. IOC容器的使用
(1)导入Spring框架依赖的jar包
<!-- 添加spring框架的jar context:上下文,框架核心包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.6.RELEASE</version> </dependency>
(2)定义类
package com.atguigu.ioc; /* HappyComponent 类的对象,放在Spring框架的IOC容器中存储 IOC:控制反转() * */ public class HappyComponent {public void doWork() { System.out.println("component do work ..."); } }
(3)放进IOC容器中
标签名字:<bean>
属性: id :这个对象的唯一标识
class:配置的类的全类名
scope:对象的作用域,spring框架的对象容器中对象的作用域是两个单例模式(默认)和多例模式。
scope="singleton" 单例模式的配置
scope="prototype" 多例模式的配置
注意:
-
singleton:默认值,单例,项目全局内存中只有一个对象,一般在使用Spring的时候保持默认值即可
-
prototype:原型的意思,在这里是多例,每引用或者getBean一次,Spring框架就返回一个新的对象,比如SqlSession这个特殊的对象
<!-- 配置HappyComponent类的对象,放在对象容器中 --> <bean id="happyComponent" class="com.atguigu.ioc.HappyComponent" scope="singleton"></bean>
(4)通过IOC容器获取对象(不强转)
@Test public void testSpringIOCNoCast(){ ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); //方式一:context对象的方法,获取容器中的对象:getBean(要获取的对象的类的class对象) HappyComponent happyComponent = context.getBean(HappyComponent.class); happyComponent.doWork(); //方式二:getBean("配置文件中的id属性值",要获取的对象,类的class对象) //HappyComponent happyComponent1 = context.getBean("happyComponent", HappyComponent.class); //happyComponent1.doWork(); }
注意:SpringIOC对象容器的本质:Map集合ConcurrentHashMap
(5)IOC容器中的生命周期
init-method="initMethod" destroy-method="destroyMethod"
- init-method:对象初始化调用的方法
- destroy-method:对象销毁之前调用的方法
(5-1)HappyComponent类中添加两个方法initMethod()、destory()
public class HappyComponent { /* 自己定义方法:声明周期的初始化方法 initMethod() Spring框架创建对象,调用方法 initMethod * */ public void initMethod(){ System.out.println("对象初始化方法"); } public void destory(){ System.out.println("对象销毁的方法"); } public void doWork() { System.out.println("component do work ..."); } }
(5-2) ApplicationContext.xml文件中添加调用初始化、销毁方法的属性
<!-- 配置对象的生命周期: 属性:init-method,配置方法名即可 属性:destory-method,配置方法名即可 --> <bean id="happyComponent" class="com.atguigu.ioc.HappyComponent" scope="singleton" init-method="initMethod" destroy-method="destory"></bean>
(5-2)测试方法
销毁方法,只有销毁ApplicationContext对象才会销毁
@Test public void testSpringIOCLife(){ ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); HappyComponent happyComponent = context.getBean(HappyComponent.class); happyComponent.doWork(); //销毁容器中的对象,关闭容器 ClassPathXmlApplicationContext context1 =(ClassPathXmlApplicationContext) context; context1.close(); }
第三章、依赖注入(DI)
- dependency Inject(依赖注入的意思)
- IOC和DI的区别
(1) IOC和DI是一个事情,只是描述的角度不同
(2) DI 是 IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器的资源注入。相对于IOC而言,这种表述更直接。
- 结论是:IOC 就是一种反转控制的思想, 而 DI 是对 IOC 的一种具体实现。
1. set方法注入
(1)创建对象(get和set方法用lombok插件代替)
@Data public class HappyComponent { private String componentName; }
(2)将对象注入spring中
<!-- 配置对象,放在spring框架IOC容器中 利用set方法,为componentName字段赋值 bean标签的子标签:property 为字段赋值 property标签的属性:name set方法名,去掉set字母,字母小写 property标签的属性:value 字段值 --> <bean id="happyComponent" class="com.atguigu.ioc.HappyComponent"> <property name="componentName" value="张三"/> </bean>
(3)测试依赖注入,set方法注入
@Test public void testDiSet(){ ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); HappyComponent happyComponent = context.getBean(HappyComponent.class); System.out.println("componentName = " + happyComponent.getComponentName()); }
2. set方法注入——讲一个对象作为另一个对象的一个字段注入
(1)创建对象
@Data public class HappyMachine { private String machineName; //将HappyComponent对象作为该对象的一个属性 private HappyComponent happyComponent; }
(2)讲对象注入spring中
<!-- 为一个类的字段,注入另一个类的对象的时候,property标签不能使用value属性 使用另个一个属性 ref = '另一个对象的id值' --> <bean id="machine" class="com.atguigu.ioc.HappyMachine"> <property name="machineName" value="Java虚拟机"/> <property name="happyComponent" ref="happyComponent"/> </bean> <bean id="happyComponent" class="com.atguigu.ioc.HappyComponent"> <property name="componentName" value="张三"/> </bean>
(3)测试
/* 测试一个类型,作为另一个类型的字段出现 set方法注入 * */ @Test public void testDiSet2(){ ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); HappyMachine happyMachine = context.getBean(HappyMachine.class); System.out.println("happyMachine = " + happyMachine); }
3. 构造方法注入
(1)创建类
@Data @AllArgsConstructor @NoArgsConstructor public class Person { private Integer id; private Double money; private String name; }
(2)将Person对象注入Spring配置文件中
<!-- 配置Person对象 构造方法:将数据,注入到类的字段中 标签:constructor-arg name属性:表示构造方法的参数名 --> <bean class="com.atguigu.ioc.Person" id="person"> <constructor-arg name="id" value="1"/> <constructor-arg name="money" value="199.0"/> <constructor-arg name="name" value="王五"/> </bean>
(3)测试
/* 测试依赖注入 构造方法 * */ @Test public void DiConstructor(){ ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); Person person = context.getBean(Person.class); System.out.println("person = " + person); }
4. 特殊值的注入处理
null值
(1)创建类
@Data public class ValueClass { private String commonValue; }
(2)指定commonValue字段为控制
<bean class="com.atguigu.ioc.ValueClass" id="valueClass"> <!--set方法注入数据,字段名commonValue 赋值特殊值,null 常量--> <property name="commonValue"> <null/> </property> </bean>
(3)测试,结果报空指针异常
@Test public void testDiValue(){ ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); ValueClass valueClass = context.getBean(ValueClass.class); boolean b = valueClass.getCommonValue().equals("abc"); System.out.println(b);//报空指针异常 }
5. 复杂数据类型的注入(数组、List、Set、Map、Properties)
(1)创建类
@Data public class ComplexValue { private String[] myStrs; private List<String> myList; private Set<String> mySet; private Map<String,String> myMap; private Properties myPro; }
(2)讲对象注入Spring配置文件中
<!-- 配置对象ComplexValue:对象中字段进行数据注入 字段都是容器 --> <bean class="com.atguigu.ioc.ComplexValue" id="complexValue"> <!--set方法注入--> <property name="myStrs"> <!--输入数组,property标签子标签 array 输入的数据是数组容器--> <array> <!--注入数组元素--> <value>java</value> <value>c++</value> <value>mysql</value> <value>Machine</value> </array> </property> <!--注入list集合--> <property name="myList"> <list> <value>java - list</value> <value>C++ - list</value> <value>python - list</value> <value>c - list</value> </list> </property> <!--注入set集合,set集合是不重复元素--> <property name="mySet"> <!--property的子标签 set--> <set> <value>a</value> <value>b</value> <value>c</value> <value>d</value> </set> </property> <!--注意Map集合--> <property name="myMap"> <map> <!-- Map子标签 entry entry标签的属性 key = Map的键 entry标签的属性 value = Map的值 --> <entry key="Eden" value="伊甸园"/> <entry key="survivor0" value="幸存者0"/> <entry key="survivor1" value="幸存者1"/> </map> </property> <!--注入Properties集合,Map的实现类,键值对,无序的哈希表,线程安全--> <property name="myPro"> <!--property子标签props--> <props> <!-- prop配置单个键值对 --> <prop key="Eden">伊甸园</prop> <prop key="survivor0">幸存者0</prop> <prop key="survivor1">幸存者1</prop> </props> </property> </bean>
(3)测试
补充知识点:
Properties类
方法:Set<String> stringPropertyNames():返回此属性列表中的键集
String getProperty(String key):根据键返回值
/* 测试依赖注入,输入数组容器 * */ @Test public void testDiArray(){ ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); ComplexValue complexValue = context.getBean(ComplexValue.class); //测试依赖注入,输入数组容器 String[] myStrs = complexValue.getMyStrs(); for (String s : myStrs) { System.out.println("s = " + s); } //测试依赖注入,注入List集合 List<String> myList = complexValue.getMyList(); System.out.println("myList = " + myList); //测试依赖注入,注入Set集合 Set<String> mySet = complexValue.getMySet(); System.out.println("mySet = " + mySet); //测试依赖注入,注入Map集合 Map<String, String> myMap = complexValue.getMyMap(); System.out.println("myMap = " + myMap); //测试依赖注入,注入Properties Properties myPro = complexValue.getMyPro(); System.out.println("myPro = " + myPro); //myPro集合对象stringPropertyNames() 将集合的键,存储到Set集合 == Map的方法keySet() Set<String> set = myPro.stringPropertyNames(); for (String s : set) { String property = myPro.getProperty(s); System.out.println(s+" = " + property); } }
(4)运行结果
s = java s = c++ s = mysql s = Machine myList = [java - list, C++ - list, python - list, c - list] mySet = [a, b, c, d] myMap = {Eden=伊甸园, survivor0=幸存者0, survivor1=幸存者1} myPro = {survivor0=幸存者0, survivor1=幸存者1, Eden=伊甸园} survivor0 = 幸存者0 survivor1 = 幸存者1 Eden = 伊甸园
第四章、Schema约束
对于xml的新型约束,控制xml该怎么写。常用的约束有DTD,和Schema,Schema逐步取代DTD
官方约束:显示约束文档xsd怎么写,xsd限制我们自己定义的xml
- Schema约束支持命名空间namespace,就是java中的import导包
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:a="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"> <!-- 命名空间:xmlns = xml namespace 命名空间 http://www.springframework.org/schema/beans 命名空间的名字 具有全球唯一性 Schema官方约束: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 :命名空间对应的约束文件地址 写的任何标签,都是来自于命名空间 http://www.springframework.org/schema/beans 对应的约束文件 spring-bean.xsd --> </beans>