SPRINGBOOT启动流程及其原理
https://blog.csdn.net/u014352080/article/details/102716468
https://segmentfault.com/a/1190000014525138
Spring Boot、Spring MVC 和 Spring 有什么区别?
分别描述各自的特征:
Spring 框架就像一个家族,有众多衍生产品例如 boot、security、jpa等等;但他们的基础都是Spring 的ioc和 aop,ioc 提供了依赖注入的容器, aop解决了面向切面编程,然后在此两者的基础上实现了其他延伸产品的高级功能。
Spring MVC提供了一种轻度耦合的方式来开发web应用;它是Spring的一个模块,是一个web框架;通过DispatcherServlet, ModelAndView 和 View Resolver,开发web应用变得很容易;解决的问题领域是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。
Spring Boot实现了auto-configuration自动配置(另外三大神器actuator监控,cli命令行接口,starter依赖),降低了项目搭建的复杂度。它主要是为了解决使用Spring框架需要进行大量的配置太麻烦的问题,所以它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具;同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box)。
所以,用最简练的语言概括就是:
Spring 是一个“引擎”;
Spring MVC 是基于Spring的一个 MVC 框架;
Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。
一 springboot启动原理及相关流程概览
springboot是基于spring的新型的轻量级框架,最厉害的地方当属自动配置。那我们就可以根据启动流程和相关原理来看看,如何实现传奇的自动配置。
二 springboot的启动类入口
用过springboot的技术人员很显而易见的两者之间的差别就是视觉上很直观的:springboot有自己独立的启动类(独立程序)
1
2
3
4
5
6
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
从上面代码可以看出,Annotation定义(@SpringBootApplication)和类定义(SpringApplication.run)最为耀眼,所以要揭开SpringBoot的神秘面纱,我们要从这两位开始就可以了。
三 单单是SpringBootApplication接口用到了这些注解
1
2
3
4
5
6
7
8
9
10
11
12
@Target(ElementType.TYPE) // 注解的适用范围,其中TYPE用于描述类、接口(包括包注解类型)或enum声明
@Retention(RetentionPolicy.RUNTIME) // 注解的生命周期,保留到class文件中(三个生命周期)
@Documented // 表明这个注解应该被javadoc记录
@Inherited // 子类可以继承该注解
@SpringBootConfiguration // 继承了Configuration,表示当前是注解类
@EnableAutoConfiguration // 开启springboot的注解功能,springboot的四大神器之一,其借助@import的帮助
@ComponentScan(excludeFilters = { // 扫描路径设置(具体使用待确认)
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
在其中比较重要的有三个注解,分别是:
1)@SpringBootConfiguration // 继承了Configuration,表示当前是注解类
2)@EnableAutoConfiguration // 开启springboot的注解功能,springboot的四大神器之一,其借助@import的帮助
3)@ComponentScan(excludeFilters = { // 扫描路径设置(具体使用待确认)
接下来对三个注解一一详解,增加对springbootApplication的理解:
1)@Configuration注解
按照原来xml配置文件的形式,在springboot中我们大多用配置类来解决配置问题
配置bean方式的不同:
a)xml配置文件的形式配置bean
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
default-lazy-init="true">
<!--bean定义-->
</beans>
b)java configuration的配置形式配置bean
1
2
3
4
@Configuration
public class MockConfiguration{
//bean定义
}
注入bean方式的不同:
a)xml配置文件的形式注入bean
1
2
3
<bean id="mockService" class="..MockServiceImpl">
...
</bean>
b)java configuration的配置形式注入bean
1
2
3
4
5
6
7
@Configuration
public class MockConfiguration{
@Bean
public MockService mockService(){
return new MockServiceImpl();
}
}
任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器,方法名将默认成该bean定义的id。
表达bean之间依赖关系的不同:
a)xml配置文件的形式表达依赖关系
1
2
3
4
<bean id="mockService" class="..MockServiceImpl">
<propery name ="dependencyService" ref="dependencyService" />
</bean>
<bean id="dependencyService" class="DependencyServiceImpl"></bean>
b)java configuration配置的形式表达依赖关系(重点)
如果一个bean A的定义依赖其他bean B,则直接调用对应的JavaConfig类中依赖bean B的创建方法就可以了。
1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class MockConfiguration{
@Bean
public MockService mockService(){
return new MockServiceImpl(dependencyService());
}
@Bean
public DependencyService dependencyService(){
return new DependencyServiceImpl();
}
}
2) @ComponentScan注解
作用:a)对应xml配置中的元素;
b) (重点)ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义;
c) 将这些bean定义加载到IoC容器中.
我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。
注:所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages
3) @EnableAutoConfiguration
此注解顾名思义是可以自动配置,所以应该是springboot中最为重要的注解。
在spring框架中就提供了各种以@Enable开头的注解,例如: @EnableScheduling、@EnableCaching、@EnableMBeanExport等; @EnableAutoConfiguration的理念和做事方式其实一脉相承简单概括一下就是,借助@Import的支持,收集和注册特定场景相关的bean定义。
@EnableScheduling是通过@Import将Spring调度框架相关的bean定义都加载到IoC容器【定时任务、时间调度任务】
@EnableMBeanExport是通过@Import将JMX相关的bean定义加载到IoC容器【监控JVM运行时状态】
@EnableAutoConfiguration也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。
@EnableAutoConfiguration作为一个复合Annotation,其自身定义关键信息如下:
1
2
3
4
5
6
7
8
9
10
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage【重点注解】
@Import(AutoConfigurationImportSelector.class)【重点注解】
public @interface EnableAutoConfiguration {
...
}
其中最重要的两个注解已经标注:1、@AutoConfigurationPackage【重点注解】2、@Import(AutoConfigurationImportSelector.class)【重点注解】
当然还有其中比较重要的一个类就是:EnableAutoConfigurationImportSelector.class
AutoConfigurationPackage注解:
1
2
3
4
5
6
7
8
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
通过@Import(AutoConfigurationPackages.Registrar.class)
1
2
3
4
5
6
7
8
9
10
11
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
……
}
它其实是注册了一个Bean的定义;
new PackageImport(metadata).getPackageName(),它其实返回了当前主程序类的同级以及子级的包组件(重点);
(重点)那这总体就是注册当前主程序类的同级以及子级的包中的符合条件的Bean的定义?
以上图为例,DemoApplication是和demo包同级,但是demo2这个类是DemoApplication的父级,和example包同级
也就是说,DemoApplication启动加载的Bean中,并不会加载demo2,这也就是为什么,我们要把DemoApplication放在项目的最高级中。
Import(AutoConfigurationImportSelector.class)注解
(重点)可以从图中看出 AutoConfigurationImportSelector 实现了 DeferredImportSelector 从 ImportSelector继承的方法:selectImports。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
第9行List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);其实是去加载各个组件jar下的 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";外部文件。
该方法在springboot启动流程——bean实例化前被执行,返回要实例化的类信息列表;
如果获取到类信息,spring可以通过类加载器将类加载到jvm中,现在我们已经通过spring-boot的starter依赖方式依赖了我们需要的组件,那么这些组件的类信息在select方法中就可以被获取到。
1
2
3
4
5
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
其返回一个自动配置类的类名列表,方法调用了loadFactoryNames方法,查看该方法
1
2
3
4
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
自动配置器会跟根据传入的factoryClass.getName()到项目系统路径下所有的spring.factories文件中找到相应的key,从而加载里面的类。
这个外部文件,有很多自动配置的类。如下:
(重点)其中,最关键的要属@Import(AutoConfigurationImportSelector.class),借助AutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件(spring.factories)的bean定义(如Java Config@Configuration配置)都加载到当前SpringBoot创建并使用的IoC容器。就像一只“八爪鱼”一样。
自动配置幕后英雄:SpringFactoriesLoader详解
借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自动配置功效才得以大功告成!
SpringFactoriesLoader属于Spring框架私有的一种扩展方案,其主要功能就是从指定的配置文件META-INF/spring.factories加载配置,加载工厂类。
SpringFactoriesLoader为Spring工厂加载器,该对象提供了loadFactoryNames方法,入参为factoryClass和classLoader即需要传入工厂类名称和对应的类加载器,方法会根据指定的classLoader,加载该类加器搜索路径下的指定文件,即spring.factories文件;
传入的工厂类为接口,而文件中对应的类则是接口的实现类,或最终作为实现类。
1
2
3
4
5
6
7
8
9
10
11
public abstract class SpringFactoriesLoader {
//...
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
...
}
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
....
}
}
配合@EnableAutoConfiguration使用的话,它更多是提供一种配置查找的功能支持,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类
上图就是从SpringBoot的autoconfigure依赖包中的META-INF/spring.factories配置文件中摘录的一段内容,可以很好地说明问题。
(重点)所以,@EnableAutoConfiguration自动配置的魔法其实就变成了:
从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。
四 springboot启动流程概览图
五 深入探索SpringApplication执行流程
1
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered
EventPublishingRunListener实现了SpringApplicationRunListener接口;
实现了方法,下面是部分方法源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(
this.application, this.args, context));
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
.....................
简单了解下Bean的生命周期
一个Bean的构造函数初始化时是最先执行的,这个时候,bean属性还没有被注入;
@PostConstruct注解的方法优先于InitializingBean的afterPropertiesSet执行,这时Bean的属性竟然被注入了;
spring很多组件的初始化都放在afterPropertiesSet做,想和spring一起启动,可以放在这里启动;
spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中同过init-method指定,两种方式可以同时使用;
实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率相对来说要高点;但是init-method方式消除了对spring的依赖;
如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。
Bean在实例化的过程中:
Constructor > @PostConstruct > InitializingBean > init-method
BeanFactory 和ApplicationContext的区别
BeanFactory和ApplicationContext都是接口,并且ApplicationContext间接继承了BeanFactory。
BeanFactory是Spring中最底层的接口,提供了最简单的容器的功能,只提供了实例化对象和获取对象的功能,而ApplicationContext是Spring的一个更高级的容器,提供了更多的有用的功能。
ApplicationContext提供的额外的功能:获取Bean的详细信息(如定义、类型)、国际化的功能、统一加载资源的功能、强大的事件机制、对Web应用的支持等等。
加载方式的区别:BeanFactory采用的是延迟加载的形式来注入Bean;ApplicationContext则相反的,它是在Ioc启动时就一次性创建所有的Bean,好处是可以马上发现Spring配置文件中的错误,坏处是造成浪费。
1
2
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver
SpringMVC处理请求的流程
1、用户发送请求至前端控制器DispatcherServlet
2、DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、处理器映射器根据请求url找到具体的处理器,生成处理器对象Handler及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、DispatcherServlet通过HandlerAdapter(让Handler实现更加灵活)处理器适配器调用处理器
5、执行处理器(Controller,也叫后端控制器)。
6、Controller执行完成返回ModelAndView(连接业务逻辑层和展示层的桥梁,持有一个ModelMap对象和一个View对象)。
7、HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9、ViewReslover解析后返回具体View
10、DispatcherServlet对View进行渲染视图(将ModelMap模型数据填充至视图中)。
11、DispatcherServlet响应用户
BEANFACTORY和FACTORYBEAN的区别与联系
两者都是接口;
BeanFactory主要是用来创建Bean和获得Bean的;
FactoryBean跟普通Bean不同,其返回的对象不是指定类的一个实例,而是该FactoryBean的getObject方法所返回的对象;
通过BeanFactory和beanName获取bean时,如果beanName不加&则获取到对应bean的实例;如果beanName加上&,则获取到FactoryBean本身的实例
FactoryBean 通常是用来创建比较复杂的bean(如创建mybatis的SqlSessionFactory很复杂),一般的bean 直接用xml配置即可,但如果创建一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean。
社招阿里巴巴(新零售部门),三面被挂
阿里巴巴一面(55分钟)
先介绍一下自己吧
说一下自己的优缺点
具体讲一下之前做过的项目
你觉得项目里给里最大的挑战是什么?
Hashmap为什么不用平衡树?
AQS知道吗?知道哪一些呢?讲一讲。
CLH同步队列是怎么实现非公平和公平的?
ReetrantLock和synchronized的区别
讲一下JVM的内存结构
JVM 里 new 对象时,堆会发生抢占吗?你是怎么去设计JVM的堆的线程安全的?
讲一下redis的数据结构
redis缓存同步问题
讲一讲MySQL的索引结构
你有什么问题要问我吗?
直接口头通知我:答得不错,准备二面吧
阿里巴巴二面(45分钟)
根据项目问了一些细节问题
说一下HashMap的数据结构
红黑树和AVL树有什么区别?
如何才能得到一个线程安全的HashMap?
讲一下JVM常用垃圾回收期
redis分布式锁
再描述一下你之前的项目吧
你觉得这个项目的亮点在哪里呢?
你设计的数据库遵循的范式?
你有没有问题?
阿里巴巴三面(50分钟)
又聊项目
在项目中,并发量大的情况下,如何才能够保证数据的一致性?
elasticsearch为什么检索快,它的底层数据结构是怎么样的?
JVM内存模型
netty应用在哪些中间件和框架中呢?
线程池的参数
讲一下B树和B+树的区别
为什么要用redis做缓存?
了解Springboot吗?那讲一下Springboot的启动流程吧
如何解决bean的循环依赖问题?
Java有哪些队列?
讲一讲Spring和Springboot的区别
最近看了什么书?为什么?
你平时是怎么学习Java的呢?
内推阿里巴巴(阿里口碑)
5面拿offer(3轮技术面+总监面+HR面)
阿里巴巴一面(38分钟)- 自我介绍
介绍项目, 具体一点
讲一下Redis分布式锁的实现
HashMap了解么吗?说一下put方法过程
HashMap是不是线程安全?
ConcurrentHashMap如何保证线程安全?
数据库索引了解吗?讲一下
常见排序算法
TCP三次握手,四次挥手。
深入问了乐观锁,悲观锁及其实现。
阿里巴巴二面(45分钟)
自我介绍+项目介绍
你在项目中担任什么样的角色?
那你觉得你比别人的优势在哪里?你用了哪些别人没有的东西吗?
Java怎么加载类?
linux常用命令有哪些?
Spring的IOC, AOP。
讲一下ORM框架Hibernate
设计模式了解吗?讲一下
自己实现一个二阶段提交,如何设计?
你还有什么想问的?
阿里巴巴三面(30分钟)
说一下自己做的项目
问了一些项目相关的问题
wait()和sleep()的区别
原子变量的实现原理
CAS的问题,讲一下解决方案。
有没有更好的计数器解决策略
讲一讲NIO和BIO的区别
Nginx负载均衡时是如何判断某个节点挂掉了?
讲一下redis的数据类型和使用场景
k8s的储存方式是怎样的?
Spring AOP原理是什么?怎么使用?什么是切点,什么是切面?最好是举个例子
算法题:给一堆硬币的array,返回所有的组合
阿里巴巴总监面(34分钟)
算法:给一个set打印出所有子集;多线程从多个文件中读入数据,写到同一个文件中;判断ip是否在给定范围内;打乱一副扑克牌,不能用额外空间,证明为什么是随机的。
Tcp和udp区别
线程池的原理以及各种线程池的应用场景
线程池中使用有限的阻塞队列和无限的阻塞队列的区别
如果你发现你的sql语句始终走另一个索引,但是你希望它走你想要的索引,怎么办?
mysql执行计划
数据库索引为什么用b+树?
你在做sql优化主要从哪几个方面做,用到哪些方法工具?
有没有想问的?
阿里巴巴HR面(23分钟)
自我介绍
平时怎么学习的?
有什么兴趣爱好吗?
怎么看待996?
怎么平衡工作和学习?
有没有什么想问的
总结
社招时面试新零售部门,主要因为准备不充分,面试又比较紧张,所以发挥不是很好,三面之后没有了后续。之后意识到学习的重要性,平时多拿出时间来学习,后来幸运地拿到内推资格,为了把握住这次机会,做了很多准备,好在已经拿到offer。
在上周,我密集面试了若干位Java后端的候选人,工作经验在3到5年间。
我的标准其实不复杂:第一能干活,第二Java基础要好,第三最好熟悉些分布式框架。我相信其它公司招初级开发时,应该也照着这个标准来面的。
我也知道,不少候选人能力其实不差,但面试时没准备或不会说,这样的人可能在进团队干活后确实能达到期望,但可能就无法通过面试,但面试官总是只根据面试情况来判断。
但现实情况是,大多数人可能面试前没准备,或准备方法不得当。要知道,我们平时干活更偏重于业务,不可能大量接触到算法,数据结构,底层代码这类面试必问的问题点,换句话说,面试准备点和平时工作要点匹配度很小。
作为面试官,我只能根据候选人的回答来决定面试结果。不过,与人方便自己方便,所以我在本文里,将通过一些常用的问题来介绍面试的准备技巧。
大家在看后一定会感叹:只要方法得当,准备面试第一不难,第二用的时间也不会太多。
别让人感觉你只会山寨别人的代码
框架是重点,但别让人感觉你只会山寨别人的代码!
在面试前,我会阅读简历以查看候选人在框架方面的项目经验,在候选人的项目介绍的环节,我也会着重关注候选人最近的框架经验,目前比较热门的是SSM。
不过,一般工作在5年内的候选人,大多仅仅是能“山寨”别人的代码,也就是说能在现有框架的基础上,照着别人写的流程,扩展出新的功能模块。
比如要写个股票挂单的功能模块,是会模仿现有的下单流程,然后从前端到后端再到数据库,依样画葫芦写一遍,最多把功能相关的代码点改掉。
其实我们每个人都这样过来的,但在面试时,如果你仅仅表现出这样的能力,就和大多数人的水平差不多了,在这点就没法体现出你的优势了。
我们知道,如果单纯使用SSM框架,大多数项目都会有痛点。比如数据库性能差,或者业务模块比较复杂,并发量比较高,用Spring MVC里的Controller无法满足跳转的需求。
所以我一般还会主动问:你除了依照现有框架写业务代码时,还做了哪些改动?
我听到的回答有:增加了Redis缓存,以避免频繁调用一些不变的数据。
或者,在MyBitas的xml里,select语句where条件有isnull,即这个值有就增加一个where条件,对此,会对任何一个where增加一个不带isnull的查询条件,以免该语句当传入参数都是null时,做全表扫描。
或者,干脆说,后端异步返回的数据量很大,时间很长,我在项目里就调大了异步返回的最大时间,或者对返回信息做了压缩处理,以增加网络传输性能。
对于这个问题,我不在乎听到什么回答,我只关心回答符不符逻辑。一般只要答对,我就会给出“在框架层面有自己的体会,有一定的了解”,否则,我就只会给出“只能在项目经理带领下编写框架代码,对框架本身了解不多”。
其实,在准备面试时,归纳框架里的要点并不难,我就不信所有人在做项目时一点积累也没,只要你说出来,可以说,这方面你就碾压了将近7成的竞争者。
单机版够用?适当了解些分布式
别单纯看单机版的框架,适当了解些分布式!此外,在描述项目里框架技术时,最好你再带些分布式的技术。下面我列些大家可以准备的分布式技术。
1、反向代理方面,nginx的基本配置,比如如何通过lua语言设置规则,如何设置session粘滞。如果可以,再看些nginx的底层,比如协议,集群设置,失效转移等。
2、远程调用dubbo方面,可以看下dubbo和zookeeper整合的知识点,再深一步,了解下dubbo底层的传输协议和序列化方式。
3、消息队列方面,可以看下kafka或任意一种组件的使用方式,简单点可以看下配置,工作组的设置,再深入点,可以看下Kafka集群,持久化的方式,以及发送消息是用长连接还是短拦截。
以上仅仅是用3个组件举例,大家还可以看下Redis缓存,日志框架,MyCAT分库分表等。
准备的方式有两大类,第一是要会说怎么用,这比较简单,能通过配置文件搭建成一个功能模块即可,第二是可以适当读些底层代码,以此了解下协议,集群和失效转移之类的高级知识点。
如果能在面试中侃侃而谈分布式组件的底层,那么得到的评价就会比较好了,比如“深入了解框架底层”,或“框架经验丰富”,这样就算去面试架构师也行了,更何况是高级开发。
别只知道增删改查,得了解性能优化
数据库方面,别就知道增删改查,得了解性能优化!在实际项目里,大多数程序员用到的可能仅仅是增删改查,当我们用Mybatis时,这个情况更普遍。不过如果你面试时也这样表现,估计你的能力就和其它竞争者差不多了。
这方面,你可以准备如下的技能:
1、SQL高级方面,比如group by, having,左连接,子查询(带in),行转列等高级用法。
2、建表方面,你可以考虑下,你项目是用三范式还是反范式,理由是什么?
3、尤其是优化,你可以准备下如何通过执行计划查看SQL语句改进点的方式,或者其它能改善SQL性能的方式(比如建索引等)。
4、如果你感觉有能力,还可以准备些MySQL集群,MyCAT分库分表的技能。比如通过LVS+Keepalived实现MySQL负载均衡,MyCAT的配置方式。同样,如果可以,也看些相关的底层代码。
哪怕你在前三点表现一般,那么至少也能超越将近一般的候选人,尤其当你在SQL优化方面表现非常好,那么你在面试高级开发时,数据库层面一定是达标的
如果你连第四点也回答非常好,那么恭喜你,你在数据库方面的能力甚至达到了初级架构的级别。
围绕数据结构和性能优化准备面试题
Java核心方面,围绕数据结构和性能优化准备面试题!Java核心这块,网上的面试题很多,不过在此之外,大家还应当着重关注集合(即数据结构)和多线程并发这两块,在此基础上,大家可以准备些设计模式和虚拟机的说辞。
下面列些我一般会问的部分问题:
String a = "123"; String b = "123"; a==b的结果是什么?这包含了内存,String存储方式等诸多知识点。
HashMap里的hashcode方法和equal方法什么时候需要重写?如果不重写会有什么后果?对此大家可以进一步了解HashMap(甚至ConcurrentHashMap)的底层实现。
ArrayList和LinkedList底层实现有什么差别?它们各自适用于哪些场合?对此大家也可以了解下相关底层代码。
volatile关键字有什么作用?由此展开,大家可以了解下线程内存和堆内存的差别。
CompletableFuture,这个是JDK1.8里的新特性,通过它怎么实现多线程并发控制?
JVM里,new出来的对象是在哪个区?再深入一下,问下如何查看和优化JVM虚拟机内存。
Java的静态代理和动态代理有什么差别?最好结合底层代码来说。
通过上述的问题点,我其实不仅仅停留在“会用”级别,比如我不会问如何在ArrayList里放元素。
大家可以看到,上述问题包含了“多线程并发”,“JVM优化”,“数据结构对象底层代码”等细节,大家也可以举一反三,通过看一些高级知识,多准备些其它类似面试题。
我们知道,目前Java开发是以Web框架为主,那么为什么还要问Java核心知识点呢?我这个是有切身体会的。
之前在我团队里,我见过两个人,一个是就会干活,具体表现是会用Java核心基本的API,而且也没有深入了解的意愿(估计不知道该怎么深入了解),另一位平时专门会看些Java并发,虚拟机等的高级知识。
过了半年以后,后者的能力快速升级到高级开发,由于对JAVA核心知识点了解很透彻,所以看一些分布式组件的底层实现没什么大问题。而前者,一直在重复劳动,能力也只一直停留在“会干活”的层面。
而在现实的面试中,如果不熟悉Java核心知识点,估计升高级开发都难,更别说是面试架构师级别的岗位了。
至少了解如何看日志排查问题
Linux方面,至少了解如何看日志排查问题!如果候选人能证明自己有“排查问题”和“解决问题”的能力,这绝对是个加分项,但怎么证明?
目前大多数的互联网项目,都是部署在Linux上,也就是说,日志都是在Linux,下面归纳些实际的Linux操作。
1、能通过less命令打开文件,通过Shift+G到达文件底部,再通过?+关键字的方式来根据关键来搜索信息。
2、能通过grep的方式查关键字,具体用法是, grep 关键字 文件名,如果要两次在结果里查找的话,就用grep 关键字1 文件名 | 关键字2 --color。最后--color是高亮关键字。
3、能通过vi来编辑文件。
4、能通过chmod来设置文件的权限。
当然,还有更多更实用的Linux命令,但在实际面试过程中,不少候选人连一条linux命令也不知道。还是这句话,你哪怕知道些很基本的,也比一般人强了。
通读一段底层代码,作为加分项
如何证明自己对一个知识点非常了解?莫过于能通过底层代码来说明。
我在和不少工作经验在5年之内的程序员沟通时,不少人认为这很难?确实,如果要通过阅读底层代码了解分布式组件,那难度不小,但如果如下部分的底层代码,并不难懂。
1、ArrayList,LinkedList的底层代码里,包含着基于数组和链表的实现方式,如果大家能以此讲清楚扩容,“通过枚举器遍历“等方式,绝对能证明自己。
2、HashMap直接对应着Hash表这个数据结构,在HashMap的底层代码里,包含着hashcode的put,get等的操作,甚至在ConcurrentHashMap里,还包含着Lock的逻辑。我相信,如果大家在面试中,看看而言ConcurrentHashMap,再结合在纸上边说边画,那一定能征服面试官。
3、可以看下静态代理和动态代理的实现方式,再深入一下,可以看下Spring AOP里的实现代码。
4、或许Spirng IOC和MVC的底层实现代码比较难看懂,但大家可以说些关键的类,根据关键流程说下它们的实现方式。
其实准备的底层代码未必要多,而且也不限于在哪个方面,比如集合里基于红黑树的TreeSet,基于NIO的开源框架,甚至分布式组件的Dubbo,都可以准备。而且准备时未必要背出所有的底层(事实上很难做到),你只要能结合一些重要的类和方法,讲清楚思路即可(比如讲清楚HashMap如何通过hashCode快速定位)。
那么在面试时,如何找到个好机会说出你准备好的上述底层代码?
在面试时,总会被问到集合,Spring MVC框架等相关知识点,你在回答时,顺便说一句,“我还了解这块的底层实现”,那么面试官一定会追问,那么你就可以说出来了。
不要小看这个对候选人的帮助,一旦你讲了,只要意思到位,那么最少能得到个“肯积极专业“的评价
如果描述很清楚,那么评价就会升级到“熟悉Java核心技能(或Spring MVC),且基本功扎实”。
要知道,面试中,很少有人能讲清楚底层代码,所以你抛出了这个话题,哪怕最后没达到预期效果,面试官也不会由此对你降低评价。所以说,准备这块绝对是“有百利而无一害”的挣钱买卖。
把上述技能嵌入到你做过的项目里
一切的一切,把上述技能嵌入到你做过的项目里!在面试过程中,我经常会听到一些比较遗憾的回答,比如候选人对SQL优化技能讲得头头是道,但最后得知,这是他平时自学时掌握的,并没用在实际项目里。
当然这总比不说要好,所以我会写下“在平时自学过SQL优化技能”,但如果在项目里实践过,那么我就会写下“有实际数据库SQL优化的技能”。
大家可以对比下两者的差别,一个是偏重理论,一个是直接能干活了。其实,很多场景里,我就不信在实际项目里一定没有实践过SQL优化技能。
从这个案例中,我想告诉大家的是,你之前费了千辛万苦(其实方法方向得到,也不用费太大精力)准备的很多技能和说辞,最后应该落实到你的实际项目里。
比如你有过在Linux日志里查询关键字排查问题的经验,在描述时你可以带一句,在之前的项目里我就这样干的。
又如,你通过看底层代码,了解了TreeSet和HashSet的差别以及它们的适用范围,那么你就可以回想下你之前做的项目,是否有个场景仅仅适用于TreeSet?
如果有,那么你就可以适当描述下项目的需求,然后说,通过读底层代码,我了解了两者的差别,而且在这个实际需求里,我就用了TreeSet,而且我还专门做了对比性试验,发现用TreeSet比HashSet要高xx个百分点。
请记得,“实践经验”一定比“理论经验”值钱,而且大多数你知道的理论上的经验,一定在你的项目里用过。所以,如果你仅仅让面试官感觉你只有“理论经验”,那就太亏了。
小结:本文更多讲述的准备面试的方法
本文给出的面试题并不多,但本文并没有打算给出太多的面试题。从本文里,大家更多看到的是面试官发现的诸多候选人的痛点。
本文的用意是让大家别再重蹈别人的覆辙,这还不算,本文还给出了不少准备面试的方法。
你的能力或许比别人出众,但如果你准备面试的方式和别人差不多,或者就拿你在项目里干的活来说事,而没有归纳出你在项目中的亮点,那么面试官还真的会看扁你。
1. 一般问题
1.1. 不同版本的 Spring Framework 有哪些主要功能?
1.2. 什么是 Spring Framework?
1.3. 列举 Spring Framework 的优点。
1.4. Spring Framework 有哪些不同的功能?
1.5. Spring Framework 中有多少个模块,它们分别是什么?
1.6. 什么是 Spring 配置文件?
1.7. Spring 应用程序有哪些不同组件?
1.8. 使用 Spring 有哪些方式?
2. 依赖注入(Ioc)
2.1. 什么是 Spring IOC 容器?
2.2. 什么是依赖注入?
2.3. 可以通过多少种方式完成依赖注入?
2.4. 区分构造函数注入和 setter 注入。
2.5. spring 中有多少种 IOC 容器?
2.6. 区分 BeanFactory 和 ApplicationContext。
2.7. 列举 IoC 的一些好处。
2.8. Spring IoC 的实现机制。
3. Beans
3.1. 什么是 spring bean?
3.2. spring 提供了哪些配置方式?
3.3. spring 支持集中 bean scope?
3.4. spring bean 容器的生命周期是什么样的?
3.5. 什么是 spring 的内部 bean?
3.6. 什么是 spring 装配
3.7. 自动装配有哪些方式?
3.8. 自动装配有什么局限?
4. 注解
4.1. 你用过哪些重要的 Spring 注解?
4.2. 如何在 spring 中启动注解装配?
4.3. @Component, @Controller, @Repository, @Service 有何区别?
4.4. @Required 注解有什么用?
4.5. @Autowired 注解有什么用?
4.6. @Qualifier 注解有什么用?
4.7. @RequestMapping 注解有什么用?
5. 数据访问
5.1. spring DAO 有什么用?
5.2. 列举 Spring DAO 抛出的异常。
5.3. spring JDBC API 中存在哪些类?
5.4. 使用 Spring 访问 Hibernate 的方法有哪些?
5.5. 列举 spring 支持的事务管理类型
5.6. spring 支持哪些 ORM 框架
6. AOP
6.1. 什么是 AOP?
6.2. AOP 中的 Aspect、Advice、Pointcut、JointPoint 和 Advice 参数分别是什么?
6.3. 什么是通知(Advice)?
6.4. 有哪些类型的通知(Advice)?
6.5. 指出在 spring aop 中 concern 和 cross-cutting concern 的不同之处。
6.6. AOP 有哪些实现方式?
6.7. Spring AOP and AspectJ AOP 有什么区别?
6.8. 如何理解 Spring 中的代理?
6.9. 什么是编织(Weaving)?
7. MVC
7.1. Spring MVC 框架有什么用?
7.2. 描述一下 DispatcherServlet 的工作流程
7.3. 介绍一下 WebApplicationContext
8. 资料
1. 一般问题
1.1. 不同版本的 Spring Framework 有哪些主要功能?
Version Feature
Spring 2.5 发布于 2007 年。这是第一个支持注解的版本。
Spring 3.0 发布于 2009 年。它完全利用了 Java5 中的改进,并为 JEE6 提供了支持。
Spring 4.0 发布于 2013 年。这是第一个完全支持 JAVA8 的版本。
1.2. 什么是 Spring Framework?
Spring 是一个开源应用框架,旨在降低应用程序开发的复杂度。
它是轻量级、松散耦合的。
它具有分层体系结构,允许用户选择组件,同时还为 J2EE 应用程序开发提供了一个有凝聚力的框架。
它可以集成其他框架,如 Structs、Hibernate、EJB 等,所以又称为框架的框架。
1.3. 列举 Spring Framework 的优点。
由于 Spring Frameworks 的分层架构,用户可以自由选择自己需要的组件。
Spring Framework 支持 POJO(Plain Old Java Object) 编程,从而具备持续集成和可测试性。
由于依赖注入和控制反转,JDBC 得以简化。
它是开源免费的。
1.4. Spring Framework 有哪些不同的功能?
轻量级 - Spring 在代码量和透明度方面都很轻便。
IOC - 控制反转
AOP - 面向切面编程可以将应用业务逻辑和系统服务分离,以实现高内聚。
容器 - Spring 负责创建和管理对象(Bean)的生命周期和配置。
MVC - 对 web 应用提供了高度可配置性,其他框架的集成也十分方便。
事务管理 - 提供了用于事务管理的通用抽象层。Spring 的事务支持也可用于容器较少的环境。
JDBC 异常 - Spring 的 JDBC 抽象层提供了一个异常层次结构,简化了错误处理策略。
1.5. Spring Framework 中有多少个模块,它们分别是什么?
Spring 核心容器 – 该层基本上是 Spring Framework 的核心。它包含以下模块:
Spring Core
Spring Bean
SpEL (Spring Expression Language)
Spring Context
数据访问/集成 – 该层提供与数据库交互的支持。它包含以下模块:
JDBC (Java DataBase Connectivity)
ORM (Object Relational Mapping)
OXM (Object XML Mappers)
JMS (Java Messaging Service)
Transaction
Web – 该层提供了创建 Web 应用程序的支持。它包含以下模块:
Web
Web – Servlet
Web – Socket
Web – Portlet
AOP – 该层支持面向切面编程
Instrumentation – 该层为类检测和类加载器实现提供支持。
Test – 该层为使用 JUnit 和 TestNG 进行测试提供支持。
几个杂项模块:
Messaging – 该模块为 STOMP 提供支持。它还支持注解编程模型,该模型用于从 WebSocket 客户端路由和处理 STOMP 消息。
Aspects – 该模块为与 AspectJ 的集成提供支持。
1.6. 什么是 Spring 配置文件?
Spring 配置文件是 XML 文件。该文件主要包含类信息。它描述了这些类是如何配置以及相互引入的。但是,XML 配置文件冗长且更加干净。如果没有正确规划和编写,那么在大项目中管理变得非常困难。
1.7. Spring 应用程序有哪些不同组件?
Spring 应用一般有以下组件:
接口 - 定义功能。
Bean 类 - 它包含属性,setter 和 getter 方法,函数等。
Spring 面向切面编程(AOP) - 提供面向切面编程的功能。
Bean 配置文件 - 包含类的信息以及如何配置它们。
用户程序 - 它使用接口。
1.8. 使用 Spring 有哪些方式?
使用 Spring 有以下方式:
作为一个成熟的 Spring Web 应用程序。
作为第三方 Web 框架,使用 Spring Frameworks 中间层。
用于远程使用。
作为企业级 Java Bean,它可以包装现有的 POJO(Plain Old Java Objects)。
2. 依赖注入(Ioc)
2.1. 什么是 Spring IOC 容器?
Spring 框架的核心是 Spring 容器。容器创建对象,将它们装配在一起,配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入来管理组成应用程序的组件。
容器通过读取提供的配置元数据来接收对象进行实例化,配置和组装的指令。该元数据可以通过 XML,Java 注解或 Java 代码提供。
2.2. 什么是依赖注入?
在依赖注入中,您不必创建对象,但必须描述如何创建它们。您不是直接在代码中将组件和服务连接在一起,而是描述配置文件中哪些组件需要哪些服务。由 IoC 容器将它们装配在一起。
2.3. 可以通过多少种方式完成依赖注入?
通常,依赖注入可以通过三种方式完成,即:
构造函数注入
setter 注入
接口注入
在 Spring Framework 中,仅使用构造函数和 setter 注入。
2.4. 区分构造函数注入和 setter 注入。
构造函数注入 setter 注入
没有部分注入 有部分注入
不会覆盖 setter 属性 会覆盖 setter 属性
任意修改都会创建一个新实例 任意修改不会创建一个新实例
适用于设置很多属性 适用于设置少量属性
2.5. spring 中有多少种 IOC 容器?
BeanFactory - BeanFactory 就像一个包含 bean 集合的工厂类。它会在客户端要求时实例化 bean。
ApplicationContext - ApplicationContext 接口扩展了 BeanFactory 接口。它在 BeanFactory 基础上提供了一些额外的功能。
2.6. 区分 BeanFactory 和 ApplicationContext。
BeanFactory ApplicationContext
它使用懒加载 它使用即时加载
它使用语法显式提供资源对象 它自己创建和管理资源对象
不支持国际化 支持国际化
不支持基于依赖的注解 支持基于依赖的注解
2.7. 列举 IoC 的一些好处。
IoC 的一些好处是:
它将最小化应用程序中的代码量。
它将使您的应用程序易于测试,因为它不需要单元测试用例中的任何单例或 JNDI 查找机制。
它以最小的影响和最少的侵入机制促进松耦合。
它支持即时的实例化和延迟加载服务。
2.8. Spring IoC 的实现机制。
Spring 中的 IoC 的实现原理就是工厂模式加反射机制。
示例:
interface Fruit {
public abstract void eat();
}
class Apple implements Fruit {
public void eat(){
System.out.println("Apple");
}
}
class Orange implements Fruit {
public void eat(){
System.out.println("Orange");
}
}
class Factory {
public static Fruit getInstance(String ClassName) {
Fruit f=null;
try {
f=(Fruit)Class.forName(ClassName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class Client {
public static void main(String[] a) {
Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple");
if(f!=null){
f.eat();
}
}
}
3. Beans
3.1. 什么是 spring bean?
它们是构成用户应用程序主干的对象。
Bean 由 Spring IoC 容器管理。
它们由 Spring IoC 容器实例化,配置,装配和管理。
Bean 是基于用户提供给容器的配置元数据创建。
3.2. spring 提供了哪些配置方式?
基于 xml 配置
bean 所需的依赖项和服务在 XML 格式的配置文件中指定。这些配置文件通常包含许多 bean 定义和特定于应用程序的配置选项。它们通常以 bean 标签开头。例如:
<bean id="studentbean" class="org.edureka.firstSpring.StudentBean">
<property name="name" value="Edureka"></property>
</bean>
基于注解配置
您可以通过在相关的类,方法或字段声明上使用注解,将 bean 配置为组件类本身,而不是使用 XML 来描述 bean 装配。默认情况下,Spring 容器中未打开注解装配。因此,您需要在使用它之前在 Spring 配置文件中启用它。例如:
<beans>
<context:annotation-config/>
<!-- bean definitions go here -->
</beans>
基于 Java API 配置
Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。
@Bean 注解扮演与 元素相同的角色。
@Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 bean 间依赖关系。
例如:
@Configuration
public class StudentConfig {
@Bean
public StudentBean myStudent() {
return new StudentBean();
}
}
3.3. spring 支持集中 bean scope?
Spring bean 支持 5 种 scope:
Singleton - 每个 Spring IoC 容器仅有一个单实例。
Prototype - 每次请求都会产生一个新的实例。
Request - 每一次 HTTP 请求都会产生一个新的实例,并且该 bean 仅在当前 HTTP 请求内有效。
Session - 每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效。
Global-session - 类似于标准的 HTTP Session 作用域,不过它仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portlet 所共享。在 global session 作用域中定义的 bean 被限定于全局 portlet Session 的生命周期范围内。如果你在 web 中使用 global session 作用域来标识 bean,那么 web 会自动当成 session 类型来使用。
仅当用户使用支持 Web 的 ApplicationContext 时,最后三个才可用。更多spring内容,可以看这里:Spring内容合集
3.4. spring bean 容器的生命周期是什么样的?
spring bean 容器的生命周期流程如下:
Spring 容器根据配置中的 bean 定义中实例化 bean。
Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。
如果 bean 实现 BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用 setBeanName()。
如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory()。
如果存在与 bean 关联的任何 BeanPostProcessors,则调用 preProcessBeforeInitialization() 方法。
如果为 bean 指定了 init 方法( 的 init-method 属性),那么将调用它。
最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法。
如果 bean 实现 DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。
如果为 bean 指定了 destroy 方法( 的 destroy-method 属性),那么将调用它。
3.5. 什么是 spring 的内部 bean?
只有将 bean 用作另一个 bean 的属性时,才能将 bean 声明为内部 bean。为了定义 bean,Spring 的基于 XML 的配置元数据在 <property> 或 <constructor-arg> 中提供了 <bean> 元素的使用。内部 bean 总是匿名的,它们总是作为原型。
例如,假设我们有一个 Student 类,其中引用了 Person 类。这里我们将只创建一个 Person 类实例并在 Student 中使用它。
Student.java
public class Student {
private Person person;
//Setters and Getters
}
public class Person {
private String name;
private String address;
//Setters and Getters
}
bean.xml
<bean id=“StudentBean" class="com.edureka.Student">
<property name="person">
<!--This is inner bean -->
<bean class="com.edureka.Person">
<property name="name" value=“Scott"></property>
<property name="address" value=“Bangalore"></property>
</bean>
</property>
</bean>
3.6. 什么是 spring 装配
当 bean 在 Spring 容器中组合在一起时,它被称为装配或 bean 装配。Spring 容器需要知道需要什么 bean 以及容器应该如何使用依赖注入来将 bean 绑定在一起,同时装配 bean。
3.7. 自动装配有哪些方式?
Spring 容器能够自动装配 bean。也就是说,可以通过检查 BeanFactory 的内容让 Spring 自动解析 bean 的协作者。更多spring内容,可以看这里:Spring内容合集
自动装配的不同模式:
no - 这是默认设置,表示没有自动装配。应使用显式 bean 引用进行装配。
byName - 它根据 bean 的名称注入对象依赖项。它匹配并装配其属性与 XML 文件中由相同名称定义的 bean。
byType - 它根据类型注入对象依赖项。如果属性的类型与 XML 文件中的一个 bean 名称匹配,则匹配并装配属性。
构造函数 - 它通过调用类的构造函数来注入依赖项。它有大量的参数。
autodetect - 首先容器尝试通过构造函数使用 autowire 装配,如果不能,则尝试通过 byType 自动装配。
3.8. 自动装配有什么局限?
覆盖的可能性 - 您始终可以使用 和 设置指定依赖项,这将覆盖自动装配。
基本元数据类型 - 简单属性(如原数据类型,字符串和类)无法自动装配。
令人困惑的性质 - 总是喜欢使用明确的装配,因为自动装配不太精确。
4. 注解
4.1. 你用过哪些重要的 Spring 注解?
@Controller - 用于 Spring MVC 项目中的控制器类。
@Service - 用于服务类。
@RequestMapping - 用于在控制器处理程序方法中配置 URI 映射。
@ResponseBody - 用于发送 Object 作为响应,通常用于发送 XML 或 JSON 数据作为响应。
@PathVariable - 用于将动态值从 URI 映射到处理程序方法参数。
@Autowired - 用于在 spring bean 中自动装配依赖项。
@Qualifier - 使用 @Autowired 注解,以避免在存在多个 bean 类型实例时出现混淆。
@Scope - 用于配置 spring bean 的范围。
@Configuration,@ComponentScan 和 @Bean - 用于基于 java 的配置。
@Aspect,@Before,@After,@Around,@Pointcut - 用于切面编程(AOP)。
4.2. 如何在 spring 中启动注解装配?
默认情况下,Spring 容器中未打开注解装配。因此,要使用基于注解装配,我们必须通过配置<context:annotation-config /> 元素在 Spring 配置文件中启用它。
4.3. @Component, @Controller, @Repository, @Service 有何区别?
@Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。
@Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。
@Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。
@Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。
4.4. @Required 注解有什么用?
@Required 应用于 bean 属性 setter 方法。此注解仅指示必须在配置时使用 bean 定义中的显式属性值或使用自动装配填充受影响的 bean 属性。如果尚未填充受影响的 bean 属性,则容器将抛出 BeanInitializationException。
示例:
public class Employee {
private String name;
@Required
public void setName(String name){
this.name=name;
}
public string getName(){
return name;
}
}
4.5. @Autowired 注解有什么用?
@Autowired 可以更准确地控制应该在何处以及如何进行自动装配。此注解用于在 setter 方法,构造函数,具有任意名称或多个参数的属性或方法上自动装配 bean。默认情况下,它是类型驱动的注入。
public class Employee {
private String name;
@Autowired
public void setName(String name) {
this.name=name;
}
public string getName(){
return name;
}
}
4.6. @Qualifier 注解有什么用?
当您创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,您可以使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个确切的 bean 来消除歧义。
例如,这里我们分别有两个类,Employee 和 EmpAccount。在 EmpAccount 中,使用@Qualifier 指定了必须装配 id 为 emp1 的 bean。
Employee.java
public class Employee {
private String name;
@Autowired
public void setName(String name) {
this.name=name;
}
public string getName() {
return name;
}
}
EmpAccount.java
public class EmpAccount {
private Employee emp;
@Autowired
@Qualifier(emp1)
public void showName() {
System.out.println(“Employee name : ”+emp.getName);
}
}
4.7. @RequestMapping 注解有什么用?
@RequestMapping 注解用于将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。此注解可应用于两个级别:
类级别:映射请求的 URL
方法级别:映射 URL 以及 HTTP 请求方法
5. 数据访问
5.1. spring DAO 有什么用?
Spring DAO 使得 JDBC,Hibernate 或 JDO 这样的数据访问技术更容易以一种统一的方式工作。这使得用户容易在持久性技术之间切换。它还允许您在编写代码时,无需考虑捕获每种技术不同的异常。更多spring内容,可以看这里:Spring内容合集
5.2. 列举 Spring DAO 抛出的异常。
5.3. spring JDBC API 中存在哪些类?
JdbcTemplate
SimpleJdbcTemplate
NamedParameterJdbcTemplate
SimpleJdbcInsert
SimpleJdbcCall
5.4. 使用 Spring 访问 Hibernate 的方法有哪些?
我们可以通过两种方式使用 Spring 访问 Hibernate:
使用 Hibernate 模板和回调进行控制反转
扩展 HibernateDAOSupport 并应用 AOP 拦截器节点
5.5. 列举 spring 支持的事务管理类型
Spring 支持两种类型的事务管理:
程序化事务管理:在此过程中,在编程的帮助下管理事务。它为您提供极大的灵活性,但维护起来非常困难。
声明式事务管理:在此,事务管理与业务代码分离。仅使用注解或基于 XML 的配置来管理事务。
5.6. spring 支持哪些 ORM 框架
Hibernate
iBatis
JPA
JDO
OJB
6. AOP
6.1. 什么是 AOP?
AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与 OOP 不同的抽象软件结构的视角.
在 OOP 中, 我们以类(class)作为我们的基本单元, 而 AOP 中的基本单元是 Aspect(切面)
6.2. AOP 中的 Aspect、Advice、Pointcut、JointPoint 和 Advice 参数分别是什么?
Aspect - Aspect 是一个实现交叉问题的类,例如事务管理。方面可以是配置的普通类,然后在 Spring Bean 配置文件中配置,或者我们可以使用 Spring AspectJ 支持使用 @Aspect 注解将类声明为 Aspect。
Advice - Advice 是针对特定 JoinPoint 采取的操作。在编程方面,它们是在应用程序中达到具有匹配切入点的特定 JoinPoint 时执行的方法。您可以将 Advice 视为 Spring 拦截器(Interceptor)或 Servlet 过滤器(filter)。
Advice Arguments - 我们可以在 advice 方法中传递参数。我们可以在切入点中使用 args() 表达式来应用于与参数模式匹配的任何方法。如果我们使用它,那么我们需要在确定参数类型的 advice 方法中使用相同的名称。
Pointcut - Pointcut 是与 JoinPoint 匹配的正则表达式,用于确定是否需要执行 Advice。 Pointcut 使用与 JoinPoint 匹配的不同类型的表达式。Spring 框架使用 AspectJ Pointcut 表达式语言来确定将应用通知方法的 JoinPoint。
JoinPoint - JoinPoint 是应用程序中的特定点,例如方法执行,异常处理,更改对象变量值等。在 Spring AOP 中,JoinPoint 始终是方法的执行器。
6.3. 什么是通知(Advice)?
特定 JoinPoint 处的 Aspect 所采取的动作称为 Advice。Spring AOP 使用一个 Advice 作为拦截器,在 JoinPoint “周围”维护一系列的拦截器。
6.4. 有哪些类型的通知(Advice)?
Before - 这些类型的 Advice 在 joinpoint 方法之前执行,并使用 @Before 注解标记进行配置。
After Returning - 这些类型的 Advice 在连接点方法正常执行后执行,并使用@AfterReturning 注解标记进行配置。
After Throwing - 这些类型的 Advice 仅在 joinpoint 方法通过抛出异常退出并使用 @AfterThrowing 注解标记配置时执行。
After (finally) - 这些类型的 Advice 在连接点方法之后执行,无论方法退出是正常还是异常返回,并使用 @After 注解标记进行配置。
Around - 这些类型的 Advice 在连接点之前和之后执行,并使用 @Around 注解标记进行配置。
6.5. 指出在 spring aop 中 concern 和 cross-cutting concern 的不同之处。
concern 是我们想要在应用程序的特定模块中定义的行为。它可以定义为我们想要实现的功能。
cross-cutting concern 是一个适用于整个应用的行为,这会影响整个应用程序。例如,日志记录,安全性和数据传输是应用程序几乎每个模块都需要关注的问题,因此它们是跨领域的问题。
6.6. AOP 有哪些实现方式?
实现 AOP 的技术,主要分为两大类:
静态代理 - 指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;
编译时编织(特殊编译器实现)
类加载时编织(特殊的类加载器实现)。
动态代理 - 在运行时在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。
JDK 动态代理
CGLIB
6.7. Spring AOP and AspectJ AOP 有什么区别?
Spring AOP 基于动态代理方式实现;AspectJ 基于静态代理方式实现。
Spring AOP 仅支持方法级别的 PointCut;提供了完全的 AOP 支持,它还支持属性级别的 PointCut。
6.8. 如何理解 Spring 中的代理?
将 Advice 应用于目标对象后创建的对象称为代理。在客户端对象的情况下,目标对象和代理对象是相同的。
Advice + Target Object = Proxy
6.9. 什么是编织(Weaving)?
为了创建一个 advice 对象而链接一个 aspect 和其它应用类型或对象,称为编织(Weaving)。在 Spring AOP 中,编织在运行时执行。请参考下图:
7. MVC
7.1. Spring MVC 框架有什么用?
Spring Web MVC 框架提供 模型-视图-控制器 架构和随时可用的组件,用于开发灵活且松散耦合的 Web 应用程序。MVC 模式有助于分离应用程序的不同方面,如输入逻辑,业务逻辑和 UI 逻辑,同时在所有这些元素之间提供松散耦合。
7.2. 描述一下 DispatcherServlet 的工作流程
DispatcherServlet 的工作流程可以用一幅图来说明:
1. 一般问题
1.1. 不同版本的 Spring Framework 有哪些主要功能?
Version Feature
Spring 2.5 发布于 2007 年。这是第一个支持注解的版本。
Spring 3.0 发布于 2009 年。它完全利用了 Java5 中的改进,并为 JEE6 提供了支持。
Spring 4.0 发布于 2013 年。这是第一个完全支持 JAVA8 的版本。
1.2. 什么是 Spring Framework?
1.3. 列举 Spring Framework 的优点。
1.4. Spring Framework 有哪些不同的功能?
1.5. Spring Framework 中有多少个模块,它们分别是什么?
Spring 核心容器 – 该层基本上是 Spring Framework 的核心。它包含以下模块:
数据访问/集成 – 该层提供与数据库交互的支持。它包含以下模块:
Web – 该层提供了创建 Web 应用程序的支持。它包含以下模块:
几个杂项模块:
1.6. 什么是 Spring 配置文件?
Spring 配置文件是 XML 文件。该文件主要包含类信息。它描述了这些类是如何配置以及相互引入的。但是,XML 配置文件冗长且更加干净。如果没有正确规划和编写,那么在大项目中管理变得非常困难。
1.7. Spring 应用程序有哪些不同组件?
Spring 应用一般有以下组件:
1.8. 使用 Spring 有哪些方式?
使用 Spring 有以下方式:
2. 依赖注入(Ioc)
2.1. 什么是 Spring IOC 容器?
Spring 框架的核心是 Spring 容器。容器创建对象,将它们装配在一起,配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入来管理组成应用程序的组件。
容器通过读取提供的配置元数据来接收对象进行实例化,配置和组装的指令。该元数据可以通过 XML,Java 注解或 Java 代码提供。
2.2. 什么是依赖注入?
在依赖注入中,您不必创建对象,但必须描述如何创建它们。您不是直接在代码中将组件和服务连接在一起,而是描述配置文件中哪些组件需要哪些服务。由 IoC 容器将它们装配在一起。
2.3. 可以通过多少种方式完成依赖注入?
通常,依赖注入可以通过三种方式完成,即:
在 Spring Framework 中,仅使用构造函数和 setter 注入。
2.4. 区分构造函数注入和 setter 注入。
构造函数注入 setter 注入
没有部分注入 有部分注入
不会覆盖 setter 属性 会覆盖 setter 属性
任意修改都会创建一个新实例 任意修改不会创建一个新实例
适用于设置很多属性 适用于设置少量属性
2.5. spring 中有多少种 IOC 容器?
2.6. 区分 BeanFactory 和 ApplicationContext。
BeanFactory ApplicationContext
它使用懒加载 它使用即时加载
它使用语法显式提供资源对象 它自己创建和管理资源对象
不支持国际化 支持国际化
不支持基于依赖的注解 支持基于依赖的注解
2.7. 列举 IoC 的一些好处。
IoC 的一些好处是:
2.8. Spring IoC 的实现机制。
Spring 中的 IoC 的实现原理就是工厂模式加反射机制。
示例:
interface Fruit {
public abstract void eat();
}
class Apple implements Fruit {
public void eat(){
System.out.println("Apple");
}
}
class Orange implements Fruit {
public void eat(){
System.out.println("Orange");
}
}
class Factory {
public static Fruit getInstance(String ClassName) {
Fruit f=null;
try {
f=(Fruit)Class.forName(ClassName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class Client {
public static void main(String[] a) {
Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple");
if(f!=null){
f.eat();
}
}
}
3. Beans
3.1. 什么是 spring bean?
3.2. spring 提供了哪些配置方式?
bean 所需的依赖项和服务在 XML 格式的配置文件中指定。这些配置文件通常包含许多 bean 定义和特定于应用程序的配置选项。它们通常以 bean 标签开头。例如:
<bean id="studentbean" class="org.edureka.firstSpring.StudentBean">
<property name="name" value="Edureka"></property>
</bean>
您可以通过在相关的类,方法或字段声明上使用注解,将 bean 配置为组件类本身,而不是使用 XML 来描述 bean 装配。默认情况下,Spring 容器中未打开注解装配。因此,您需要在使用它之前在 Spring 配置文件中启用它。例如:
<beans>
<context:annotation-config/>
<!-- bean definitions go here -->
</beans>
Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。
例如:
@Configuration
public class StudentConfig {
@Bean
public StudentBean myStudent() {
return new StudentBean();
}
}
3.3. spring 支持集中 bean scope?
Spring bean 支持 5 种 scope:
仅当用户使用支持 Web 的 ApplicationContext 时,最后三个才可用。更多spring内容,可以看这里:Spring内容合集
3.4. spring bean 容器的生命周期是什么样的?
spring bean 容器的生命周期流程如下:
3.5. 什么是 spring 的内部 bean?
只有将 bean 用作另一个 bean 的属性时,才能将 bean 声明为内部 bean。为了定义 bean,Spring 的基于 XML 的配置元数据在 <property> 或 <constructor-arg> 中提供了 <bean> 元素的使用。内部 bean 总是匿名的,它们总是作为原型。
例如,假设我们有一个 Student 类,其中引用了 Person 类。这里我们将只创建一个 Person 类实例并在 Student 中使用它。
Student.java
public class Student {
private Person person;
//Setters and Getters
}
public class Person {
private String name;
private String address;
//Setters and Getters
}
bean.xml
<bean id=“StudentBean" class="com.edureka.Student">
<property name="person">
<!--This is inner bean -->
<bean class="com.edureka.Person">
<property name="name" value=“Scott"></property>
<property name="address" value=“Bangalore"></property>
</bean>
</property>
</bean>
3.6. 什么是 spring 装配
当 bean 在 Spring 容器中组合在一起时,它被称为装配或 bean 装配。Spring 容器需要知道需要什么 bean 以及容器应该如何使用依赖注入来将 bean 绑定在一起,同时装配 bean。
3.7. 自动装配有哪些方式?
Spring 容器能够自动装配 bean。也就是说,可以通过检查 BeanFactory 的内容让 Spring 自动解析 bean 的协作者。更多spring内容,可以看这里:Spring内容合集
自动装配的不同模式:
3.8. 自动装配有什么局限?
4. 注解
4.1. 你用过哪些重要的 Spring 注解?
4.2. 如何在 spring 中启动注解装配?
默认情况下,Spring 容器中未打开注解装配。因此,要使用基于注解装配,我们必须通过配置<context:annotation-config /> 元素在 Spring 配置文件中启用它。
4.3. @Component, @Controller, @Repository, @Service 有何区别?
4.4. @Required 注解有什么用?
@Required 应用于 bean 属性 setter 方法。此注解仅指示必须在配置时使用 bean 定义中的显式属性值或使用自动装配填充受影响的 bean 属性。如果尚未填充受影响的 bean 属性,则容器将抛出 BeanInitializationException。
示例:
public class Employee {
private String name;
@Required
public void setName(String name){
this.name=name;
}
public string getName(){
return name;
}
}
4.5. @Autowired 注解有什么用?
@Autowired 可以更准确地控制应该在何处以及如何进行自动装配。此注解用于在 setter 方法,构造函数,具有任意名称或多个参数的属性或方法上自动装配 bean。默认情况下,它是类型驱动的注入。
public class Employee {
private String name;
@Autowired
public void setName(String name) {
this.name=name;
}
public string getName(){
return name;
}
}
4.6. @Qualifier 注解有什么用?
当您创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,您可以使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个确切的 bean 来消除歧义。
例如,这里我们分别有两个类,Employee 和 EmpAccount。在 EmpAccount 中,使用@Qualifier 指定了必须装配 id 为 emp1 的 bean。
Employee.java
public class Employee {
private String name;
@Autowired
public void setName(String name) {
this.name=name;
}
public string getName() {
return name;
}
}
EmpAccount.java
public class EmpAccount {
private Employee emp;
@Autowired
@Qualifier(emp1)
public void showName() {
System.out.println(“Employee name : ”+emp.getName);
}
}
4.7. @RequestMapping 注解有什么用?
@RequestMapping 注解用于将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。此注解可应用于两个级别:
5. 数据访问
5.1. spring DAO 有什么用?
Spring DAO 使得 JDBC,Hibernate 或 JDO 这样的数据访问技术更容易以一种统一的方式工作。这使得用户容易在持久性技术之间切换。它还允许您在编写代码时,无需考虑捕获每种技术不同的异常。更多spring内容,可以看这里:Spring内容合集
5.2. 列举 Spring DAO 抛出的异常。
5.3. spring JDBC API 中存在哪些类?
5.4. 使用 Spring 访问 Hibernate 的方法有哪些?
我们可以通过两种方式使用 Spring 访问 Hibernate:
5.5. 列举 spring 支持的事务管理类型
Spring 支持两种类型的事务管理:
5.6. spring 支持哪些 ORM 框架
6. AOP
6.1. 什么是 AOP?
AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与 OOP 不同的抽象软件结构的视角.
在 OOP 中, 我们以类(class)作为我们的基本单元, 而 AOP 中的基本单元是 Aspect(切面)
6.2. AOP 中的 Aspect、Advice、Pointcut、JointPoint 和 Advice 参数分别是什么?
6.3. 什么是通知(Advice)?
特定 JoinPoint 处的 Aspect 所采取的动作称为 Advice。Spring AOP 使用一个 Advice 作为拦截器,在 JoinPoint “周围”维护一系列的拦截器。
6.4. 有哪些类型的通知(Advice)?
6.5. 指出在 spring aop 中 concern 和 cross-cutting concern 的不同之处。
concern 是我们想要在应用程序的特定模块中定义的行为。它可以定义为我们想要实现的功能。
cross-cutting concern 是一个适用于整个应用的行为,这会影响整个应用程序。例如,日志记录,安全性和数据传输是应用程序几乎每个模块都需要关注的问题,因此它们是跨领域的问题。
6.6. AOP 有哪些实现方式?
实现 AOP 的技术,主要分为两大类:
6.7. Spring AOP and AspectJ AOP 有什么区别?
Spring AOP 基于动态代理方式实现;AspectJ 基于静态代理方式实现。
Spring AOP 仅支持方法级别的 PointCut;提供了完全的 AOP 支持,它还支持属性级别的 PointCut。
6.8. 如何理解 Spring 中的代理?
将 Advice 应用于目标对象后创建的对象称为代理。在客户端对象的情况下,目标对象和代理对象是相同的。
Advice + Target Object = Proxy
6.9. 什么是编织(Weaving)?
为了创建一个 advice 对象而链接一个 aspect 和其它应用类型或对象,称为编织(Weaving)。在 Spring AOP 中,编织在运行时执行。请参考下图:
7. MVC
7.1. Spring MVC 框架有什么用?
Spring Web MVC 框架提供 模型-视图-控制器 架构和随时可用的组件,用于开发灵活且松散耦合的 Web 应用程序。MVC 模式有助于分离应用程序的不同方面,如输入逻辑,业务逻辑和 UI 逻辑,同时在所有这些元素之间提供松散耦合。
7.2. 描述一下 DispatcherServlet 的工作流程
DispatcherServlet 的工作流程可以用一幅图来说明:
7.3. 介绍一下 WebApplicationContext
WebApplicationContext 是 ApplicationContext 的扩展。它具有 Web 应用程序所需的一些额外功能。它与普通的 ApplicationContext 在解析主题和决定与哪个 servlet 关联的能力方面有所不同。
向服务器发送 HTTP 请求,请求被前端控制器 DispatcherServlet 捕获。
DispatcherServlet 根据 -servlet.xml 中的配置对请求的 URL 进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用 HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以HandlerExecutionChain 对象的形式返回。
DispatcherServlet 根据获得的Handler,选择一个合适的 HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的 preHandler(…)方法)。
提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:
HttpMessageConveter:将请求消息(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的响应信息。
数据转换:对请求消息进行数据转换。如`String`转换成`Integer`、`Double`等。
数据根式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等。
数据验证:验证数据的有效性(长度、格式等),验证结果存储到`BindingResult`或`Error`中。
Handler(Controller)执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象;
根据返回的ModelAndView,选择一
1. 一般问题
1.1. 不同版本的 Spring Framework 有哪些主要功能?
1.2. 什么是 Spring Framework?
1.3. 列举 Spring Framework 的优点。
1.4. Spring Framework 有哪些不同的功能?
1.5. Spring Framework 中有多少个模块,它们分别是什么?
1.6. 什么是 Spring 配置文件?
1.7. Spring 应用程序有哪些不同组件?
1.8. 使用 Spring 有哪些方式?
2. 依赖注入(Ioc)
2.1. 什么是 Spring IOC 容器?
2.2. 什么是依赖注入?
2.3. 可以通过多少种方式完成依赖注入?
2.4. 区分构造函数注入和 setter 注入。
2.5. spring 中有多少种 IOC 容器?
2.6. 区分 BeanFactory 和 ApplicationContext。
2.7. 列举 IoC 的一些好处。
2.8. Spring IoC 的实现机制。
3. Beans
3.1. 什么是 spring bean?
3.2. spring 提供了哪些配置方式?
3.3. spring 支持集中 bean scope?
3.4. spring bean 容器的生命周期是什么样的?
3.5. 什么是 spring 的内部 bean?
3.6. 什么是 spring 装配
3.7. 自动装配有哪些方式?
3.8. 自动装配有什么局限?
4. 注解
4.1. 你用过哪些重要的 Spring 注解?
4.2. 如何在 spring 中启动注解装配?
4.3. @Component, @Controller, @Repository, @Service 有何区别?
4.4. @Required 注解有什么用?
4.5. @Autowired 注解有什么用?
4.6. @Qualifier 注解有什么用?
4.7. @RequestMapping 注解有什么用?
5. 数据访问
5.1. spring DAO 有什么用?
5.2. 列举 Spring DAO 抛出的异常。
5.3. spring JDBC API 中存在哪些类?
5.4. 使用 Spring 访问 Hibernate 的方法有哪些?
5.5. 列举 spring 支持的事务管理类型
5.6. spring 支持哪些 ORM 框架
6. AOP
6.1. 什么是 AOP?
6.2. AOP 中的 Aspect、Advice、Pointcut、JointPoint 和 Advice 参数分别是什么?
6.3. 什么是通知(Advice)?
6.4. 有哪些类型的通知(Advice)?
6.5. 指出在 spring aop 中 concern 和 cross-cutting concern 的不同之处。
6.6. AOP 有哪些实现方式?
6.7. Spring AOP and AspectJ AOP 有什么区别?
6.8. 如何理解 Spring 中的代理?
6.9. 什么是编织(Weaving)?
7. MVC
7.1. Spring MVC 框架有什么用?
7.2. 描述一下 DispatcherServlet 的工作流程
7.3. 介绍一下 WebApplicationContext
8. 资料
Spring 是一个开源应用框架,旨在降低应用程序开发的复杂度。
它是轻量级、松散耦合的。
它具有分层体系结构,允许用户选择组件,同时还为 J2EE 应用程序开发提供了一个有凝聚力的框架。
它可以集成其他框架,如 Structs、Hibernate、EJB 等,所以又称为框架的框架。
由于 Spring Frameworks 的分层架构,用户可以自由选择自己需要的组件。
Spring Framework 支持 POJO(Plain Old Java Object) 编程,从而具备持续集成和可测试性。
由于依赖注入和控制反转,JDBC 得以简化。
它是开源免费的。
轻量级 - Spring 在代码量和透明度方面都很轻便。
IOC - 控制反转
AOP - 面向切面编程可以将应用业务逻辑和系统服务分离,以实现高内聚。
容器 - Spring 负责创建和管理对象(Bean)的生命周期和配置。
MVC - 对 web 应用提供了高度可配置性,其他框架的集成也十分方便。
事务管理 - 提供了用于事务管理的通用抽象层。Spring 的事务支持也可用于容器较少的环境。
JDBC 异常 - Spring 的 JDBC 抽象层提供了一个异常层次结构,简化了错误处理策略。
Spring Core
Spring Bean
SpEL (Spring Expression Language)
Spring Context
JDBC (Java DataBase Connectivity)
ORM (Object Relational Mapping)
OXM (Object XML Mappers)
JMS (Java Messaging Service)
Transaction
Web
Web – Servlet
Web – Socket
Web – Portlet
AOP – 该层支持面向切面编程
Instrumentation – 该层为类检测和类加载器实现提供支持。
Test – 该层为使用 JUnit 和 TestNG 进行测试提供支持。
Messaging – 该模块为 STOMP 提供支持。它还支持注解编程模型,该模型用于从 WebSocket 客户端路由和处理 STOMP 消息。
Aspects – 该模块为与 AspectJ 的集成提供支持。
接口 - 定义功能。
Bean 类 - 它包含属性,setter 和 getter 方法,函数等。
Spring 面向切面编程(AOP) - 提供面向切面编程的功能。
Bean 配置文件 - 包含类的信息以及如何配置它们。
用户程序 - 它使用接口。
作为一个成熟的 Spring Web 应用程序。
作为第三方 Web 框架,使用 Spring Frameworks 中间层。
用于远程使用。
作为企业级 Java Bean,它可以包装现有的 POJO(Plain Old Java Objects)。
构造函数注入
setter 注入
接口注入
BeanFactory - BeanFactory 就像一个包含 bean 集合的工厂类。它会在客户端要求时实例化 bean。
ApplicationContext - ApplicationContext 接口扩展了 BeanFactory 接口。它在 BeanFactory 基础上提供了一些额外的功能。
它将最小化应用程序中的代码量。
它将使您的应用程序易于测试,因为它不需要单元测试用例中的任何单例或 JNDI 查找机制。
它以最小的影响和最少的侵入机制促进松耦合。
它支持即时的实例化和延迟加载服务。
它们是构成用户应用程序主干的对象。
Bean 由 Spring IoC 容器管理。
它们由 Spring IoC 容器实例化,配置,装配和管理。
Bean 是基于用户提供给容器的配置元数据创建。
基于 xml 配置
基于注解配置
基于 Java API 配置
@Bean 注解扮演与 元素相同的角色。
@Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 bean 间依赖关系。
Singleton - 每个 Spring IoC 容器仅有一个单实例。
Prototype - 每次请求都会产生一个新的实例。
Request - 每一次 HTTP 请求都会产生一个新的实例,并且该 bean 仅在当前 HTTP 请求内有效。
Session - 每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效。
Global-session - 类似于标准的 HTTP Session 作用域,不过它仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portlet 所共享。在 global session 作用域中定义的 bean 被限定于全局 portlet Session 的生命周期范围内。如果你在 web 中使用 global session 作用域来标识 bean,那么 web 会自动当成 session 类型来使用。
Spring 容器根据配置中的 bean 定义中实例化 bean。
Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。
如果 bean 实现 BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用 setBeanName()。
如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory()。
如果存在与 bean 关联的任何 BeanPostProcessors,则调用 preProcessBeforeInitialization() 方法。
如果为 bean 指定了 init 方法( 的 init-method 属性),那么将调用它。
最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法。
如果 bean 实现 DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。
如果为 bean 指定了 destroy 方法( 的 destroy-method 属性),那么将调用它。
no - 这是默认设置,表示没有自动装配。应使用显式 bean 引用进行装配。
byName - 它根据 bean 的名称注入对象依赖项。它匹配并装配其属性与 XML 文件中由相同名称定义的 bean。
byType - 它根据类型注入对象依赖项。如果属性的类型与 XML 文件中的一个 bean 名称匹配,则匹配并装配属性。
构造函数 - 它通过调用类的构造函数来注入依赖项。它有大量的参数。
autodetect - 首先容器尝试通过构造函数使用 autowire 装配,如果不能,则尝试通过 byType 自动装配。
覆盖的可能性 - 您始终可以使用 和 设置指定依赖项,这将覆盖自动装配。
基本元数据类型 - 简单属性(如原数据类型,字符串和类)无法自动装配。
令人困惑的性质 - 总是喜欢使用明确的装配,因为自动装配不太精确。
@Controller - 用于 Spring MVC 项目中的控制器类。
@Service - 用于服务类。
@RequestMapping - 用于在控制器处理程序方法中配置 URI 映射。
@ResponseBody - 用于发送 Object 作为响应,通常用于发送 XML 或 JSON 数据作为响应。
@Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。
@Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。
@Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。
@Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。
类级别:映射请求的 URL
方法级别:映射 URL 以及 HTTP 请求方法
JdbcTemplate
SimpleJdbcTemplate
NamedParameterJdbcTemplate
SimpleJdbcInsert
SimpleJdbcCall
使用 Hibernate 模板和回调进行控制反转
扩展 HibernateDAOSupport 并应用 AOP 拦截器节点
程序化事务管理:在此过程中,在编程的帮助下管理事务。它为您提供极大的灵活性,但维护起来非常困难。
声明式事务管理:在此,事务管理与业务代码分离。仅使用注解或基于 XML 的配置来管理事务。
Hibernate
iBatis
JPA
JDO
OJB
Aspect - Aspect 是一个实现交叉问题的类,例如事务管理。方面可以是配置的普通类,然后在 Spring Bean 配置文件中配置,或者我们可以使用 Spring AspectJ 支持使用 @Aspect 注解将类声明为 Aspect。
Advice - Advice 是针对特定 JoinPoint 采取的操作。在编程方面,它们是在应用程序中达到具有匹配切入点的特定 JoinPoint 时执行的方法。您可以将 Advice 视为 Spring 拦截器(Interceptor)或 Servlet 过滤器(filter)。
Advice Arguments - 我们可以在 advice 方法中传递参数。我们可以在切入点中使用 args() 表达式来应用于与参数模式匹配的任何方法。如果我们使用它,那么我们需要在确定参数类型的 advice 方法中使用相同的名称。
Pointcut - Pointcut 是与 JoinPoint 匹配的正则表达式,用于确定是否需要执行 Advice。 Pointcut 使用与 JoinPoint 匹配的不同类型的表达式。Spring 框架使用 AspectJ Pointcut 表达式语言来确定将应用通知方法的 JoinPoint。
JoinPoint - JoinPoint 是应用程序中的特定点,例如方法执行,异常处理,更改对象变量值等。在 Spring AOP 中,JoinPoint 始终是方法的执行器。
Before - 这些类型的 Advice 在 joinpoint 方法之前执行,并使用 @Before 注解标记进行配置。
After Returning - 这些类型的 Advice 在连接点方法正常执行后执行,并使用@AfterReturning 注解标记进行配置。
After Throwing - 这些类型的 Advice 仅在 joinpoint 方法通过抛出异常退出并使用 @AfterThrowing 注解标记配置时执行。
After (finally) - 这些类型的 Advice 在连接点方法之后执行,无论方法退出是正常还是异常返回,并使用 @After 注解标记进行配置。
Around - 这些类型的 Advice 在连接点之前和之后执行,并使用 @Around 注解标记进行配置。
静态代理 - 指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;
编译时编织(特殊编译器实现)
类加载时编织(特殊的类加载器实现)。
动态代理 - 在运行时在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。
JDK 动态代理
CGLIB
向服务器发送 HTTP 请求,请求被前端控制器 DispatcherServlet 捕获。
DispatcherServlet 根据 -servlet.xml 中的配置对请求的 URL 进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用 HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以HandlerExecutionChain 对象的形式返回。
DispatcherServlet 根据获得的Handler,选择一个合适的 HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的 preHandler(…)方法)。
提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:
HttpMessageConveter:将请求消息(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的响应信息。
数据转换:对请求消息进行数据转换。如`String`转换成`Integer`、`Double`等。
数据根式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等。
数据验证:验证数据的有效性(长度、格式等),验证结果存储到`BindingResult`或`Error`中。
Handler(Controller)执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象;
根据返回的ModelAndView,选择一个适合的 ViewResolver(必须是已经注册到 Spring 容器中的ViewResolver)返回给DispatcherServlet。
ViewResolver 结合Model和View,来渲染视图。
视图负责将渲染结果返回给客户端。
@PathVariable - 用于将动态值从 URI 映射到处理程序方法参数。
@Autowired - 用于在 spring bean 中自动装配依赖项。
@Qualifier - 使用 @Autowired 注解,以避免在存在多个 bean 类型实例时出现混淆。
@Scope - 用于配置 spring bean 的范围。
@Configuration,@ComponentScan 和 @Bean - 用于基于 java 的配置。
@Aspect,@Before,@After,@Around,@Pointcut - 用于切面编程(AOP)。
个适合的 ViewResolver(必须是已经注册到 Spring 容器中的ViewResolver)返回给DispatcherServlet。
ViewResolver 结合Model和View,来渲染视图。
视图负责将渲染结果返回给客户端。
7.3. 介绍一下 WebApplicationContext
WebApplicationContext 是 ApplicationContext 的扩展。它具有 Web 应用程序所需的一些额外功能。它与普通的 ApplicationContext 在解析主题和决定与哪个 servlet 关联的能力方面有所不同。
————————————————
版权声明:本文为CSDN博主「麦田里守望者_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014352080/article/details/102716468