Spring框架笔记
文章目录
- Spring框架笔记
- 一.spring概念
- 二. Spring 体系结构
- 三.IOC容器
- 四.AOP
- 五.JdbcTemplate
- 六.事务管理
- 七.spring5新特性
一.spring概念
-
Spring 是 一款轻量级的开源框架。
-
Spring 可以解决企业应用开发的复杂性。
-
Spring 有两个核心部分:IOC 和 Aop
- IOC :控制反转,把创建对象过程交给 Spring 进行管理。
- Aop :面向切面,不修改源代码就可以进行功能的增强。
-
Spring 特点
- IOC 控制反转:把创建对象过程交给 Spring 进行管理,方便解耦,简化开发。
- Aop 面向切面编程:不修改源代码就可以进行功能的增强。
- 一站式:可以方便与其他框架和优秀的第三方类库进行整合。
- 简化 API 的使用,spring 对很多难用的 JavaEE API (如JDBC)进行了简单的封装,从而降低了一些 API 的使用难度。
- 方便程序测试(支持Junit4测试)
- 方便进行事务的操作
二. Spring 体系结构
Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入。
Spring 框架基本涵盖了企业级应用开发的各个方面,它包含了 20 多个不同的模块。
核心容器
- spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。
- spring-core 核心模块提供了框架的基本组成部分,包括 IOC 和依赖注入功能。
- Context 上下文模块建立在 Core 和 Beans 模块的基础之上,集成 Beans 模块功能并添加资源绑定、数据验证、国际化、Java EE 支持、容器生命周期、事件传播等。ApplicationContext 接口是上下文模块的焦点。
- **SpEL 模块:**提供了强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从 Spring 容器获取 Bean,它也支持列表投影、选择和一般的列表聚合等。
数据访问/集成
数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:
- JDBC 模块提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。
- ORM 模块提供了对流行的对象关系映射 API 的集成,包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 spring的其它功能整合,比如前面提及的事务管理。
- OXM 模块提供了对 OXM 实现的支持,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。
- JMS 模块包含生产(produce)和消费(consume)消息的功能。从 Spring 4.1 开始,集成了 spring-messaging 模块。
- 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写 beginTransaction()、commit()、rollback() 等事务管理方法,声明式事务是通过注解或配置由 spring 自动处理,编程式事务粒度更细)
Web
Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:
- Web 模块提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与 web 相关的部分。
- Web-MVC 模块为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。
- Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。
- Web-Portlet 模块提供了用于 Portlet 环境的 MVC 实现,并反映了 spring-webmvc 模块的功能。
Test模块
Test 模块:Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。
其他模块
- AOP 模块提供了面向方面(切面)的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。
- Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
- Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。
- Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。
- 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。
三.IOC容器
什么是 IOC ?
(1)控制反转,把对象创建和对象之间的调用都交给 Spring 来管理。
(2)使用 IOC 的目的:降低耦合度
IOC 底层原理
XML 的解析、工厂模式、反射
IOC 接口(BeanFactory)
1. IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂。
2. Spring 提供 IOC 容器实现的两种方式:两个接口
(1)BeanFactory接口:是IOC容器实现的基本接口,是Spring内部接口,不提供给开发人员进行使用(加载配置文件时候不会创建对象,在获取对象时才会创建对象。)
(2)ApplicationContext接口:BeanFactory接口的子接口,提供更多更强大的功能,提供给开发人员使用(加载配置文件时候就会把在配置文件对象进行创建)(推荐使用!我们希望当程序刚启用-加载配置文件的时候就创建对象,而不是在-获取对象的时候在创建对象)
//1.加载 Spring 配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
HelloSpring5 obj = context.getBean("helloWorld", HelloSpring5.class);
obj.getMesage();
3. ApplicationContext通常的实现是什么?(面试)
-
FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean配置文件的全路径名必须提供给它的构造函数。(对应绝对路径)
-
ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。(对应类路径)
4. IOC的优点是什么?(面试)
IOC 或 依赖注入把应用的代码量降到最低。它使应用容易测试,单元测试不再需要单例和JNDI查找机制。最小的代价和最小的侵入性使松散耦合得以实现。IOC容器支持加载服务时的饿汉式初始化和懒加载。
5. Bean 工厂和 Application contexts 有什么区别?(面试)
Application contexts提供一种方法处理文本消息,一个通常的做法是加载文件资源(比如镜像),它们可以向注册为监听器的bean发布事件。另外,在容器或容器内的对象上执行的那些不得不由bean工厂以程序化方式处理的操作,可以在Application contexts中以声明的方式处理。Application contexts实现了MessageSource接口,该接口的实现以可插拔的方式提供获取本地化消息的方法。
什么是 Bean 管理:
Bean 管理指的是两个操作:1. Spring 创建对象 (通过反射创建对象) 2.注入属性(设置属性值)
IOC 操作 Bean 管理(***基于XML的 Bean 管理)
1. 基于 XML 方式创建对象
使用<Bean>标签方式创建对象
2. 基于 XML 方式注入属性
- DI:依赖注入,就是注入属性
- IOC 和 DI 的区别是?(面试) DI 是 IOC Bean管理操作的具体实现,它表示依赖注入,就是注入属性。
(1)set 方法注入属性(利用 property 标签注入属性)
<!--创建对象-->
<bean id="helloWorld" class="src.com.cn.java.HelloSpring5">
<!-- 利用 property 标签注入属性-->
<property name="mesage" value="你好" ></property>
</bean>
(2)通过有参构造方法完成注入属性 ( 利用 constructor标签注入属性 )
<bean id="book1" class="src.com.cn.java.book">
<constructor-arg name="bname" value="易筋经"></constructor-arg>
<constructor-arg name="bprices" value="达摩院"></constructor-arg>
</bean>
3. 基于 XML 方式注入其他类型属性
(1)注入其他属性–字面量
-
属性设置空值
<constructor-arg name="bbba" > <null></null> </constructor-arg>
-
属性包含特殊符号,例如 <<南京>>
<!-- 把特殊符号内容写入CDATA中--> <constructor-arg name="bbba" > <value> <![CDATA[<<南京>>]]> </value> </constructor-arg>
(2)注入其他属性–外部 Bean
(从 Service 引用 dao 层的一个类作为service层类的一个属性,需要注入dao层的一个对象(而非简单的属性),就叫做引入外部 Bean)
service层
public class userService {
//创建UserDao类型的属性,生成Set方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
userDao.addUserById();
System.out.println("---------------");
}
}
XML 配置如下:
<--基于set方法的对象注入如下,而基于有参构造方法的注入同理。-->
<bean name="userService" class="src.com.service.userService">
<!-- name是service 属性名称 ref:创建Bean标签的id值-->
<property name="userDao" ref="userDao1"></property>
</bean>
<bean name="userDao1" class="src.com.dao.UserDaoImp"></bean>
(3)注入其他属性–内部 Bean 和 级联赋值
a.一对多关系:部门和员工------在实体类之间表示一对多的关系
<!--内部Bean写法-->
<bean name="Emp" class="src.com.dao.Emp">
<property name="ename" value="张"></property>
<property name="egender" value="nv"></property>
<!--设置对象类型属性 内部Bean写法-->
<property name="dept ">
<bean id="Dept" class="src.com.dao.Dept">
<property name="dname" value="计算机"></property>
</bean>
</property>
</bean>
与外部Bean的区别就是,级联赋值在引入外部Bean的同时,给外部Bean设置了属性。
<!--级联赋值Bean写法-->
<bean name="Emp1" class="src.com.dao.Emp">
<property name="ename" value="张"></property>
<property name="egender" value="女"></property>
<!--级联赋值-->
<property name="dept" value="Dept2"></property></bean>
<bean name="Dept2" class="src.com.dao.Dept">
<property name="dname" value="安保部门"></property>
</bean>
(4)注入其他属性–集合属性
-
注入数组类型属性
-
注入 List 集合类型属性
-
注入 Map 集合类型属性
-
注入set类型属性
-
集合里面设置对象类型的属性
<bean name="stu_bean" class="src.com.dao.stu"> <!-- 注入数组类型属性--> <property name="courses"> <array> <value>Java课程</value> <value>数据库课程</value> </array> </property> <!-- 注入List集合类型属性--> <property name="list"> <list> <value>张三</value> <value>李四</value> </list> </property> <!-- 注入Map集合类型属性--> <property name="map"> <map> <entry key="2017405A3" value="长女"></entry> <entry key="2017405A8" value="次子"></entry> </map> </property> <!-- set类型属性注入--> <property name="set"> <set> <value>MySql</value> <value>SqlServer</value> </set> </property> </bean> <!-- list集合类型,对象类型--> <property name="courses_list"> <list> <ref bean="course_Bean1"></ref> <ref bean="course_Bean2"></ref> </list> </property> </bean> <bean id="course_Bean1" class="src.com.dao.course"> <property name="cname" value="数学二"></property> </bean> <bean id="course_Bean2" class="src.com.dao.course"> <property name="cname" value="英语二"></property> </bean>
集合里面设置对象类型如何输出?
设置一个 toString
public class course {
//课程名称
private String cname;
public String toString() {
return "course{" +
"cname='" + cname + '\'' +
'}';}
}
System.out.println(courses_list);
-
集合里面设置对象类型的属性,将List数组提取出来
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <util:list id="course_BeanList"> <ref bean="course_Bean1"></ref> <ref bean="course_Bean2"></ref> </util:list> <bean name="stu_bean" class="src.com.dao.stu"> <property name="courses_list" ref="course_BeanList"></property>
IOC 操作 Bean 管理(FactoryBean 管理)
-
Spring 有两种类型的 Bean:普通 Bean 和工厂 Bean( FactoryBean )
普通 Bean:在配置文件中定义的 Bean 类型就是返回的类型。
工厂 Bean:在配置文件中定义的 Bean 类型可以和返回类型不一样。
-
工厂 Bean 的创建
第一步:创建类,让这个类作为工厂 Bean,实现接口FactoryBean
第二步:实现接口里面的方法,在实现的方法中可以定义返回对象的类型
例如: public class MyBean implements FactoryBean<course> { //定义的是MyBean类型,返回的是course类型 @Override public course getObject() throws Exception { course c = new course(); return c; } }
IOC 操作 Bean 管理(Bean 作用域)
- 在 Spring 里面,设置创建 Bean 实例是单实例还是多实例,叫做Bean的作用域。(面试)
在 Spring 里面,默认创建单实例对象(验证如下)。(面试)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-txYDcnrz-1649943729811)(…/AppData/Roaming/Typora/typora-user-images/image-20220414205344469.png)]
IOC 操作 Bean 管理(Bean 生命周期)
Bean 的生命周期:
第一步:通过构造器创建 Bean 实例对象(无参构造)
第二步:为 Bean 的注入 属性值 或 外部引用 Bean (调用set方法或有参构造方法)
第三步:*把 Bean 实例传给 Bean 后置处理器方法
第四步:调用 Bean 的初始化的方法(需要配置初始化方法)
第五步:*把 Bean 实例传给 Bean 后置处理器方法
第六步:Bean 使用
第七步:手动 Bean 的销毁,当容器关闭的时候,调用 Bean 销毁方法(需要配置销毁方法)
//实体类
public class oders {
private String oname;
public oders() {
System.out.println("第一步:调用无参构造方法创建实例对象");
}
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步:通过set方法设置属性值");
}
//第三步:把 Bean 实例传给 Bean 后置处理器方法postProcessBeforeInitialization
public void init_oders(){
System.out.println("第四步:调用初始化方法");
}
//第五步:把 Bean 实例传给 Bean 后置处理器方法postProcessAfterInitialization
public void output(){
System.out.println("第六步:使用Bean" +oname);
}
public void destroyMethod(){
System.out.println("第七步:执行销毁方法");
}
}
//后置处理器类
public class MyBean implements BeanPostProcessor {
}
<bean name="order" class="src.com.dao.oders" init-method="init_oders" destroy-method="destroyMethod">
<property name="oname" value="手机"></property>
</bean>
<!-- 配置Bean后置处理器-->
<bean id="a1" class="src.com.dao.MyBean"></bean>
<!-- 配置的这个后置处理器会默认把所有Bean都设置去执行 后置处理器方法-->
@Test//Bean生命周期测试
public void orderTest(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("src/com/oderBean.xml");
oders obj = context.getBean("order",oders.class);
//使用Bean
obj.output();
//手动销毁Bean
context.close();
}
IOC 操作 Bean 管理(基于XML自动装配)
通过标签注入属性—手动装配
什么是自动装配:根据属性的 名称 或 类型 进行自动匹配注入
实现:
<!-- 自动装配 autowire
属性值: byName 根据属性名称自动装配 注入Bean的id值 要与属性名称一致
bytype 根据类型自动注入-->
<bean name="order" class="src.com.dao.oders" autowire="byName">
</bean>
<bean name="stu"></bean>
IOC 操作 Bean 管理(基于XML外部属性文件)
引入外部属性文件 例如下:
xml配置写法如下:
① 引入名空间 context
②如图
IOC 操作 Bean 管理(***基于注解方式的 Bean 管理)
- 什么是注解?
注解是代码的特殊标记。
格式:@注解名称(属性名称=属性值,属性名称=属性值)
注解可作用在 类上面 方法上面 属性上面
使用注解的目的:简化 XML 配置
- Spring 针对Bean 管理中 创建对象提供了四个注解如下:
@Component(创建对象注解中的普通注解)
@Service (一般用在业务逻辑层service层)
@Controller (一般用在web层)
@Repository (一般用在dao层)
*上述四个注解功能一样,只是为了提高代码的可读性。
1.基于注解方式创建对象步骤
第一步:引入 Aop 依赖包
第二步:开启组件扫描
------------------包中类都进行扫描---------------------
<!-- 开启组件扫描
若扫描多个包: 逗号隔开 或 扫描上一级目录-->
<context:component-scan base-package="src.com.service"></context:component-scan>
------------------包中类选择性扫描---------------------
<!-- 示例1 use-default-filters="false"表示不在使用默认扫描 需要自己配置 context:include-filter哪些进行扫描(包含Service注解的)-->
<context:component-scan base-package="src.com.service" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
<!-- 示例2 excludefilter哪些不进行扫描-->
<context:component-scan base-package="src.com.service" use-default-filters="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
第三步:创建类
在注解里 value 值可以省略不写,系统默认设置为 类名首字母小写userService
@Service(value = "userService") //对应XML方式的 <bean id="userService" class="...">
public class UserService {
public void add(){
System.out.println("这里是userService------------------");
}
}
第四步测试类
2.基于注解方式属性注入
(1)@Autowired 根据属性类型 进行自动注入
@Service(value = "userService") //对应XML方式的 <bean id="userService" class="...">
public class UserService {
@Autowired //根据类型自动注入
private UserDao userDao;
public void add(){
userDao.addUserById();
System.out.println("这里是userService------------------");
}
}
(2)@Qualifier 根据属性名称进行自动注入
- 与@Autowired 配合使用
@Service(value = "userService") //对应XML方式的 <bean id="userService" class="...">
public class UserService {
@Autowired //根据类型自动注入
@Qualifier(value = "userDao") //根据名称自动注入
private UserDao userDao;
public void add(){
userDao.addUserById();
System.out.println("这里是userService------------------");
}
}
(3)@Resource可以根据属性类型也可以根据属性名称进行注入(不推荐用)
//@Resource 根据类型注入
@Resource(name = "userDao")//根据名称 注入
private UserDao userDao;
(4)@Value
@Value("abczhnga")
private String name;
3.完全注解开发
创建配置类 替代配置文件组件扫描设置
@Configuration //配置类标识
@ComponentScan(basePackages = {"src.com.service" })
public class springConfig1 {
}
测试类:
@Test
public void TestuserService2(){
ApplicationContext context = new AnnotationConfigApplicationContext(src.com.config.springConfig1.class);
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
+++
四.AOP
什么是 Aop
(1)面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码的方式,在主干功能里添加新功能
(3)使用登录例子说明 Aop
Aop 的底层原理
1.Aop 底层使用动态代理
(1)有两种情况动态代理:
第一种:有接口的情况,使用 JDK 动态代理
- 创建接口实现类的代理对象,增强类方法
第二种:没有接口的情况,使用 CGLIB 动态代理