spring学习笔记
第一章 引言
1、EJB(Enterprise Java Bean)的缺陷
-
运行环境苛刻
-
代码移植性差
总结:EJB是一个重量级的框架
2、什么是spring?
Spring是一个轻量级的JavaEE的解决方案,整合众多优秀的设计模式
-
轻量级:
1.对于运行环境是没有额外要求的,可以选择开源的服务器,也可以选择收费的服务器,运行在servlet引擎中;
2.代码移植性高:不需要实现额外的接口
-
JavaEE的解决方案:
整合设计模式:
1、 工厂设计模式
2、 代理设计模式
3、 模板设计模式
4、 策略设计模式
3、设计模式
-
广义概念:
面向对象设计中,解决特定问题的经典代码
-
狭义概念:
GOF4人帮定义的23中设计模式:工厂、适配器、装饰器、门面、代理、模板……
4、 工厂设计模式
4.1 概念:通过工厂类创建对象
-
好处:解耦合
-
耦合:指的是代码之间的强关联关系,一方改变会影响另一方
4.2 通用工厂的使用方式
4.2.1 定义类型(类)
4.2.2 通过配置文件的配置告知工厂
4.2.3 通过工厂获得类的对象
5、总结
- Spring的本质:工厂 ApplicationContext
第二章 spring
1、软件版本
1、jdk 1.8
2、Maven 3.5
3、idea
4、SpringFramework 5.1.4
官网:www.spring.io
2、环境搭建
-
spring的jar包
<!-- 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
- 作用:Spring提供的ApplicationContext这个工厂,用于对象的创建
- 好处:解耦合
- ApplicationContext接口类型
-
接口:屏蔽实现的差异
-
非web环境:ClassPathXmlApplicationContext(main junit)
-
web环境:XmlWebApplicationContext
-
- ApplicationContext接口类型
-
重量级资源
- ApplicationContext工厂的对象占用大量内存。
- 不会频繁的创建对象:一个应用只会创建一个工厂对象。
- ApplicationContext工厂:一定是线程安全的(多线程并发访问)
4、程序开发
-
创建类型
-
配置文件的配置 applicationContext.xml
-
通过工厂类,获得对象
-
ApplicationCOntext
- ClassPathXmlApplicationContext
2、ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
Person person = (person) ctx.getBean("person");
-
-
5、细节分析
- 名词解释
1、Spring工程创建的对象,叫做bean或者组件(component)
-
Spring工厂的相关方法
-
配置文件中需要注意的细节
-
只配置class属性 :
-
上述这种配置 有id值:com.baizhiedu.basic.Person#0
-
应用场景:如果这个bean只需要使用一次,那么就可以省略id值
如果这个bean会使用多次,或者被其他bean引用则需要设置id
-
-
name属性
-
作用:用于在Pring的配置文件中,为bean对象定义别名
-
相同:等效于id
-
区别:别名可以定义多个,但是id属性只能有一个值
containsBeanDefinition方法:不能判断name值,只能判断id值
containsBwan方法:不仅能判断name值,也能判断id值
-
-
6、Spring工厂的底层实现原理(简易版)
Spring工厂是可以调用对象私有的构造方法创造对象的
核心:
-
通过ClassPathXmlApplicationContext工厂读取配置文件apploicationContext.xml
-
获取bean标签的相关信息di的值、class的值;通过反射创建对象
- Clsss<?> clazz = Class.forName(class的值);
- id 的值 = clazz.newInstance();
-
反射创建对象底层一会调用对象自己的构造方法
第三章 Spring5.x与日志框架的整合
Spring与日志框架进行整合,日志框架就可以在控制台中,输出Spring框架运行过程中的一些重要的信息。
好处:便于了解Spring框架的运行过程, 利于程序的调试
-
Spring如何整合日志框架
默认
-
Spring1.2.3早期都是与commons-logging.jar
-
Spring5.x默认整合日志框架logback log4j2
Spring5.x整合log4j
-
引入log4j jar包
-
引入log4.properties配置文件
-
- pom
- log4j.properties
-
第四章 注入(injection)
1、什么是注入
-
通过Spring工厂及配置文件,为所创建对象的成员变量赋值
-
为什么需要注入
通过编码的方式,为成员变量进行赋值,存在耦合
-
如何进行注入
类的成员变量提供get、set方法
配置spring的配置文件
-
注入的好处
解耦合
-
2、Spring注入的原理分析(简易版)
- Spring通过底层调用对象属性对应的set方法,完成成员变量的赋值,这种方法也称之为set注入
第五章 set注入详解
1、针对不同类型的成员变量,在标签,需要嵌套其他标签
2、jdk内置类型
-
8种基本类型+String
- roy
-
数组
<property name="emails"> <list> <value>sun@hfja.com.cn</value> <value>ssafun@sfa.com.cn</value> <value>wet@sfwwr.com.cn</value> </list> </property> -
Set集合:无序、不可重复的
<property> <set> <value>111111</value> <value>222222</value> </set> </property> -
List集合:有序、可重复的
<property> <list> <value>111111</value> <value>222222</value> </list> </property> -
Map集合
<map> <entry> <key><value>name</value></key> <value>sun</value> </entry> <entry> <key><value>id</value></key> <value>1</value> </entry> </map> -
Properties
Properties类型,特殊的Map key=String ,value=String,值只能是String
<props> <prop key="key1">value1</prop> <prop key="key2">value2</prop> </props> -
复杂的jdk类型(Date)
需要自定义类型转换器
3、用户自定义类型
-
第一种方式
-
为成员变量提供set get方法
-
配置文件进行注入(赋值)
<bean id="userService" class="xxxx.UserServiceImpl"> <prpperty name="userDao"> <bean class="xxxx.UserServiceImpl"/> </property> </bean> -
-
第二种方式
-
第一种赋值方式存在的问题
-
配置文件代码冗余
-
被注入的对象(UserDao),多次创建,浪费(JVM)内存资源
- 为成员变量提供set get方法
- 配置文件中进行配置
<bean id="userDao" class="xxx.UserDaoImpl"></bean> <bean id="userService" class="xxx.UserServiceImpl"> <property name="userDao"> <ref bean="userDao"/> </property> </bean> -
-
Set注入的简化方法
- 基于属性简化
JDK类型注入 <property name="name"> <value>suns</value> </property> <property name="name" value="suns"> 注意:value属性只能简化8种基本类型+String 注入标签 用户自定义类型 <peoperty name="userDao"> <ref bean="userDao"> </peoperty> <property name="userDao" ref="userDao"/>2. 基金p命名空间简化JDK类型注入 <bean id="person" class="xxx.Person"> <property name="name"> <value>suns</value> </property> </bean> <bean id="person" class="xxx.Persom" p:name="suns"/> 注意:value属性 只能简化 8种基本类型+String 注入标签 用户自定义类型 <bean id="userService" class="xxxx.UserServiceImpl"> <property name="userDao"> <ref bean="userDao"> </property> </bean> <bean id="userService" class="xxxx.UserServiceImpl" p:userDao-ref="userDao"/>
第六章 构造注入
1、注入:通过Spring的配置文件,为成员变量赋值
2、Set注入:Spring调用Set方法,通过配置文件,为成员变量赋值
3、构造注入: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 ;
}
}
- Spring的配置文件
<bean id="costomer" class="xxxx.Customer">
<constructor-arg>
<value>suns</value>
</constructor-arg>
<constructor-arg>
<value>18</value>
</constructor-arg>
</bean>
2、构造方法重载
- 参数个数不同时
- 通过控制标签的数量进行区分
- 构造参数个数相同时
- 通过在标签引入type属性,进行类型的区分
3、注入的总结
- 未来实战中,应用set注入还是构造注入?
- 答案:set注入会更多
- 构造注入麻烦(重载)
- Spring框架底层 大量应用了 set注入
第七章 反转控制 与 依赖注入
1、反转(转移)控制(IOC--inverce of control)
-
控制:对于成员变量赋值的控制权
-
反转控制:把对于成员变量赋值的控制权,从代码中反转(转移)到Spring工厂和配置文件中
好处:解耦合
底层实现:工厂设计模式
2、依赖注入(Dependency Injecttion DI)
-
注入:通过Spring的工厂及配置文件,为对象(bean,组件)的成员变量赋值
-
依赖注入:当一个类需要另一个类时,就意味着依赖,一旦出现依赖,就可以把另一个类作为本类的成员变量,最终通过Spring配置文件进行注入(赋值)。
好处:解耦合
第八章 Spring工厂创建复杂对象
Spring工厂:
-
简单对象:指的就是可以直接通过new构造方法创建对象
- UserService
- UserDAO
- Customer
- Person
-
复杂对象:指的是不能直接通过new构造方法创建的对象
-
Connection
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection();
-
1、什么是复杂对象
- 复杂对象:指的就是不能直接通过new构造方法创建的对象
- Connection
- SqlSessionFactory
2、Spring工厂创建复杂对象的3种方式
2.1 FactoryBean接口
-
开发步骤
-
实现FactoryBean接口
public class ConnnectionFactoryBean implements FactoryBean{ @Override public Object getIbject() throws Exception{ } @Override public Class<?> getObjectType(){ } @Override public boolean isSingleton(){ } }
-
-
Spring配置文件的配置
# 如果Class中指定的类型是FactoryBean接口的实现类,那么通过id值获得的是这个类所创建的复杂对象 Connection <bean id="conn" class="com.xxxx.factorybean.ConnectionFactoryBean"/>
细节:
-
如果就像获得FactoryBean类型的对象 ctx.getBean("&conn")
获得就是ConnectionFactoryBean对象
-
isSingleton方法
- 返回true只会创建一个复杂对象
- 返回false每一次都会创建新的对象
- 问题:根据这个对象的特点,决定是返回true(SqlSessionFactory)还是false(Connection)
-
mysql共版本连接创建时,需要指定SSL证书,解决问题的方式
url = "jdbc:mysql://localhost:3306/suns?useSSL=false" -
依赖注入的体会(DI)
把ConnectionFactoryBean中依赖的4个人字符串信息,进行配置文件的注入 好处:解耦合 <bean id="conn" class="com.xxxx.factorybean.ConnectionFactoryBean"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/suns?useSSL=false"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean> -
FactoryBean的实现原理【简易版】
接口回调 1、为什么Spring规定FactoryBean接口 实现 并且getObject()? 2、ctx.getBean("conn")获得是复杂对象Connection而没有获得ConnectionFactoryBean Spring内部运行流程 1、通过conn获得ConnectionFactoryBean类的对象,进而通过instenceOf判断出是FactoryBean接口的实现类 2、Spring按照规定 getObject ---> Connection 3、返回Connection -
FactoryBean总结
Spring中用于创建复杂对象的一宗方式,也是Spring原生提供的,Spring整合其他框架,大量应用了FactoryBean
2.2 实例工厂
1、避免Spring框架的侵入
2、整合遗留系统
-
开发步骤
<bean id="connFactory" class="com.xxxx.factory.ConnectionFactory"></bean> <bean id="conn" factory-bean="connFactory" factory-method="getConnection"/>
2.3 静态工厂
-
开发步骤
<bean id="conn" class="com.xxxx.factoryBean.StaticConnectionFactory" factory-method="getConnection"/>
第九章 控制Spring工厂创建对象的次数
1、如何控制简单对象的创建次数
<bean id="account" scope="singleton|prorotype" class="xxxx.Account">
singleton:只会创建一次简单对象,默认值
prototype:每一次都会创建新的对象
2、如何控制复杂对象的创建次数
FactoryBean{
isSingleton(){
return true 只会创建一次
return false 每一次都会创建新的
}
}
如没有isSingleton方法 还是通过scope属性 进行对象创建次数的控制
3、为什么要控制对象的创建次数?
好处:节省不必要的内存浪费
-
什么样的对象只创建一次?
1、SqlSessionFactory 2、DAO 3、Service -
什么样的对象 每一次都要创建新的?
1、Connection 2、SqlSession | Session 3、Struts2 Action
第十章 对象的生命周期
1、什么是对象的生命周期
指的是一个对象创建、存活、消亡的一个完整过程
2、为什么要学习对象的生命周期
由Spring负责对象的创建、存活、销毁,了解生命周期,有利于我们使用好Spring为我们创建的对象
3、生命周期的3个阶段
-
创建阶段
Spring工厂何时创建对象-
scope="singlenton"
Spring工厂创建的同时,对象的创建 注意:设置scope="singlenton" 这种情况下,也需要在获取对象的同时,创建对象 <bean lazy-init="true"> 懒加载 -
scope="prototype"
Spring工厂会在获取对象的同时,创建对象 ctx.getBean("")
-
-
初始化阶段
Spring工厂在创建完对象后,调用对象的初始化方法,完成对应的初始化操作 1、初始化方法提供:程序员根据需求,提供初始化方法,最终完成初始化操作 2、初始化方法调用:Spring工厂进行调用-
InitializingBean接口
// 程序员根据需求,实现的方法,完成初始化操作 public void afterPropertiesSet(){ } -
对象中提供一个普通的方法
public void myInit(){ } <bean id="product" class="xxx.Product" init-method="myInit"/> -
细节分析
-
如果一个对象既实现InitializingBean ,同时又提供的普通初始化方法,顺序如何?
1.InitializingBean 2.普通初始化方法 -
注入一定发生在初始化操作的前面
-
什么叫做初始化操作
资源的初始化:数据库、IO、网络......
-
-
-
销毁阶段
Spring销毁对象前,会调用对象的销毁方法,完成销毁操作 1.Sprig什么时候销毁所创建的对象? ctx.close(); 2.销毁方法:程序员根据自己的需求,定义销毁方法,完成销毁操作 调用:Spring工厂完成调用-
DisposableBean
public void destory()throws Exception{ } -
定义一份普通的销毁方法
public void myDestroy()throws Exception{ } <bean id="" class="" init-method="" destory-method="myDestroy"/> -
细节分析
-
销毁方法的操作只适用于scope="singleton"
-
什么叫做销毁操作?
主要指的就是 资源的释放操作 io.close() connnection.close()
-
-
第十一章 配置文件参数化
把Spring配置文件中需要经常修改的字符串信息,转移到一个更小的配置文件中
1. Spring的配置文件中存在需要经常修改的字符串?
存在,以数据库连接相关的参数 代表
2. 经常变化字符串,在Spring的配置文件中,直接修改
不利于项目维护(修改)
3. 转移到一个小的配置文件(.properties)
利于维护(修改)
配置文件参数化:利于Spring配置文件的维护(修改)
1、配置文件参数化的开发步骤
-
提供一个小的配置文件(.properties)
名字:随便 放置位置:随变 jdbc.driverClassName = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/suns?useSSL=false jdbc.username = root kdbc.password = 123456 -
Spring的配置文件与小配置文件进行整合
applicationContext.xml <context:property-placeholder location="classpath:/db.properties"/> -
在Spring配置文件中通过${}获取小配置文件中对应的值
<!-- Spring配置文件与小配置文件的整合--> <context:property-placeholder location="classpath:/db.properties"/> <bean id="conn" class="com.xxxx.factoryBean.ConnectionFactoryBean"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"> </bean>第十二章 自定义类型转换器
1、类型转换器
作用:Spring通过类型转换器把配置文件中字符串类型的数据,转换成了对象中成员变量对应类型的数据,进而完成了注入
2、自定义类型转换器
-
类 implements Converter接口
public class MyDateConverter implements Converter<String, Date>{ @Override public Date Convert(String source){ Date date = null; try{ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd"); date = sfa.parse(source); } catch (ParseException e) { e.printStackTrace(); } return date; } } -
在Spring的配置文件中进行配置
-
MyDateConverter对象创建出来
<bean id="myDateConverter" class="xxxx.MyDateConverter"/> -
类型转换器的注册
<!-- 用于注册类型转换器--> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <ref bean="myDateConverter"/> </set> </property> </bean>
-
3、细节
-
日期格式的配置
<!--Spring创建MyDateConverter类型对象--> <bean id="myDateConverter" class="com.xxxx.converter.MyDateConverter"> <property name="pattern" value="yyyy-mm-dd"> </bean> -
ConversionServiceFactoryBean 定义id属性值必须是:conversionService
-
Spring框架内置日期类型的转换器
只支持:日期格式:2020/05/01
第十三章 后置处理Bean
BeanPostProcessor作用:对Spring工厂所创建的对象进行再加工
AOP底层实现:
注意:BeanPostProcessor接口
-
后置处理bean的运行分析
Object postProcessBeforeInitiallization(Object bean, String beanName) 作用:Spring创建完对象,并进行注入后,可以运行Before方法进行加工 获得Spring创建好的对象:通过方法的参数 最终通过返回值交给Spring框架 Object postProcessAfterInitiallization(Object bean, String beanName) 作用:Spring执行完对象的初始化操作后,可以运行After方法进行加工 获得Spring创建好的对象:通过方法的参数 最终通过返回值交给Spring框架 实战中: 很少处理Spring的初始化操作:没有必要区分Before After,只需要实现其中一个After方法即可 注意:return bean对象 -
BeanPostProcessor的开发步骤
-
累实现BeanPostProcessor接口
public class MyBeanPostProcessor implements beanPostProcessor{ @Override public Object postProcessBeforeInitializstion(Object bean, String beanName){ return bean; } @Override public Obejct poseProcessorAfterInitialization(Object bean, String beanName){ if(bean instanceof Categroy){ Categroy categroy = (Categroy) bean; categroy.setName("roy"); } return bean; } } -
Spring的配置文件中进行配置
<bean id="myBeanPostProcessor" class="xxx.MyBeanPostProcessor"/> -
BeanPostProcessor细节
BeanPostProcessor会对Spring工厂中所有创建的对象进行加工
-