Springboot学习总结
Springboot、IOC、AOP、mybatis、git、代码规范、整理总结,不足请补充指正
1,Springboot有哪些优点,为什么要使用Springboot
为什么要用Spring Boot:
一、独立运行
Spring Boot而且内嵌了各种servlet容器,Tomcat、Jetty等,现在不再需要打成war包部署到容器中,Spring Boot只要打成一个可执行的
jar包就能独立运行,所有的依赖包都在一个jar包内。
二、简化配置
spring-boot-starter-web启动器自动依赖其他组件,简少了maven的配置。
三、自动配置
Spring Boot能根据当前类路径下的类、jar包来自动配置bean,如添加一个spring-boot-starter-web启动器就能拥有web的功能,无需其他配置。
四、无代码生成和XML配置
Spring Boot配置过程中无代码生成,也无需XML配置文件就能完成所有配置工作,这一切都是借助于条件注解完成的,这也是Spring4.x的核心功能之一。
五、应用监控
Spring Boot提供一系列端点可以监控服务及应用,做健康检测
springboot的优点:
- 快速开发spring应用的框架
- 内嵌tomcat和jetty容器,不需要单独安装容器,jar包直接发布一个web应用
- 简化maven配置,parent这种方式,一站式引入需要的各种依赖
- 基于注解的零配置思想
- 各种流行框架,spring web mvc,mybatis,spring cloud无缝整合
2,Springboot,SpringMVC,Spring有什么区别
①、Spring
Spring是一个开源容器框架,可以接管web层,业务层,dao层,持久层的组件,并且可以配置各种bean,和维护bean与bean之间的关系。其核心就是控制反转(IOC),和面向切面(AOP),简单的说就是一个分层的轻量级开源框架。
②、SpringMVC
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。SpringMVC是一种web层mvc框架,用于替代servlet(处理|响应请求,获取表单参数,表单校验等。SpringMVC是一个MVC的开源框架,SpringMVC=struts2+spring,springMVC就相当于是Struts2加上Spring的整合。
③、SpringBoot
Springboot是一个微服务框架,延续了spring框架的核心思想IOC和AOP,简化了应用的开发和部署。Spring Boot是为了简化Spring应用的创建、运行、调试、部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置。提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题—>习惯大于约定。
区别:
1.简单理解为:Spring包含了SpringMVC,而SpringBoot又包含了Spring或者说是在Spring的基础上做得一个扩展。
2、关系大概就是这样:
spring < spring mvc < springboot
3、Spring Boot 对比Spring的一些优点包括:
- 提供嵌入式容器支持
- 使用命令java -jar独立运行jar
- 在外部容器中部署时,可以选择排除依赖关系以避免潜在的jar冲突
- 部署时灵活指定配置文件的选项
- 用于集成测试的随机端口生成
4、结论
Spring Boot只是Spring本身的扩展,使开发,测试和部署更加方便。
3,什么是Springboot的自动装配
通过注解或者一些简单的配置就能在spring boot的帮助下实现某款功能。
4,什么是yaml,yaml格式是什么
YAML (YAML Ain’t Markup Language) , 一种直观的能够被电脑识别的的数据数据序列化格式,并且容易被人类阅读, 容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入
优点 :
1.容易阅读 2.容易与脚本语言交互 3.以数据为核心 , 重数据轻格式
YAML文件扩展名 :
.yml (主流) .yaml
yaml的数据格式 :
#单个属性
country: china
#中间一定要有一个空格
#(对象)多个属性
user:
name: sichen
age: 17
#注意 : 层级之间名称不能重复
#写一个数组
likes:
- game
- music
- sleep
#用-号 , 中间加空格
#简单写法
likes2: [game,music,sleep]
#对象数组 :
user2:
- name: zhangsan
- age: 17
#简单写法 :
user3: [{name:zhangsan,age:17},{name:sichen,age=17}]
@Value("${name}")
private String name;
//使用${配置文件中想要引用的数据的名称}
@Value("${数组名称[第几个数].数组中的什么数据}")
private String name;
//使用${配置文件中想要引用的数据的名称}
@Value("${user[0].age}")
private String age;
#使用${属性名}的格式来引用数据
age: 10000
user2:
-
name: 思尘
age: ${age}
读取yaml全部属性数据 :
//使用自动装配 , 将所有的数据封装到一个对象Environment中
@Autowired
private Environment env;
5,SPringboot配置文件的优先级
1. 第一种是在执行命令的目录下建config文件夹,然后把配置文件放到这个文件夹下。(在jar包的同一个目录下建config文件夹,执行命令需要在jar包所在目录下才行)
2. 第二种是直接把配置文件放到jar包的同级目录
3. 第三种在classpath下建一个config文件夹,然后把配置文件放进去。
4. 第四种是在classpath下直接放配置文件。
springboot默认是优先读取它本身同级目录下的一个config/application.properties文件的。在src/main/resource文件夹下创建的application.properties文件的优先级是最低的
所以springboot启动读取外部配置文件,只需要在外面加一层配置文件覆盖默认的即可,不用修改代码
6,什么是嵌入式服务器,Springboot是怎么内嵌web容器的
嵌入式服务器:
嵌入式服务器就是我们的可执行单元包含服务器的二进制文件(例如,tomcat.jar)。
例如,对于一个 Spring Boot 应用程序来说,你可以生成一个包含 Embedded Tomcat 的应用程序 jar。这样可以像运行正常 Java 应用程序一样来运行 web 应用程序了。
这样就只需要机器上安装了Java虚拟机,就可以直接在上面部署应用程序了,因此不需要再安装tomcat服务器了。
Springboot是怎么内嵌web容器的:
通过自动配置机制,Spring Boot提供了一个嵌入式的运行时容器环境,并使用代码注解的方式在代码中将URL服务地址映射到Controller的方法完成服务映射。开发者不再需要关心传统容器(如Tomcat)中web.xml的配置,同时实现容器的具体技术都是可替换及可更改的,这些技术以插件化的Starter组件方式在运行时加载到Spring容器中。
SpringBoot自动配置web容器原理:
1.@SpringBootConfiguration注解是个组合注解。其中包含了@EnableAutoConfiguration这个注解。
2.EnableAutoConfiguration注解导入了一个实现DeferredImportSelector接口的AutoConfigurationImportSelector类。
3.Spring容器初始化前,会调用
invokeBeanFactoryPostProcessors()->invokeBeanDefinitionRegistryPostProcessors()->
BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry()
此BeanDefinitionRegistryPostProcessor为bean工厂的后置处理器。实现类为ConfigurationClassPostProcessor。会扫描到用@Import导入的方法,并把实现DeferredImportSelector接口的对象放到一个map中,后面会执行DeferredImportSelector.getAutoConfigurationEntry()方法。
4.DeferredImportSelector.getAutoConfigurationEntry()方法会从META-INF/spring.factories文件中找到
spring.boot.enableautoconfiguration变量数组。会把定义的变量数组值配置到到Spring容器中。其中就有个WebServicesAutoConfiguration配置类。配置了web容器。
7,@Autowride和@resource的区别
@Autowired是spring提供的注解,而@Resource是JDK提供的注解。
@Autowired默认按类型装配,默认情况下必须要求依赖对象存在,如果要允许null值,可以设置它的required属性为false。如果想使用名称装配可以结合@Qualifier注解进行使用。
@Resource,默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行名称查找。
如果一个接口,有多个实现类如一个IUser接口,分别有UserImpl01、UserImpl02。
那么在装配的时候我们就要指定我们需要装配哪一个实现类。这个@Autowired做不到,编译不通过,这时候要用(@Resource (name=“UserImpl01”))
8,描述几条常见的代码规范(阿里巴巴java代码规范)
1.大括号的使用约定:如果大括号内为空,简洁地写成{}即可,不需要换行,如果是非空代码块则:
- 左大括号前不换行
- 左大括号后换行
- 右大括号前换行
- 右大括号后还有else等代码不换行
- 表示终止的右大括号后必须换行。
2.左小括号和字符之间不出现空格;同样,右小括号和字符之间也不出现空格。
3.if/for/while/switch/do等保留字和括号之间都必须加空格。
4.任何二目、三目运算符的左右两边都要加一个空格。
5.采用4个空格缩进,禁止使用tab字符。
例子:
public static void main(String[] args) {
// 缩进 4 个空格
String say = "hello";
// 运算符的左右必须有一个空格
int flag = 0;
// 关键词 if 与括号之间必须有一个空格,括号内的 f 与左括号,0 与右括号不需要空格
if (flag == 0) {
System.out.println(say);
}
// 左大括号前加空格且不换行;左大括号后换行
if (flag == 1) {
System.out.println("world");
// 右大括号前换行,右大括号后有 else,不用换行
} else {
System.out.println("ok");
// 在右大括号后直接结束,则必须换行
}
6.注释的双斜线与注释内容之间有且仅有一个空格
7.单行字符数限制不超过120个,超出需要执行换行,换行时遵循如下原则
第二行相比第一行缩进4个空格,从第三行开始不再缩进。
运算符与下文一起换行
方法调用的点符号和下文一起换行
方法调用时,多个参数,需要换行时,在逗号后进行
在括号前不要换行
8.方法参数在定义和传入时,多个参数逗号后边必须加空格
9.IDE的text file encoding 设置为UTF-8;IDE中文件换行符使用Unix格式,不要使用Windows格式等......
9,接口和抽象类的区别
A:成员的区别
抽象类:
- 构造方法:有构造方法,用于子类实例化使用。
- 成员变量:可以是变量,也可以是常量。
- 成员方法:可以是抽象的,也可以是非抽象的。
接口:
- 构造方法:没有构造方法
- 成员变量:只能是常量。默认修饰符:public static final
- 成员方法:jdk1.7只能是抽象的。默认修饰符:public abstract (推荐:默认修饰符请自己永远手动给出)
jdk1.8可以写以default和static开头的具体方法
B:类和接口的关系区别
类与类:
继承关系,只能单继承。可以多层继承。
类与接口:
实现关系,可以单实现,也可以多实现。
类还可以在继承一个类的同时实现多个接口。
接口与接口:
继承关系,可以单继承,也可以多继承。
C:体现的理念不同
抽象类里面定义的都是一个继承体系中的共性内容。
接口是功能的集合,是一个体系额外的功能,是暴露出来的规则。
你选择使用接口和抽象类的依据是什么?
接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。
抽象类表示的是:这个对象是什么。接口表示的是:这个对象能做什么。比如,男人,女人,这两个类(如果是类的话……),他们的抽象类是人。说明,他们都是人。
人可以吃东西,狗也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它.所以,在高级语言上,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)。
当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。
抽象类的功能要远超过接口,但是,定义抽象类的代价高。因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类。在这个类中,你必须继承或编写出其所有子类的所有共性。虽然接口在功能上会弱化许多,但是它只是针对一个动作的描述。而且你可以在一个类中同时实现多个接口。在设计阶段会降低难度。
10,简述一下公司的开发流程,以及git分支的使用规范
开发流程:
需求评审->开发设计方案->开发方案评审->进入开发
开发环境->测试环境->预生产环境->灰度测试->生产环境
git分支的使用规范:
分支类型 | 分支前缀 | 简介 |
主分支 | master | 生产环境分支。 固定分支 |
预发分支 | pre | 预发环境分支。 固定分支 |
开发分支 | dev | 测试环境分支。 固定分支 |
功能分支 | feature/* | 作为新功能开发分支。 |
补丁分支 | hotfix/* | 作为生产环境问题修复分支。 |
支持分支 | support/* | 作为代码优化、重构分支。 |
冲突分支 | conflict/* | 作为解决合并冲突使用的分支,合并冲突解决后即删除。 自定义类型分支 |
分支命名
格式:分支前缀/自定义标识
例如:
# 功能分支:微信商家券开发 - 禅道任务 ID:311
feature/wechat_merchant_coupon_311
# 修复分支:修复商品详情页推荐 - 禅道任务 ID:311
hotfix/goods_detail_recommend_311
# 支持分支:优化商品定价脚本 - 禅道任务 ID:311
support/goods_price_command_311
# 冲突分支:解决指定分支的合并冲突 - 禅道任务 ID:311
conflict/hotfix/goods_detail_recommend_311
分支说明
- master
- 生产环境分支。
- 操作权限:仅管理员。
- 合并说明:-
- 推送说明:-
pre
- 预发环境分支。
- 操作权限:仅管理员。
- 合并说明:-
- 推送说明:-
dev
- 测试环境分支,此分支包含:正在测试、等待测试的代码,属于不稳定代码分支。
- 操作权限:仅管理员。
- 合并说明:-
- 推送说明:-
- 注意!合并到此分支的代码将被自动部署到开发环境。
- 由于 dev 分支存在多种类型分支的合并(新功能开发、问题修复、代码重构),故,不能基于此分支创建任何类型的新分支,同时,也不能将此分支合并到其他分支。
feature/*
- 新功能开发分支。
- 操作权限:仅允许对应开发人员操作。
- 创建说明:
- 创建自 master :新功能开发分支。
- 合并说明:
- 合并到 dev :新功能开发完成,等待测试。
- 合并到 pre :新功能测试通过,预发环境测试。
- 合并到 master :预发布环境测试通过,发布。
support/*
- 支持分支,用于:代码重构、代码优化等。
- 操作权限:仅允许对应开发人员操作。
- 创建说明:
- 创建自 master :代码重构分支。
- 合并说明:
- 合并到 dev :代码重构完成,等待测试。
- 合并到 pre :代码重构测试通过,预发环境测试。
- 合并到 master :预发布环境测试通过,发布。
hotfix/*
- 生产环境问题修复分支。
- 操作权限:仅允许对应开发人员。
- 创建说明:
- 创建自 master :生产环境问题修复分支。
- 合并说明:
- 合并到 dev :问题修复完成,等待测试。
- 合并到 pre :问题修复测试通过,预发环境测试。
- 合并到 master :预发环境测试通过,发布。
conflict/*
- 解决冲突分支。一次性分支,解决冲突完成后即删除。
- 操作权限:仅允许对应开发人员。
- 创建说明:-
- 合并说明:-
11,Springboot只能打成jar包,如果不是,怎么打war包。
1.修改打包方式 war
2.去除内置tomcat,防止根原生的Tomcat冲突
3.修改Springboot启动类
12,@RequestMapping和@getMapping的区别是什么呢。
@RequestMapping、@PostMapping、@GetMapping均为映射请求路径,可作用于类或方法上。
@RequestMapping当作用于类时,是该类中所有响应请求方法地址的父路径。
@RequestMapping当作用于方法时,是该接口响应请求方法地址的子路径,method里可以填写【RequestMethod.GET/RequestMethod.POST/RequestMethod.DELETE】。
@RequestMapping("/father") //test即父路径
public class Demo{
@RequestMapping(value = "/son", method = RequestMethod.GET)
@ResponseBody // 将返回的java对象转为json格式的数据
public String hello() {
return "hello world !";
}
}
访问路径:http://localhost:8080/father/son (切记不要忘记“father”哦!)
@GetMapping例子
@RequestMapping当作用于类时,是该类中所有响应请求方法地址的父路径。
@GetMapping当作用于方法时,是该接口响应请求方法地址的子路径。
@RequestMapping("/father") //test即父路径
public class Demo{
@GetMapping("/son")
@ResponseBody // 将返回的java对象转为json格式的数据
public String hello() {
return "hello world !";
}
}
13,如何重新加载SPringboot上的更改,不重启服务。(热部署)。
此操作可以使用DEV工具来实现,可以节省任何更改,嵌入式Tomcat将重新启动。SpringBoot有一个开发工具(DevTools)模块,它有助于提高开发人员的生产力。Java开发人员面临的一个主要的挑战是将文件更改为自动部署到服务器并自动重启服务。开发人员可以重新加载SpringBoot上的更改,而无需重新启动服务器。这将消除每次手动部署更改的需要。springboot在发布它的第一个版本时没有这个功能。这是开发人员最需要的功能。DevTools模块完全满足开发人员的需求。该模块将在生成环境中被禁用。它还提供H2数据库控制台以更好的测试应用程序。
没有springboot之前,如果我们修改了jsp文件,我们不需要重启tomcat,但是如果是java文件修改,就必须得重启tomcat,但是有了springboot就不一样了,我们可以在maven的pom.xml文件中添加两个依赖就可以实现修改java文件,不需要重启springboot,这样就很大程度上可以节省我们重启tomcat的时间了
依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>1.3.0.RELEASE</version>
</dependency>
14,什么是java的封装继承多态,各有什么好处。
1.封装
封装的概念:把对象的属性和方法结合成一个独立的整体,隐藏实现细节,并提供对外访问的接口。
封装的好处:
(1):隐藏实现细节。好比你买了台电视机,你只需要怎么使用,并不用了解其实现原理。
(2):安全性。比如你在程序中私有化了age属性,并提供了对外的get和set方法,当外界 使用set方法为属性设值的时候 你可以在set方法里面做个if判断,把值设值在0-80岁,那样他就不能随意赋值了。
(3):增加代码的复用性。
好比在工具类中封装的各种方法,你可以在任意地方重复调用,而不用再每处都去实现其细节。
(4):模块化。封装分为属性封装,方法封装,类封装,插件封装,模块封装,系统封装等等。有利于程序的协助分工,互不干扰,方便了模块之间的相互组合与分解,也有利于代码的调试和维护。比如人体由各个器官所组成,如果有个器官出现问题,你只要去对这个器官进行医治就行了。
2.继承
继承的概念:从已知的一个类中派生出新的一个类,叫子类。子类实现了父类所有非私有化属性和方法,并能根据自己的实际需求扩展出新的行为。
继承的好处:
(1):继承是传递的,容易在其基础上构造,建立和扩充出新的类。
(2):简化了人们对事物的认识和描述,能清晰体现相关类之间的层次结构关系。
(3):能减少数据和代码的冗余度。
(4):大大增加了代码的维护性。
3.多态
多态的概念:多个不同的对象对同一消息作出响应,同一消息根据不同的对象而采用各种不同的行为方法。
实现多态的必要条件:
1.必须要有继承
2.必须要重写方法
3.父类引用指向子类对象
多态的好处:主要是利于扩展。
15,什么是mybatis。
MyBatis是一款优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
16,#{}和${}的区别
mybatis在处理两个字符时,处理的方式也是不同的:
①、处理#{}时,会将sql中的#{}整体替换为占位符(即:?),调用PreparedStatement的set方法来赋值;
②、在处理 $ { } 时,就是把 ${ } 替换成变量的值。
假如用${}来编写SQL会出现:恶意SQL注入,对于数据库的数据安全性就没办法保证了
使用 #{} 可以有效的防止SQL注入,提高系统安全性
17,什么是动态sql,有哪些动态sql
1.动态SQL的概念
动态sql是指在进行sql操作的时候,传入的参数对象或者参数值,根据匹配的条件,有可能需要动态的去判断是否为空,循环,拼接等情况;
2.动态Sql的标签大致有以下几种
if 和 where 标签和include标签
if标签中可以判断传入的值是否符合某种规则,比如是否不为空;
where标签可以用来做动态拼接查询条件,当和if标签配合的时候,不用显示的声明类似where 1=1这种无用的条件,来达到匹配的时候and会多余的情况;
include可以把大量重复的代码整理起来,当使用的时候直接include即可,减少重复代码的编写
<!--动态Sql : where / if-->
<select id="findUserById" resultType="com.lagou.pojo.User">
select <include refid="userInfo"/> from user
<where>
<if test="id != null and id != 0">
AND id = #{id}
</if>
<if test="name != null and name != ''">
AND name = #{name}
</if>
</where>
</select>
choose、when、otherwise 标签
类似于 Java 中的 switch、case、default。只有一个条件生效,也就是只执行满足的条件 when,没有满足的条件就执行 otherwise,表示默认条件
<!--动态Sql: choose、when、otherwise 标签-->
<select id="findUserById" resultType="com.lagou.pojo.User">
select * from user
<where>
<choose>
<when test="name != null and name != ''">
AND name = #{name}
</when>
<otherwise>
AND id = #{id}
</otherwise>
</choose>
</where>
</select>
foreach 标签
foreach标签可以把传入的集合对象进行遍历,然后把每一项的内容作为参数传到sql语句中,里面涉及到 item(具体的每一个对象), index(序号), open(开始符), close(结束符), separator(分隔符)
<!--动态Sql: foreach标签, 批量插入-->
<insert id="insertBatch" useGeneratedKeys="true" keyProperty="id">
insert into user (id, name)
values
<foreach collection="list" item="user" separator="," >
(#{user.id}, #{user.name})
</foreach>
</insert>
<!--动态Sql: foreach标签, in查询-->
<select id="dynamicSqlSelectList" resultType="com.lagou.pojo.User">
SELECT * from user WHERE id in
<foreach collection="list" item="id" open="(" close=")" separator="," >
#{id}
</foreach>
</select>
map参数
< map> 标签需要结合MyBatis的参数注解 @Param()来使用,需要告诉Mybatis配置文件中的collection="map"里的map是一个参数
<!--动态Sql: foreach标签, map参数查询-->
<select id="findByMap" resultType="com.lagou.pojo.User">
select * from user WHERE
<foreach collection="map" index="key" item="value" separator="=">
${key} = #{value}
</foreach>
</select>
set标签
适用于更新中,当匹配某个条件后,才会对该字段进行更新操作
<!--动态Sql: set 标签-->
<update id="updateSet" parameterType="com.lagou.pojo.User">
update user
<set>
<if test="name != null and name != ''">
name = #{name},
</if>
</set>
where id = #{id}
</update>
trim标签
是一个格式化标签,主要有4个参数:
- prefix(前缀)
- prefixOverrides(去掉第一个标记)
- suffix(后缀)
- suffixOverrides(去掉最后一个标记)
<!--动态Sql: trim 标签-->
<select id="findUser" resultType="com.lagou.pojo.User">
select * from user
<trim prefix="where" suffix="order by id" prefixOverrides="and | or" suffixOverrides=",">
<if test="name != null and name != ''">
AND name = #{name}
</if>
<if test="id != null">
AND id = #{id}
</if>
</trim>
</select>
19,spring的ioc和aop有哪些优点,我们可以利用这些特性来实现哪些功能呢?
IOC是什么?
Ioc即控制反转,把原来的代码里需要实现的对象创建,依赖反转给容器来帮忙实现,需要创建一个容器并且需要一种描述让容器知道要创建的对象间的关系,在Spring中管理对象及其依赖关系是通过Spring IOC容器实现的。Ioc的实现方式有依赖注入和依赖查找,由于依赖查找使用的很少,因此Ioc也叫做依赖注入。依赖注入指对象被动地接收依赖类而不用自己主动去找,对象不是从容器中查找它依赖的类,而是在容器实例化对象时主动将它依赖的类注入给它。假设一个Car类需要一个Engine的对象,那么一般需要手动new 一个Engine,利用Ioc就只需要定义一个私有的Engine类型的成员变量,容器会在运行时自动创建一个Engine的实例对象并将引入自动注入给成员变量。
Ioc容器的初始化过程?
当创建一个ClassPathXmlApplicationContext时,构造方法做了两件事情:①调用父容器的构造方法为容器设置好Bean资源加载器。②调用父类的setConfigLocations方法设置Bean配置信息的定位路径。 ClassPathXmlApplicationContext通过调用父类AbstractApplicationContext的refresh方法启动整个Ioc容器对Bean定义的载入过程,refresh是一个模板方法,规定了Ioc容器的启动流程。在创建Ioc容器前如果已有容器存在,需要把已有的容器销毁,保证在refresh方法后使用新创建的Ioc容器。容器创建后通过loadBeanDefinitions方法加载Bean 配置资源,该方法做两件事:①调用资源加载器的方法获取要加载的资源。②真正执行加载的功能,由子类XmlBeanDefinitionReader实现,加载资源时首先解析配置文件路径,读取配置文件的内容,然后通过XML解析器将Bean配置信息转换成文档对象,之后按照Spring Bean的定义规则对文档进行解析。Spring Ioc容器中注册解析的Bean信息存放在一个HashMap集合中,key是字符集,只是BeanDefinition,注册过程中需要使用synchronized 保证线程安全。当配置信息中配置的Bean被解析且被注册到Ioc容器中后,初始化就算真正完成了,Bean定义信息已经可以使用且可被检索。Spring Ioc容器的作用就是对这些注册的Bean定义信息进行处理和维护,注册的Bean定义信息是控制反转和依赖注入的基础。
基于注解的容器初始化
直接将注解Bean注册到容器中,可以在初始化容器时注册,也可以在容器创建之后手动注册,然后刷新容器使其对注册的注解Bean进行处理。
通过扫描指定的包及其子包的所有类处理,在初始化注解容器时指定要自动扫描的路径。
依赖注入的相关注解?
- @Autowired :自动按类型注入,如果有多个匹配则按照指定的Bean的id查找,查找不到会报错。
- @Qualifier :在自动按照类型注入的基础上再按照Bean的id注入,给变量注入时必须搭配@Autowired,给方法注入时可单独使用。
- @Resource:直接按照Bean的id注入,只能注入Bean类型。
- @Value:用于注入基本数据类型和String类型
如何通过注解创建Bean?
@Component 把当前类对象存入Spring容器中,相当于xml中配置了一个bean标签。value属性指定bean的id,默认使用当前类的首字母小写的类名。@Controller 、@Service、@Repository 三个注解都是@Component的衍生注解,作用及属性都是一模一样的,只是提供了更加明确的语义。@Controller用于表现层,@Service用于业务层,@Repository用于持久层。如果注解的中只有一个value属性要赋值时可以省略value。如果想将第三方的类变成组件有没有源代码,也就没办法使用@Component进行自动配置,这种时候就要使用@Bean注解,被@Bean注解的方法返回值是一个对象,将会实例化,配置和初始化一个新对象并返回,这个对象由Spring的Ioc容器管理。name属性用于给当前@Bean注解方法创建的对象指定一个名称,即Bean的id,当使用注解配置方法时,如果方法有参数,Spring会去容器查找是否有可用的bean对象,查找方式和@Autowired一样。
AOP是什么?
AOP即面向切面编程,通过预编译和运行期动态代理实现程序功能的统一维护。常用场景:权限认证、自动缓存、错误处理、日志、调试和事务等。
实现AOP的方式?
采用动态代理方式实现:利用拦截方法的方式,对该方法进行装饰,以增强原有对象的方法。具体实现技术有JDK动态代理基于接口代理和CGLib基于类代理的字节码提升。
采用静态织入的方式:引入特定的语法创建“切面”,从而使得编译器可以在编译期间织入相关“切面”的代码。
AOP原理
AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用。AOP代理包含了目标对象的全部方法,但AOP代理中的方法与目标对象的方法存在差异:AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法。Spring的AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IoC容器负责管理,因此,AOP代理可以直接使用容器中的其他Bean实例作为目标,这种关系可由IoC容器的依赖注入提供。
AOP的相关注解有哪些?
- @Aspect:声明被注解的类是一个切面的Bean;
- @Before:前置通知,指在某个连接点之前执行的通知;
- @After:后置通知,指某个连接点退出时执行的通知(不论程序是正常返回还是异常退出)
- @AfterReturning:返回后通知,指某连接点正常完成之后执行的通知,返回值使用returning属性接收。
- @AfterThrowing:异常通知,指方法抛出异常导致退出时执行的通知,和@AfterReturning只会有一个执行,异常使用throwing属性接收。
20,异常处理的三种方法。
1.抛出异常有两种方式:
第一种是在方法上throw
第二种是使用try-catch语句,在catch中new throw出去
一般会在controller层将service层的异常try-catch,将异常发给前端
2.异常处理分三类:
- 第一类,特殊异常,即自己业务上的特殊异常,需要特别处理的,直接在catch中将该异常处理吃掉。比如有个业务需要访问一个鉴权的接口,当第一次鉴权不成功时,捕获到异常,在catch上继续鉴权。
- 第二类,可忽略的异常。即有些异常抛出不会影响正常流程和业务的,可忽略掉,在catch里不作处理
- 第三类,需要交给上一层处理的异常。比如在service层抛出的异常,需要再往上抛出去给controller层,让其处理或者发给前端。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)