2023年2月9日 16:34 周四转载自https://github.com/Snailclimb/JavaGuide(添加小部分笔记)感谢作者!
部分疑问参考自
https://blog.csdn.net/Gherbirthday0916 感谢作者!
#{} 和 ${} 的区别是什么?
#
注:这道题是面试官面试我同事的。
答:
${}是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于静态文本替换,比如${driver}会被静态替换为com.mysql.jdbc. Driver。#{}是 sql 的参数占位符,MyBatis 会将 sql 中的#{}替换为? 号,在 sql 执行前会使用 PreparedStatement 的参数设置方法,按序给 sql 的? 号占位符设置参数值,比如 ps.setInt(0, parameterValue),#{item.name} 的取值方式为使用反射从参数对象中获取 item 对象的 name 属性值,相当于 param.getItem().getName()。 [这里用到了反射]
在底层构造完整SQL语句时,MyBatis的两种传参方式所采取的方式不同。#{Parameter}采用预编译的方式构造SQL,避免了 SQL注入 的产生。而**${Parameter}采用拼接的方式构造SQL,在对用户输入过滤不严格**的前提下,此处很可能存在SQL注入
xml 映射文件中,除了常见的 select、insert、update、delete 标签之外,还有哪些标签?
#
注:这道题是京东面试官面试我时问的。
答:还有很多其他的标签, <resultMap> 、 <parameterMap> 、 <sql> 、 <include> 、 <selectKey> ,加上动态 sql 的 9 个标签, trim|where|set|foreach|if|choose|when|otherwise|bind 等,其中 <sql> 为 sql 片段标签,通过 <include> 标签引入 sql 片段, <selectKey> 为不支持自增的主键生成策略标签。
...
2023年2月9日 15:38 周四两个测试方向
#
方向1:两个maven项目
#
详见git上的 conditional_on_class_main 项目以及 conditional_on_class2 项目
基础maven项目 conditional_on_class2
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>conditional_on_class_2</artifactId>
<version>1.0-SNAPSHOT</version>
</project>
java类
package com;
public class LyReferenceImpl {
public String sayWord() {
return "hello one";
}
}
简单的SpringBoot项目 conditional_on_class_main
<!--pom文件-->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>conditional_on_class_main</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.8</version>
</parent>
<dependencies>
<!--把1配置的bean引用进来-->
<dependency>
<groupId>org.example</groupId>
<artifactId>conditional_on_class_2</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<!-- 默认会将conditional_on_class_2 打包进去,现在会配置SayExist
如果放开注释,那么会配置SayNotExist-->
<!--<dependency>
<groupId>org.example</groupId>
<artifactId>conditional_on_class_2</artifactId>
</dependency>-->
</excludes>
<jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中 -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
//两个配置类
//配置类1
package com.config;
import com.service.ISay;
import com.service.SayExist;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
//不要放在方法里面,否则会报错"java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy"
@ConditionalOnClass(value = com.LyReferenceImpl.class)
public class ExistConfiguration {
@Bean
public ISay getISay1(){
return new SayExist();
}
}
//配置类2
package com.config;
import com.service.ISay;
import com.service.SayNotExist;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnMissingClass("com.LyReferenceImpl")
public class NotExistConfiguration {
@Bean
public ISay getISay1(){
return new SayNotExist();
}
}
方向2:3个maven项目(建议用这个理解)
#
注意,这里可能还漏了一个问题,那就是 这个conditional_on_class1 的configuration之所以能够被自动装配,是因为和 conditional_on_class_main1的Application类是同一个包,所以不用特殊处理。如果是其他包名的话,那么是需要用到spring boot的自动装配机制的:在conditional_on_class1 工程的 resources 包下创建META-INF/spring.factories,并写上Config类的全类名
...
2023年2月9日 10:37 周四转载自https://github.com/Snailclimb/JavaGuide(添加小部分笔记)感谢作者!
每次问到 Spring Boot, 面试官非常喜欢问这个问题:“讲述一下 SpringBoot 自动装配原理?”。
我觉得我们可以从以下几个方面回答:
- 什么是 SpringBoot 自动装配?
- SpringBoot 是如何实现自动装配的?如何实现按需加载?
- 如何实现一个 Starter?
篇幅问题,这篇文章并没有深入,小伙伴们也可以直接使用 debug 的方式去看看 SpringBoot 自动装配部分的源代码。
前言
#
使用过 Spring 的小伙伴,一定有被 XML 配置统治的恐惧。即使 Spring 后面引入了基于注解的配置,我们在开启某些 Spring 特性或者引入第三方依赖的时候,还是需要用 XML 或 Java 进行显式配置。
举个例子。没有 Spring Boot 的时候,我们写一个 RestFul Web 服务,还首先需要进行如下配置。
@Configuration
public class RESTConfiguration
{
@Bean
public View jsonTemplate() {
MappingJackson2JsonView view = new MappingJackson2JsonView();
view.setPrettyPrint(true);
return view;
}
@Bean
public ViewResolver viewResolver() {
return new BeanNameViewResolver();
}
}
spring-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context/ http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc/ http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.howtodoinjava.demo" />
<mvc:annotation-driven />
<!-- JSON Support -->
<bean name="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</beans>
但是,Spring Boot 项目,我们只需要添加相关依赖,无需配置,通过启动下面的 main 方法即可。
...
2023年2月8日 20:18 周三转载自https://github.com/Snailclimb/JavaGuide(添加小部分笔记)感谢作者!
“JDK 中用到了哪些设计模式? Spring 中用到了哪些设计模式? ”这两个问题,在面试中比较常见。
我在网上搜索了一下关于 Spring 中设计模式的讲解几乎都是千篇一律,而且大部分都年代久远。所以,花了几天时间自己总结了一下。
由于我的个人能力有限,文中如有任何错误各位都可以指出。另外,文章篇幅有限,对于设计模式以及一些源码的解读我只是一笔带过,这篇文章的主要目的是回顾一下 Spring 中的设计模式。
控制反转(IoC)和依赖注入(DI)
#
IoC(Inversion of Control,控制反转) 是 Spring 中一个非常非常重要的概念,它不是什么技术,而是一种解耦的设计思想。IoC 的主要目的是借助于“第三方”(Spring 中的 IoC 容器) 实现具有依赖关系的对象之间的解耦(IOC 容器管理对象,你只管使用即可),从而降低代码之间的耦合度。
IoC 是一个原则,而不是一个模式,以下模式(但不限于)实现了 IoC 原则。

Spring IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 IoC 容器负责创建对象,将对象连接在一起,配置这些对象,并从创建中处理这些对象的整个生命周期,直到它们被完全销毁。
在实际项目中一个 Service 类如果有几百甚至上千个类作为它的底层,我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IOC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
关于 Spring IOC 的理解,推荐看这一下知乎的一个回答:https://www.zhihu.com/question/23277575/answer/169698662 ,非常不错。
控制反转怎么理解呢? 举个例子:"对象 a 依赖了对象 b,当对象 a 需要使用 对象 b 的时候必须自己去创建。但是当系统引入了 IOC 容器后, 对象 a 和对象 b 之前就失去了直接的联系。这个时候,当对象 a 需要使用 对象 b 的时候, 我们可以指定 IOC 容器去创建一个对象 b 注入到对象 a 中"。 对象 a 获得依赖对象 b 的过程,由主动行为变为了被动行为,控制权反转,这就是控制反转名字的由来。
...
2023年2月8日 16:08 周三转载自https://github.com/Snailclimb/JavaGuide(添加小部分笔记)感谢作者!
前段时间答应读者的 Spring 事务 分析总结终于来了。这部分内容比较重要,不论是对于工作还是面试,但是网上比较好的参考资料比较少。
什么是事务?
#
事务是逻辑上的一组操作,要么都执行,要么都不执行。
相信大家应该都能背上面这句话了,下面我结合我们日常的真实开发来谈一谈。
我们系统的每个业务方法可能包括了多个原子性的数据库操作,比如下面的 savePerson() 方法中就有两个原子性的数据库操作。这些原子性的数据库操作是有依赖的,它们要么都执行,要不就都不执行。
public void savePerson() {
personDao.save(person);
personDetailDao.save(personDetail);
}
另外,需要格外注意的是:事务能否生效数据库引擎是否支持事务是关键。比如常用的 MySQL 数据库默认使用支持事务的 innodb引擎。但是,如果把数据库引擎变为 myisam,那么程序也就不再支持事务了!
事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账 1000 元,这个转账会涉及到两个关键操作就是:
- 将小明的余额减少 1000 元。
- 将小红的余额增加 1000 元。
万一在这两个操作之间突然出现错误比如银行系统崩溃或者网络故障,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。
public class OrdersService {
private AccountDao accountDao;
public void setOrdersDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT, readOnly = false, timeout = -1)
public void accountMoney() {
//小红账户多1000
accountDao.addMoney(1000,xiaohong);
//模拟突然出现的异常,比如银行中可能为突然停电等等
//如果没有配置事务管理的话会造成,小红账户多了1000而小明账户没有少钱
int i = 10 / 0;
//小王账户少1000
accountDao.reduceMoney(1000,xiaoming);
}
}
另外,数据库事务的 ACID 四大特性是事务的基础,下面简单来了解一下。
...
2023年2月8日 14:56 周三转载自https://github.com/Snailclimb/JavaGuide(添加小部分笔记)感谢作者!
0.前言
#
可以毫不夸张地说,这篇文章介绍的 Spring/SpringBoot 常用注解基本已经涵盖你工作中遇到的大部分常用的场景。对于每一个注解我都说了具体用法,掌握搞懂,使用 SpringBoot 来开发项目基本没啥大问题了!
为什么要写这篇文章?
最近看到网上有一篇关于 SpringBoot 常用注解的文章被转载的比较多,我看了文章内容之后属实觉得质量有点低,并且有点会误导没有太多实际使用经验的人(这些人又占据了大多数)。所以,自己索性花了大概 两天时间简单总结一下了。
因为我个人的能力和精力有限,如果有任何不对或者需要完善的地方,请帮忙指出!Guide 哥感激不尽!
1. @SpringBootApplication
#
这里先单独拎出@SpringBootApplication 注解说一下,虽然我们一般不会主动去使用它。
Guide 哥:这个注解是 Spring Boot 项目的基石,创建 SpringBoot 项目之后会默认在主类加上。
@SpringBootApplication
public class SpringSecurityJwtGuideApplication {
public static void main(java.lang.String[] args) {
SpringApplication.run(SpringSecurityJwtGuideApplication.class, args);
}
}
我们可以把 @SpringBootApplication看作是 @Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合。
package org.springframework.boot.autoconfigure;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
......
}
package org.springframework.boot;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
根据 SpringBoot 官网,这三个注解的作用分别是:
...
2023年2月7日 16:48 周二转载自https://github.com/Snailclimb/JavaGuide(添加小部分笔记)感谢作者!
这篇文章主要是想通过一些问题,加深大家对于 Spring 的理解,所以不会涉及太多的代码!
下面的很多问题我自己在使用 Spring 的过程中也并没有注意,自己也是临时查阅了很多资料和书籍补上的。网上也有一些很多关于 Spring 常见问题/面试题整理的文章,我感觉大部分都是互相 copy,而且很多问题也不是很好,有些回答也存在问题。所以,自己花了一周的业余时间整理了一下,希望对大家有帮助。
Spring 基础
#
什么是 Spring 框架?
#
Spring 是一款开源的轻量级 Java 开发框架,旨在提高开发人员的开发效率以及系统的可维护性。
我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发,比如说 Spring 支持 IoC(Inversion of Control:控制反转) 和 AOP(Aspect-Oriented Programming:面向切面编程)、可以很方便地对数据库进行访问、可以很方便地集成第三方组件(电子邮件,任务,调度,缓存等等)、对单元测试支持比较好、支持 RESTful Java 应用程序的开发。
[
Spring 最核心的思想就是不重新造轮子,开箱即用,提高开发效率。
Spring 翻译过来就是春天的意思,可见其目标和使命就是为 Java 程序员带来春天啊!感动!
🤐 多提一嘴 : 语言的流行通常需要一个杀手级的应用,Spring 就是 Java 生态的一个杀手级的应用框架。
Spring 提供的核心功能主要是 IoC 和 AOP。学习 Spring ,一定要把 IoC 和 AOP 的核心思想搞懂!
Spring 包含的模块有哪些?
#
Spring4.x 版本 :
...
2023年2月7日 16:14 周二转载自https://github.com/Snailclimb/JavaGuide(添加小部分笔记)感谢作者!
版本控制
#
什么是版本控制
#
版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。 除了项目源代码,你还可以对任何类型的文件进行版本控制。
为什么要版本控制
#
有了它你就可以将某个文件回溯到之前的状态,甚至将整个项目都回退到过去某个时间点的状态,你可以比较文件的变化细节,查出最后是谁修改了哪个地方,从而找出导致怪异问题出现的原因,又是谁在何时报告了某个功能缺陷等等。
本地版本控制系统
#
许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别。 这么做唯一的好处就是简单,但是特别容易犯错。 有时候会混淆所在的工作目录,一不小心会写错文件或者覆盖意想外的文件。
为了解决这个问题,人们很久以前就开发了许多种本地版本控制系统,大多都是采用某种简单的数据库来记录文件的历次更新差异。

集中化的版本控制系统
#
接下来人们又遇到一个问题,如何让在不同系统上的开发者协同工作? 于是,集中化的版本控制系统(Centralized Version Control Systems,简称 CVCS)应运而生。
集中化的版本控制系统都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。

这么做虽然解决了本地版本控制系统无法让在不同系统上的开发者协同工作的诟病,但也还是存在下面的问题:
- 单点故障: 中央服务器宕机,则其他人无法使用;如果中心数据库磁盘损坏又没有进行备份,你将丢失所有数据。本地版本控制系统也存在类似问题,只要整个项目的历史记录被保存在单一位置,就有丢失所有历史更新记录的风险。
- 必须联网才能工作: 受网络状况、带宽影响。
分布式版本控制系统
#
于是分布式版本控制系统(Distributed Version Control System,简称 DVCS)面世了。 Git 就是一个典型的分布式版本控制系统。
这类系统,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。 这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。 因为每一次的克隆操作,实际上都是一次对代码仓库的完整备份。

分布式版本控制系统可以不用联网就可以工作,因为每个人的电脑上都是完整的版本库,当你修改了某个文件后,你只需要将自己的修改推送给别人就可以了。但是,在实际使用分布式版本控制系统的时候,很少会直接进行推送修改,而是使用一台充当“中央服务器”的东西。这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
分布式版本控制系统的优势不单是不必联网这么简单,后面我们还会看到 Git 极其强大的分支管理等功能。
认识 Git
#
Git 简史
#
Linux 内核项目组当时使用分布式版本控制系统 BitKeeper 来管理和维护代码。但是,后来开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用 BitKeeper 时的经验教训,开发出自己的版本系统,而且对新的版本控制系统做了很多改进。
...
2023年2月7日 13:28 周二转载自https://github.com/Snailclimb/JavaGuide(添加小部分笔记)感谢作者!
这部分内容主要根据 Maven 官方文档整理,做了对应的删减,主要保留比较重要的部分,不涉及实战,主要是一些重要概念的介绍。
Maven 介绍
#
Maven 官方文档是这样介绍的 Maven 的:
Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project’s build, reporting and documentation from a central piece of information.
Apache Maven 的本质是一个软件项目管理和理解工具。基于项目对象模型 (Project Object Model,POM) 的概念,Maven 可以从一条中心信息 管理项目的构建、报告和文档。
什么是 POM? 每一个 Maven 工程都有一个 pom.xml 文件,位于根目录中,包含项目构建生命周期的详细信息。通过 pom.xml 文件,我们可以定义项目的坐标、项目依赖、项目信息、插件信息等等配置。
对于开发者来说,Maven 的主要作用主要有 3 个:
- 项目构建 :提供标准的、跨平台的自动化项目构建方式。
- 依赖管理 :方便快捷的管理项目依赖的资源(jar 包),避免资源间的版本冲突问题。
- 统一开发结构 :提供标准的、统一的项目结构。
关于 Maven 的基本使用这里就不介绍了,建议看看官网的 5 分钟上手 Maven 的教程:
Maven in 5 Minutes 。
...
2023年2月3日 11:04 周五Java实现CAS的原理[非javaguide]
#
i是非线程安全的,因为**i不是原子操作;可以使用synchronized和CAS实现加锁**
synchronized是悲观锁,一旦获得锁,其他线程进入后就会阻塞等待锁;而CAS是乐观锁,执行时不会加锁,假设没有冲突,如果因为冲突失败了就重试,直到成功
其中i为V,5为E,6为N
CAS是一种原子操作,它是一种系统原语,是一条CPU原子指令,从CPU层面保证它的原子性(不可能出现说,判断了对比了i为5之后,正准备更新它的值,此时该值被其他线程改了)
当多个线程同时使用CAS操作一个变量时,只有一个会胜出,并成功更新,其余均会失败,但失败的线程并不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。
Java实现CAS的原理 - Unsafe类
}
}
...