Spring5学习笔记
Spring5学习笔记2.0
第1章 引言
- 工厂模式
第2章、第一个Spring程序
1 软件版本
1.JDk1.8+
2.Manven3.5+
3.IDEA2020
4.SpringFramework5.14
2 环境搭建
- spring的jar包
#利用Manven来管理jar包 设置pom文件
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
- spring的配置文件
1.配置文件的位置:没有硬性要求
2.配置文件的名称:没有硬性要求,建议使用appLicationContext.xml
3.Spring的核心API
-
AppLicationContext(工厂接口)
1.作用:Spring提供ApplicationContext工厂,用于对象的创建 2.好处:解耦合
-
AppLicationContext接口的两个实现类:
1.为什么使用接口:屏蔽实现的差异 2.非web环境:ClassPathXmlAppLicationContext 3.web环境:XmlWebApplicationContext
-
重量级资源
1 ApplicationContext的工厂对象占用大量内存 2 不会频繁的创建该对象:一个应用只创建一个工厂对象 3 ApplicationContext工厂:是线程安全的
-
源码:可以看出是个ApplicationContext接口
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { }
4.程序开发
-
1.创建类型
2.配置applicationContext.xml文件
[id:唯一] [class:全限定路径名]
3.通过工厂类来获取对象
//1.获取spring的工厂
ApplicationContext context = new ClassPathXmlApplicationContext("/appLicationContext.xml");
//2.通过工厂获取对象
Person person = context.getBean(“person”, Person.class);
### 5. 细节分析
- 名词解释:
Spring工厂创建的对象叫做bean或者叫作组件(componet)
- Spring工厂中的常用方法:
~~~markdown
1 context.getBeanDfinitionNames()//返回配置文件中所有bean标签的id值
2 context.getBeanNameForType(类名.class)//返回配置文件中所有指定类型的bean的id值
3 context.containsBeanDfinition("Stirng")//判断是否存在指定id的bean
4 context.containsBean("String")//判断是否存在指定id或者name(别名)的bean
-
配置文件中需要注意的细节
-
只配置class属性时
<bean class="String"/>
a). Spring会为bean提供一个默认的id值
b). 一般在bean只被调用一次时采用这种方式配置
-
name属性
-
作用:作为bean对象的别名
<bean name="String"/>
-
于id属性的区别:
a) 一个bean只能有一个id属性,但是可以定义多个name属性
b) xml的id命名只能以字母开头
-
-
6.Spring工厂的底层实现原理
图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KYpO07Kk-1620127891248)(C:\Users\Hooker\Pictures\Spring截图\spring原理图.PNG)]
7 思考
问:所有的对象都需要交给Spring工厂来创建吗?
答:理论上是的,但是实体对象(entity)例外,它交由持久层创建,因为它牵涉到数据库
第三章、Spring5与日志框架整合
1.为什么要整合日志框架?
Spring整合日志框架后,在程序运行时就可以在控制台中输出Spring的重要信息!
2.好处:
便于了解Spring的运行过程,利于调试
3.Spring如何整合日志框架?
1.引入log4j的jar包
<!--日志jar包-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
2 引入log4j.properties的配置文件
#该文件需要放置在resources文件夹根目录下
#配置根
log4j.rootLogger = debug , console
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Layout = org.apache.log4j.PatternLayout
log4j.appender.console.Layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5-p %c{1}:%L - %m%n
第四章、注入(injection)
1.什么是注入?
1.通过Spring工厂及配置文件,为所创建的对象的成员变量赋值的过程就叫作注入。
2.为什么需要注入?
因为通过代码编码的方式进行赋值在耦合1
3.如何进行注入?【开发步骤】
1 创建类成员变量的get和set方法。
2 配置Spring的配置文件<property name="id"></property>
4. 注入的好处
解耦合(从配置文件修改属性的值,不需要重新编译)
5.Spring注入的原理
Spring通过解析配置文件,然后调用类中的set()方法来完成成员变量的赋值。
图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0WChq2gg-1620127891250)(C:\Users\Hooker\Pictures\Spring截图\spring注入原理.PNG)]
第五章、set注入
1.不同类型的成员变量的set注入:
图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9LPIZUUi-1620127891252)(C:\Users\Hooker\Pictures\Spring截图\类型注入图.PNG)]
2.JDK内置类型的set注入
2.2 String+8种基本数据类型 的set注入
<!--value可以写在标签内也可以写在标签体之间-->
<property name="id">
<value>10</value>
</property>
<property name="name" value="张三"></property>
2.3 数组 的set注入
<!--数组-->
<property name="emails">
<list>
<value>[email protected]</value>
<value>[email protected]</value>
</list>
</property>
2.4 Set集合 的set注入
<!--Set集合-->
<property name="tels">
<set>
<value>1234567</value>
<value>1342424</value>
</set>
</property>
2.5 List集合的set注入
<!--List集合-->
<property name="emails">
<list>
<value>[email protected]</value>
<value>[email protected]</value>
</list>
</property>
2.6 Map集合的set注入
<!--Map集合-->
<property name="qqs">
<map>
<entry>
<key><value>大号</value></key>
<value>1234567</value>
</entry>
<entry>
<key><value>小号</value></key>
<value>3131324</value>
</entry>
</map>
</property>
2.6 Properties类型的set注入(特殊的Map)
<property name="p">
<props>
<prop key="这是key1">这是值1</prop>
<prop key="这是key2">这是值2</prop>
</props>
</property>
3.用户自定义类型的set注入
3.1 第一种方式:
-
为成员变量提供get(),set()方法
-
在bean标签中嵌套一个bean
<bean id="userService" class="com.it.basic.UserServiceImpl"> <property name="userDao"> <bean class="com.it.basic.UserDaoImpl"></bean> </property> </bean>
3.2 第二种方式:
- 把嵌套的bean单独提取出来 避免了重复创建bean对象
<!--先创建一个bean-->
<bean id="userDao" class="com.it.basic.UserDaoImpl"/>
<!--通过ref标签引用外部bean-->
<bean id="userService" class="com.it.basic.UserServiceImpl">
<property name="userDao">
<ref bean="userDao"/>
</property>
</bean>
3.3 Set注入的简化写法
- 基于命名空间p的简化写法(p => property)
<bean id="person" class="com.it.basic.Person" p:id="001" p:name="tom"/>
<bean id="userDao" class="com.it.basic.UserDaoImpl"/>
<bean id="userService" class="com.it.basic.UserServiceImpl" p:userDao-ref="userDao"/>
第六章、构造注入
- 注入:通过Spring的xml文件为成员变量赋值
- Set注入:Spring调用set()方法,通过解析xml文件为成员变量赋值
- 构造注入:Spring调用构造方法,通过配置文件为成员变量赋值
1.构造注入的开发步骤:
- 提供有参构造方法
public class Customer implements Serializable {
private String name;
private int age;
//有参构造函数
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
]
- 配置xml文件
<bean id="customer" class="com.it.basic.constructor.Customer">
<!--一个constructor代表一个参数-->
<constructor-arg index="0" value="tom"/>
<constructor-arg index="1" value="18"/>
</bean>
2.构造方法重载
- 参数个数相同
通过控制<constructor-arg>标签的数量来区分
- 参数个数不相同
通过在标签引入type标签来区分:<constructor-arg type="">
3.注入总结
图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3vU0eawT-1620127891254)(C:\Users\Hooker\Pictures\Spring截图\注入总结.PNG)]
第七章、反转控制与依赖注入
1.反转控制IOC(Inverse Of Control)
1.控制:对成员变量赋值的控制权
2.反转控制:把对成员变量赋值的控制权从代码中转移到Spring工厂和配置文件中完成
3.好处:解耦合
4.底层实现原理:工厂设计模式
图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xh254yYl-1620127891256)(C:\Users\Hooker\Pictures\Spring截图\反转控制原理.PNG)]
2.依赖注入DI (Dependency Injection)
1.注入:通过Spring配置文件对成员变量进行赋值
2.依赖注入:当一个类需要另一个类时,就意味着依赖,一旦出现依赖,就可以把另一个类当作本类的成员变量,最终通过Spring配置文件赋值
3.好处:解耦合
举例:
//UserService类中需要将UserDao类作为自己的成员变量,因此二者为依赖关系
public class UserServiceImpl implements UserService{
private UserDao userDao;
}
第八章、Spring工厂创建复杂对象
1.什么是复杂对象?
复杂对象就是指不能直接通过new来创建的对象
图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUzOPw8O-1620127891257)(C:\Users\Hooker\Pictures\Spring截图\复杂对象和简单对象.PNG)]
2.Spring工厂创建复杂对象的3种方式
(1)FanctoryBean接口
-
开发步骤
- 实现FanctoryBean接口
图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mRjMxKkO-1620127891258)(C:\Users\Hooker\Pictures\Spring截图\FanctoryBean接口.PNG)]
代码:
public class ConnectionFactoryBean implements FactoryBean<Connection> { //用于书写复杂对象的代码 public Connection getObject() throws Exception { Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","152316"); return conn; } //用于返回所创建复杂对象的Class对象 public Class<?> getObjectType() { return Connection.class; } //返回ture只创建一个这种类型的对象 //返回false每次都创建新的复杂对象 public boolean isSingleton() { return false; } }
- Spring配置文件的配置
#如果class中指定的类 是FactoryBean接口的实现类 那么通过id值获取的对象是该类创建的复杂对象 Connection <bean id="conn" class="com.it.factorybean.ConnectionFactoryBean"/>
-
开发细节
- 如果想要获取FactoryBean对象 ,则需要在类名前加一个”&“ getBean("&conn")
//获取的是Connection对象 Connection connection = context.getBean("conn",Connection.class); //获取的是ConnectionFactoryBean对象 ConnectionFactoryBean connectionFactoryBean = context.getBean("&conn",ConnectionFactoryBean.class);
- 解决Mysql高版本连接创建时,需要定制SSL证书的问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ShmZkzia-1620127891259)(C:\Users\Hooker\AppData\Roaming\Typora\typora-user-images\image-20201023155625414.png)]
//将URl改为 url="jdbc:mysql://localhost:3306/test?useSSL=false","root","root"
- 把ConnnectionFactoryBean中依赖的字符串信息 改为Spring文件的注入
<bean id="conn" class="com.it.factorybean.ConnectionFactoryBean"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"/> <property name="username" value="root"/> <property name="password" value="152316"/> </bean>
-
FactoryBean的实现原理(接口回调)
1.为什么Spring规定创建复杂对象需要实现FactoryBean接口 并且要将实现的代码写在getObject()方法中?
2.为什么context.get("bean")获得的是复杂对象Connection 而没有获得ConnectionFactoryBean对象?
Spring内部实现流程:
1.通过conn获取ConnectionFactoryBean对象 然后通过instanceof来判断该对象是否是FactoryBean接口的实现
2.如果是,则调用其中getObject()方法创建Connection
3.返回Connection
图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7iqcR7dX-1620127891259)(C:\Users\Hooker\Pictures\Spring截图\FactoryBean接口实现原理.PNG)]
-
FactoryBean的总结
Spring原生提供的一种创建复杂对象的方式,在之后整合其他框架时将大量使用
(2)实例工厂
- 作用
1.避免Spring框架的侵入
2.整合遗留系统
- 开发步骤
<!--代表遗留下来的Connection-->
<bean id="connectionFactory" class="com.it.factorybean.ConnectionFactory"/>
<!--重新整合-->
<bean id="conn" factory-bean="connectionFactory" factory-method="getConnection"/>
(3)静态工厂
- 开发步骤
在该类中创建一个静态方法
public class StaticConnectionFactory {
public static Connection getConnection(){
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","152316");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return conn;
}
}
配置Spring文件
<bean id="conn" class="com.it.factorybean.StaticConnectionFactory" factory-method="getConnection"/>
- Spring创建对象的总结
图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OQ2hyify-1620127891260)(C:\Users\Hooker\Pictures\Spring截图\Spring创建工厂总结.PNG)]
第九章、控制创建Spring工厂对象的次数
1.如何控制简单对象的创建次数
在bean标签中加入scope属性 控制对象的创建次数
<bean id="conn" scope="prototype或者singleton" class="XX"/>
singleton:只创建一次简单对象(如果没有为scope赋值 默认是singleton)
prototype:每一次都会创建新的对象
2.如何控制复杂对象的创建次数
用FactoryBean中的isSingleton()方法来控制
//返回ture只创建一个这种类型的对象
//返回false每次都创建新的复杂对象
public boolean isSingleton() {
return false;
}
3.为什么要控制对象的创建次数?
避免对象的重复创建,节省内存空间
- 什么样的对象只创建一次
能被公用 线程安全的
1. sqlSessionFactory
2. DAO
3. Service
- 什么样的对象要创建多次
不能被公用 线程不安全的
1. Connection
2. sqlSession | Session
3. Struts2 Action
第十章、对象(bean)的生命周期
1.什么是对象的生命周期
指的是一个对象创建、存活、消亡的一个完整过程
2.Spring Bean生命周期的三个阶段
-
创建
-
当scope=”singleton“时
Spring工厂创建的同时,创建对象 <bean id="product" scope="singleton" class="com.it.life.Product" /> 如果要在获取对象时才创建需要加上一个lazy-init属性 <bean id="product" scope="singleton" class="com.it.life.Product" lazy-init="true"/>
-
当scope="prototype"时
Spring工厂在获取对象的同时,创建对象 <bean id="product" scope="prototype" class="com.it.life.Product"/> context.getBean()//获取对象
-
-
初始化
Spring工厂在创建完对象后,调用对象的初始化方法,完成初始化工作 注: 1. 初始化方法由程序员提供 2. 由Spring工厂调用 3. 资源的初始化:数据库、IO、网络...
-
方法一、实现InitializingBean接口
//2.Spring检测到实现了InitialiaingBean接口后调用这个方法 进行初始化工作 @Override public void afterPropertiesSet() throws Exception { //1.程序员根据需求实现这个方法,供Spring调用 }
-
方法二、对象中提供一个普通方法+配置文件
//定义一个普通方法 public void myInit(){ } <!--让Spring能识别出这是一个初始化方法--> <bean id="product" class="XXX" init-method="myInit"/>
-
细节:
1. 方法一的优先级高于方法二 2. 先注入后初始化(DI -> init)
-
-
销毁
当对象调用close()方法后 Spring会销毁对象
-
方法1:实现DisposableBean接口
//2.Spring调用销毁方法,销毁创建的对象 @Override public void destroy() throws Exception { //1.程序员定义销毁方法 }
-
方法2:自定义普通方法+Spring配置文件
public void myDestory(){ } <bean id="product" class="com.it.life.Product" destroy-method="myDestroy"/>
-
细节
销毁方法只适用于scope="singleton"的情况
-
-
图解Bean的生命周期
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-77rqzQc1-1620127891261)(C:\Users\Hooker\Pictures\Spring截图\Bean的生命周期.PNG)]
-
耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合 ↩︎