“程序员必备的面试技巧,就像是编写一段完美的代码一样重要。在面试战场上,我们需要像忍者一样灵活,像侦探一样聪明,还要像无敌铁金刚一样坚定。只有掌握了这些技巧,我们才能在面试的舞台上闪耀光芒,成为那个令HR们心动的程序猿!”
> 提醒:在发布作品前,请把不需要的内容删掉。
?
方向1:面试知识点
一、Spring、SpringMVC:Spring常用注解、IOC、DI、AOP、事务管理、mybatis整合 springboot启动原理,多数据源
Spring框架
Spring常用注解
?以下是Spring的常用注解及其作用、使用场景和所在位置: ?? ?1. @Component:修饰类,当扫描到该注解时,会将该类的对象注册到IOC容器当中; ? ? ? ? ? ? ? 等同于bean标签,默认的id为首字母小写的类名 添加位置:类定义之前。 ?? ?2. @ResponseBody:加了这个注解的类会将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML。添加位置:方法定义之前。 ?? ?3. @Retention:决定了注解的生命周期,用于创建自定义注解时使用。添加位置:自定义注解上。 ?? ?4. @Target:决定了自定义注解的使用范围(可以加在哪些成份上,比如接口、方法或者属性上)。添加位置:自定义注解上。 ?? ?5. @PostConstruct:在spring初始化bean时会调用加了该注解的方法,一般用于给bean属性赋值。添加位置:bean中初始化要spring执行的方法上。 ?? ?6. @Autowired:一般用来修饰成员变量,会将IOC容器当中合适的对象注入给该成员变量 ? ? 默认是ByType ?? ?7. @Resource:注入bean,先根据name后根据type扫描注入,jdk自带的注解。添加位置:变量定义之前或方法 定义之前。 ?? ?8. @Controller:子注解只是让@Component见名知义,功能和@Component是一样的 ? ? ? ? ? ? ? ? ? ? ? @Controller、@Service、@Repository等等 ?? ?10.@Repository:用于标注数据访问组件,通常用于处理数据访问操作。添加位置:类定义之前。 ?? ?11.@RestController:用于标注控制层组件,通常用于处理用户请求并返回数据对象。添加位置:类定义之前。 ?? ?12.@RequestMapping:用于映射请求URL到处理方法,可以标注在类或方法上。添加位置:类或方法定义之前。 ?? ?13.@GetMapping:用于映射GET请求到处理方法。添加位置:方法定义之前。 ?? ?14.@PostMapping:用于映射POST请求到处理方法。添加位置:方法定义之前。 ?? ?15.@PutMapping:用于映射PUT请求到处理方法。添加位置:方法定义之前。 ?? ?16.@DeleteMapping:用于映射DELETE请求到处理方法。添加位置:方法定义之前。 ?? ?17.@PathVariable:用于绑定URL路径参数到方法参数。添加位置:方法参数定义之前。 ?? ?18.@RequestParam:用于绑定请求参数到方法参数。添加位置:方法参数定义之前。 ?? ?19.@RequestBody:用于绑定请求体到方法参数。添加位置:方法参数定义之前。 ?? ?20.@ResponseBody:用于将方法返回值直接写入HTTP响应体。添加位置:方法定义之前。 ?? ?21.@ComponentScan:用于指定Spring扫描组件的包路径。添加位置:类定义之前。 ?? ?22.@Configuration:用于标注配置类,该类包含Spring容器的配置信息。添加位置:类定义之前。 ?? ?23.@Bean:用于声明将一个方法的返回值注册为Spring容器中的Bean。添加位置:方法定义之前。 ?? ?25.@Qualifier:按照byName来注入,value:IOC中已注册对象的id值,按照value去获取对象注入进来添加位置:变量定义之前或方法参数定义之前。 ?? ?26.@Value:用于注入属性值,可以从配置文件或注解中获取值。添加位置:变量定义之前或方法参数定义之前。 ?? ?27.@Profile:用于指定某个Bean只在特定的环境下生效,例如开发环境、测试环境或生产环境。添加位置:类定义之前或方法定义之前。IOC: 将控制权从应用程序的代码转移到框架或容器中,框架或容器负责创建和管理对象,并在需要时将它们注入到应用程序中
控制反转,Spring框架中其它功能都是依赖于IOC来实现,将对象交给spring来管理 ? 1.对象生命周期的管理:对象的创建、对象的初始化、对象的销毁等等。对象通常被称为bean ? 2.对象之间依赖关系管理:DI
DI:
依赖注入:容器动态的将某个依赖关系注入到组件之中。为了提升组件重用率。
属性注入(settter注入):property(属性是类或对象的成员变量)、ref(引用) 一个对象或变量对另一个对象的指向或引用
?<!-- 配置UserRepository Bean --> ?<bean id="userRepository" class="com.example.UserRepository" /> ?? ?<!-- 配置UserService Bean,并使用属性注入注入UserRepository依赖 --> ?<bean id="userService" class="com.example.UserService"> ? ? ?<property name="userRepository" ref="userRepository" /> ?</bean> ? ? ? ? ? ?public class UserService { ? ? ?private UserRepository userRepository; ?? ? ? ?public void setUserRepository(UserRepository userRepository) { ? ? ? ? ?this.userRepository = userRepository; ? ? } ?} ??构造器注入:constructor-arg 肯死抓可特儿
?<!-- 配置UserRepository Bean --> ?<bean id="userRepository" class="com.example.UserRepository" /> ?? ?<!-- 配置UserService Bean,并使用构造器注入注入UserRepository依赖 --> ?<bean id="userService" class="com.example.UserService全限定类名"> ? ? ?<constructor-arg name="名称" ref="userRepository引用" /> ?</bean> ?? ?? ?public class UserService { ? ? ?private UserRepository userRepository; ?? ? ? ?public UserService(UserRepository userRepository) { ? ? ? ? ?this.userRepository = userRepository; ? ? } ?} ??构造函数注入和setter注入的区别:
注:构造函数注入是构造器注入的一种,setter注入就是属性注入
构造函数注入 setter注入 没有部分注入 有部分注入 不会覆盖srtter属性 会覆盖setter属性 任意修改都会创建一个新的实例 任意修改不会创建一个新实例 适用于设置很多属性 适用于设置少量属性 部分注入:
部分注入是指只注入某个类的部分属性或依赖对象,而不是全部属性或依赖对象。在Spring框架中,可以通过配置<property>元素的name属性来指定需要注入的属性名称,从而实现部分注入。此外,也可以使用@Autowired注解和@Qualifier注解结合使用,实现更精细的部分注入。部分注入可以满足更加灵活的需求,例如在某些情况下,只需要注入部分属性或依赖对象就可以完成某个操作。
自动装配:
按名称自动装配(byName): 按名称自动装配是通过Bean的名称与属性名称匹配来进行依赖注入的方式。如果目标Bean的属性名称与另一个Bean的名称相匹配,Spring容器将自动将这个Bean注入到目标Bean中。 示例:
?<!-- 配置两个Bean,其中userRepository的名称匹配了userService中的userRepository属性 --> ?<bean id="userRepository" class="com.example.UserRepository" /> ?<bean id="userService" class="com.example.UserService" autowire="byName"> ? ? ?<!-- userRepository属性会自动装配 --> ?</bean>
按类型自动装配(byType): 按类型自动装配是通过Bean的类型与属性类型匹配来进行依赖注入的方式。如果目标Bean的属性类型与另一个Bean的类型相匹配,Spring容器将自动将这个Bean注入到目标Bean中。 示例:
? <!-- 配置两个Bean,其中userRepository的类型匹配了userService中的UserRepository属性的类型 --> ?<bean id="userRepository" class="com.example.UserRepository" /> ?<bean id="userService" class="com.example.UserService" autowire="byType"> ? <!-- userRepository属性会自动装配 --> ?</bean>
构造器自动装配(constructor): 构造器自动装配是通过构造函数的参数类型与Bean的类型匹配来进行依赖注入的方式。如果目标Bean的构造函数参数类型与另一个Bean的类型相匹配,Spring容器将自动将这个Bean注入到目标Bean的构造函数中。 示例:
? <!-- 配置两个Bean,其中userRepository的类型匹配了userService的构造函数参数类型 --> ?<bean id="userRepository" class="com.example.UserRepository" /> ?<bean id="userService" class="com.example.UserService" autowire="constructor"> ? <!-- userService的构造函数参数会自动装配 --> ?</bean>mybatis整合:
配置Spring的数据源、mybatis的会话工厂、和事务管理器
1. Spring整合MyBatis示例:
示例代码:
DataSourceConfig.java
:配置数据源。?@Configuration ?public class DataSourceConfig { ? ? ?@Bean ? ? ?public DataSource dataSource() { ? ? ? ? ?DriverManagerDataSource dataSource = new DriverManagerDataSource(); ? ? ? ? ?dataSource.setDriverClassName("com.mysql.jdbc.Driver"); ? ? ? ? ?dataSource.setUrl("jdbc:mysql://localhost:3306/mydatabase"); ? ? ? ? ?dataSource.setUsername("username"); ? ? ? ? ?dataSource.setPassword("password"); ? ? ? ? ?return dataSource; ? ? } ?}
MyBatisConfig.java
:配置MyBatis。?@Configuration ?@MapperScan("com.example.dao") ?public class MyBatisConfig { ? ? ?@Autowired ? ? ?private DataSource dataSource; ?? ? ? ?@Bean ? ? ?public SqlSessionFactory sqlSessionFactory() throws Exception { ? ? ? ? ?SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); ? ? ? ? ?sessionFactory.setDataSource(dataSource); ? ? ? ? ?sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver() ? ? ? ? ? ? .getResources("classpath:mybatis/*Mapper.xml")); ? ? ? ? ?return sessionFactory.getObject(); ? ? } ?? ? ? ?@Bean ? ? ?public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { ? ? ? ? ?return new SqlSessionTemplate(sqlSessionFactory); ? ? } ?}
application.properties
:Spring配置文件,用于配置数据库连接、MyBatis会话工厂、Mapper扫描以及Service注册。?<!--导入属性文件--> ? ? ?<context:property-placeholder location="classpath:db.properties"></context:property-placeholder> ?<!-- 数据源配置 --> ?<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> ? ? ?<property name="driverClassName" value="com.mysql.jdbc.Driver" /> ? ? ?<property name="url" value="jdbc:mysql://localhost:3306/mydatabase" /> ? ? ?<property name="username" value="username" /> ? ? ?<property name="password" value="password" /> ?</bean> ?? ?<!-- 配置MyBatis的SqlSessionFactory ?指定数据源和Mapper文件位置--> ?<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> ? ? ?<property name="dataSource" ref="dataSource" /> ? ? ?<property name="mapperLocations" value="classpath:mapper/*Mapper.xml" /> ?</bean> ?? ?<!-- 配置MyBatis的Mapper扫描器 ?将dao接口的代理对象注册到IOC容器中; ?本质上就是将getMapper方法得到的对象注册 ?注册的dao对象的id默认为首字母小写dao接口的名称 ?--> ?<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> ? ? ?<property name="basePackage" value="com.example.dao" /> ?</bean> ?? ?<!-- 配置事务管理器 --> ?<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> ? ? ?<property name="dataSource" ref="dataSource" /> ?</bean> ?? ?<!-- 开启注解驱动 --> ?<context:component-scan base-package="com.example" /> ?<tx:annotation-driven /> ??AOP:
面向切面编程,可以将某些功能在运行期间织入到需要该功能的对象中
面向切面编程,它的底层是通过动态代理来实现的,通过生成目标对象的代理对象,将系统功能和对象功能在代理对象中进行有效结合。它包括以下几点:
目标对象:要被添加额外功能的对象
代理对象:根据目标对象生成的对象
连接点:需要被添加额外功能的方法
切点:本质是一个表达式,满足该表达式的方法,参会被添加额外功能
通知:定义额外功能的方法
前置通知(Before Advice): 在目标方法执行之前执行。前置通知通常用于执行一些预处理操作,例如身份验证、日志记录等。
后置通知(After Advice): 在目标方法执行之后执行,无论方法是否成功执行。后置通知通常用于执行清理或资源释放操作。
返回通知(After Returning Advice): 在目标方法成功执行并返回结果后执行。返回通知通常用于处理目标方法的返回值,例如日志记录、结果转换等。
异常通知(After Throwing Advice): 在目标方法抛出异常时执行。异常通知通常用于处理异常情况,例如发送警报或执行回滚操作。
环绕通知(Around Advice): 在目标方法之前和之后执行,并控制目标方法的执行流程。环绕通知具有最大的灵活性,可以完全替代目标方法的执行,也可以在执行前后添加额外的逻辑。
切面:Aspect,本质是一个java类,在类中定义了通知,有时也会定义切点
织入:根据目标对象和切面生成代理对象的过程
AOP可以用来进行日志和异常处理,使用通知进行处理。
AOP实现方式有:
静态代理: 编译期间确定的代理关系,代理类在编译时已经存在。
·编译时编织(特殊编译器实现)
·类加载时编织(特殊的类加载器实现)
动态代理: 动态代理是在运行时动态生成代理类的方式,通常使用Java的反射机制。
JDK动态代理:通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口
CGLIB动态代理:如果目标类没有接口,他会动态代理目标类
注册对象:
spring中
xml配置:可以使用bean元素配置id和class
注解:使用@Service、Component、@Repository等
Java配置:使用Java配置类注册Bean,创建一个Java类,并使用@Configuration和@Bean注解,可以将Bean定义在Java类中
SpringMVC中使用@Controller:标识控制器类和@RequestMapping:用于指定请求的映射路径
Service层用@Service
Spring事务管理
Spring事务是Spring框架提供的一种机制,用于管理数据库操作或其他资源的事务性操作。事务是一组操作,要么全部成功执行并提交,要么全部失败并回滚,以确保数据的一致性和可靠性。以下是与Spring事务相关的一些重要知识点、其定义、作用和实现场景:
1. 事务(Transaction):
定义: 事务是一组相关的数据库操作,这些操作要么全部成功执行,要么全部失败并回滚,以维护数据的一致性和完整性。
作用: 确保数据库操作的一致性,当发生故障或错误时,保证数据库的数据状态不被破坏。
实现场景: 数据库操作、文件操作、消息队列操作等任何需要一致性和可靠性的场景。
2. 事务管理器(Transaction Manager):
定义: 事务管理器是Spring框架提供的接口,用于管理事务的生命周期,它负责事务的开始、提交和回滚。
作用: 管理事务的状态,决定何时开始、提交或回滚事务,以确保事务的完整性。
实现场景: 与不同的数据源(如数据库、消息队列)集成,管理各种资源的事务。
3. 事务传播行为(Transaction Propagation):
定义: 事务传播行为定义了在多个事务之间调用方法时,如何处理事务的行为。
作用: 控制方法之间事务的嵌套和交互,确保在方法调用期间事务的一致性。
实现场景: 当一个方法调用另一个方法,并且这些方法涉及事务操作时,定义事务传播行为以确保事务的正确管理。
4. 事务隔离级别(Isolation Level):
定义: 事务隔离级别定义了多个并发事务之间的相互影响程度。常见的隔离级别包括读未提交、读已提交、可重复读和串行化。
作用: 控制事务之间的隔离程度,以防止并发访问数据时出现问题,如脏读、不可重复读和幻读。
实现场景: 需要在高并发环境下维护数据的一致性。
5. 声明式事务管理(Declarative Transaction Management):
定义: 声明式事务管理是一种使用注解或XML配置的方式来定义事务行为,而无需在代码中编程式管理事务。
作用: 简化事务管理,将事务逻辑与业务逻辑分离,提高代码的可读性和可维护性。
实现场景: 大多数业务场景,特别是使用Spring框架的应用程序。
6. 编程式事务管理(Programmatic Transaction Management):
定义: 编程式事务管理是通过编写代码来显式管理事务的方式,使用编程接口如
TransactionTemplate
。作用: 提供更精细的控制,允许在代码中编写自定义的事务逻辑。
实现场景: 需要复杂的事务逻辑或与不支持注解的框架集成的情况。
7. 本地事务(Local Transaction):
定义: 本地事务是指只涉及单个数据源(如单个数据库)的事务,由本地事务管理器管理。
作用: 管理与单个数据源相关的事务,确保数据的一致性。
实现场景: 单个数据库操作的业务逻辑。
8. 分布式事务(Distributed Transaction):
定义: 分布式事务是指涉及多个数据源的事务,例如在不同的数据库或系统之间进行操作。
作用: 管理多个数据源之间的事务,确保多个系统之间的操作的一致性和可靠性。
实现场景: 跨越多个系统或数据库的业务逻辑,如微服务架构中的事务管理。
Spring事务管理是构建可靠和高性能应用程序的关键组成部分,它可以根据不同的场景和需求提供不同的配置选项和控制级别。通过适当地选择和配置事务管理机制,可以确保应用程序的数据一致性,并提供高度可维护的代码。
Spring的工厂模式
Spring框架中的工厂模式是一种设计模式,它用于创建和管理对象实例,从而将对象的创建和使用分离开,以提高代码的松耦合性和可维护性。Spring中的工厂模式主要体现在以下两种方式:
BeanFactory(工厂模式): Spring的
BeanFactory
是一种工厂模式的实现。它是Spring IoC容器的核心,负责创建、配置和管理Bean对象的实例。开发者通过配置文件或注解来定义Bean,然后通过BeanFactory
来获取这些Bean的实例。这种方式将对象的创建和管理交给了Spring容器,从而实现了对象的解耦和可维护性。?BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml")); ?MyBean myBean = (MyBean) factory.getBean("myBean");ApplicationContext(应用上下文):
ApplicationContext
是BeanFactory
的扩展,它是一种更高级的工厂模式实现。除了BeanFactory的功能外,ApplicationContext
还提供了更多的高级功能,如AOP、事务管理、国际化、事件发布等。它也是Spring框架中广泛使用的工厂模式的体现。?ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml"); ?MyBean myBean = context.getBean("myBean", MyBean.class);在Spring中,工厂模式的使用使得开发者可以将对象的创建和配置集中管理,从而降低了代码的复杂性,提高了可维护性和可扩展性。这也符合Spring框架的核心理念之一,即控制反转(IoC)和依赖注入(DI),其中工厂模式是IoC的一个关键实现方式。通过工厂模式,开发者将对象的创建交给了容器,从而更好地管理了应用程序的组件。
BeanFactory和ApplicationContext的区别
BeanFactory ApplicationContext 它使用懒加载 它使用即时加载 它使用语法显示提供资源对象 它自己创建和管理资源对象 不支持国际化 支持国际化 不支持基于依赖的注解 支持基于依赖的注解 BeanFactory:
优点:应用启动时占用资源少,对资源要求较高的应用,比较有优势
缺点:运行速度较慢。可能会有空指针异常错误。通过Bean工厂创建的Bean生命周期会简单一些
ApplicationContext:
优点:所有Bean在启动时都进行了加载,系统运行的速度快;在启动的时候,可以发现系统中的配置问题
缺点:把费时的操作放在系统启动中完成,所有的对象都可以预加载,缺点就是内存占用较大
SpringMvc文件上传
MultipartFile 读作:moteipartFile
在Spring MVC中,要实现文件上传功能,你可以通过以下步骤来操作:
添加文件上传配置:首先,确保你的Spring MVC项目已正确配置
multipartResolver
以支持文件上传。通常,Spring Boot应用程序已经自动配置了MultipartAutoConfiguration
,因此你只需确保添加了spring-boot-starter-web
依赖。?<dependency> ? ? ?<groupId>org.springframework.boot</groupId> ? ? ?<artifactId>spring-boot-starter-web</artifactId> ?</dependency>如果你在Spring MVC中手动配置,确保在Spring配置文件中添加以下配置:
?<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> ? ? ?<!-- 配置上传文件大小限制 --> ? ? ?<property name="maxUploadSize" value="10000000"/> <!-- 10MB --> ?</bean>创建上传表单:在你的HTML表单中添加文件上传字段,通常使用
<input type="file">
标签。例如:?<form action="/upload" method="POST" enctype="multipart/form-data"> ? ? ?<input type="file" name="file"> ? ? ?<input type="submit" value="上传文件"> ?</form>注意,表单的
enctype
属性必须设置为multipart/form-data
,以支持文件上传。编写Controller处理文件上传:在你的Spring MVC控制器中编写方法来处理文件上传请求。使用
@RequestParam
注解来接收上传的文件,并将其保存到服务器或进行其他操作。例如:?import org.springframework.stereotype.Controller; ?import org.springframework.web.bind.annotation.*; ?import org.springframework.web.multipart.MultipartFile; ?? ?@Controller ?public class FileUploadController { ?? ? ? ?@PostMapping("/upload") ? ? ?public String handleFileUpload(@RequestParam("file") MultipartFile file) { ? ? ? ? ?if (!file.isEmpty()) { ? ? ? ? ? ? ?try { ? ? ? ? ? ? ? ? ?// 获取文件名 ? ? ? ? ? ? ? ? ?String fileName = file.getOriginalFilename(); ? ? ? ? ? ? ? ? ?// 文件保存路径,你可以根据需求自定义 ? ? ? ? ? ? ? ? ?String filePath = "/path/to/save/uploads/" + fileName; ? ? ? ? ? ? ? ? ?// 保存文件 ? ? ? ? ? ? ? ? ?file.transferTo(new File(filePath)); ? ? ? ? ? ? ? ? ?// 文件上传成功,执行其他操作 ? ? ? ? ? ? ? ? ?return "redirect:/success"; // 重定向到成功页面 ? ? ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? ? ? ?e.printStackTrace(); ? ? ? ? ? ? ? ? ?// 处理文件上传异常 ? ? ? ? ? ? ? ? ?return "redirect:/error"; // 重定向到错误页面 ? ? ? ? ? ? } ? ? ? ? } else { ? ? ? ? ? ? ?// 文件为空 ? ? ? ? ? ? ?return "redirect:/error"; // 重定向到错误页面 ? ? ? ? } ? ? } ?}上述代码中,
handleFileUpload
方法接收名为"file"的上传文件,并将其保存到服务器上指定的路径。你可以根据需要修改文件保存路径和处理逻辑。配置上传文件大小限制:如果需要限制上传文件的大小,可以在
multipartResolver
的配置中设置maxUploadSize
属性,以限制文件的最大大小。创建成功和错误页面:根据上传结果,你可以创建成功和错误页面,以提供给用户相应的反馈信息。
测试文件上传:最后,启动你的Spring MVC应用程序,并访问包含文件上传表单的页面,测试文件上传功能。
这些是在Spring MVC中实现文件上传的基本步骤。根据你的项目需求,你可以进一步定制文件上传的行为,如检查文件类型、生成文件名、处理多个文件上传等。请根据实际情况进行适当的调整和扩展。