1、Spring和SpringMVC区别?
Spring是IOC和AOP的容器框架,SpringMVC是基于Spring功能之上添加的Web框架,想用SpringMVC必须先依赖Spring。
Spring可以说是一个管理bean的容器,也可以说是包括很多开源项目的总称,spring mvc是其中一个开源项目
2、Spring和SpringBoot区别
Spring Boot基本上是Spring框架的扩展,它消除了设置Spring应用程序所需的XML配置,为更快,更高效的开发生态系统铺平了道路。
Spring Boot中的一些特征:
- 创建独立的Spring应用。
- 嵌入式Tomcat、Jetty、 Undertow容器(无需部署war文件)。
- 提供的starters 简化构建配置
- 尽可能自动配置spring应用。
- 提供生产指标,例如指标、健壮检查和外部化配置
- 完全没有代码生成和XML配置要求
3、讲一下SpringBoot的启动流程?Spring Boot Starter原理?
image.pngSpring Boot Starter原理
搭建一个基于Spring的Web应用:
1、pom文件中引入相关jar包,包括spring、springmvc、redis、mybaits、log4j、mysql-connector-java 等等相关jar ...
2、配置web.xml,Listener配置、Filter配置、Servlet配置、log4j配置、error配置 ...
3、配置数据库连接、配置spring事务
4、配置视图解析器
5、开启注解、自动扫描功能
6、配置完成后部署tomcat、启动调试 ......
现在:
引入maven实质上就是导入jar包,spring-boot启动的时候会找到starter jar包中的resources/META-INF/spring.factories文件,根据spring.factories文件中的配置,找到需要自动配置的类
4、Spring Bean的生命周期(区别于Spring的启动过程)
实例化bean -> 属性填充 -> 调用Aware相关接口 -> 前置处理器 -> 检查并调用InitializingBean的AfterPropertiesSet方法 -> 反射执行bean的init-method方法 -> 后置处理器 -> 循环依赖检查 -> 初始化 -> 使用 -> 销毁
image.pngSpring启动流程及Bean生命周期梳理
image.png4、微服务存在什么优缺点?
特点:1、单一职责 2、自治
优点:1、逻辑清晰 2、简化部署 3、可扩展 4、灵活组合 5、技术异构 6、高可靠
5、spring 中 init-method 和 destroy-method 的使用方式
init-method:bean 构造器执行之后执行
destroy-method:bean 被销毁之前执行
6、Springboot自动装配怎么实现?
@SpringBootApplication -》@SpringBootConfiguration -》@EnableAutoConfiguration
- 说白了就是将主配置类(即@SpringBootApplication标注的类)的所在包及子包里面所有组件扫描加载到Spring容器。所以包名一定要注意。
- @Import注解就是给Spring容器中导入一些组件,这里传入了一个组件的选择器:AutoConfigurationImportSelector。
- 里面有一个selectImports方法,将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中。
会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件
7、 SpringBoot中starter原理
stater机制帮我们完成了项目起步所需要的的相关jar包。
starter中简单来讲就是引入了一些相关依赖和一些初始化的配置。
为什么配置了META-INF/spring.factories配置文件就可以加载?这里才是springboot实现starter的关键点,springboot的这种配置加载方式是一种类SPI(Service Provider Interface)的方式,SPI可以在META-INF/services配置接口扩展的实现类,springboot中原理类似,只是名称换成了spring.factories而已。
8、为什么依赖的依赖变少了?SpringBoot是如何管理这些依赖的?
1.1 从pom文件出发
1.2 SpringBoot将所有的常见开发功能,分成了一个个场景启动器(starter),这样我们需要开发什么功能,
就导入什么场景启动器依赖即可。
9、Spring InitializingBean和ApplicationListener的区别
- 使用spring中的InitializingBean接口,监听spring的启动过程,在spring装载完所有的bean的时候,会自动调用实现InitializingBean的afterPropertiesSet()方法
- 实现ApplicationListener接口,并实现 onApplicationEvent()方法
10、dubbo服务暴露和服务引用怎么和spring结合
服务暴露
- dubbo通过自定义Schema配置dubbo里面的核心组件
- 通过DubboNamespaceHandler注册的service把xml解析成ServiceBean,这个Bean是继承上面讲的ServiceConfig,然后通过利用Spring的生命周期在实例化bean的时候会调用org.springframework.beans.factory.InitializingBean#afterPropertiesSet方法。它最终会调用com.alibaba.dubbo.config.ServiceConfig#export方法进行服务暴露。
服务引用
- 而对于服务引用Dubbo也是同样的套路。
- 它也是通过DubboNamespaceHandler注册的的reference把xml解析成ReferenceBean。这个Bean是继承自上面提到的ReferenceConfig。然后通过利用Spring的生命周期在实例化bean的时候会调用org.springframework.beans.factory.InitializingBean#afterPropertiesSet方法。它最终会调用com.alibaba.dubbo.config.ReferenceConfig#get方法远程服务调用代理类的创建。
11、Spring跨域的三种实现
第一种办法:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
这种方式是全局配置的,网上也大都是这种解决办法,但是很多都是基于旧的spring版本,比如:
Spring Boot如何解决前端的Access-Control-Allow-Origin跨域问题
文中WebMvcConfigurerAdapter在spring5.0已经被标记为Deprecated
spring5最低支持到jdk1.8,所以注释中明确表明,你可以直接实现WebMvcConfigurer接口,无需再用这个适配器,因为jdk1.8支持接口中存在default-method。
第二种办法:
@WebFilter(filterName = "CorsFilter ")
@Configuration
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin","*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
chain.doFilter(req, res);
}
}
这种办法,是基于过滤器的方式,方式简单明了,就是在response中写入这些响应头
第三种办法:
public class GoodsController {
@CrossOrigin(origins = "http://localhost:4000")
@GetMapping("goods-url")
public Response queryGoodsWithGoodsUrl(@RequestParam String goodsUrl) throws Exception {}
}
没错就是@CrossOrigin注解,点开注解
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {}
从元注解@Target可以看出,注解可以放在method、class等上面,类似RequestMapping,也就是说,整个controller下面的方法可以都受控制,也可以单个方法受控制。
也可以得知,这个是最小粒度的cors控制办法了,精确到单个请求级别。
12、Spring中bean的作用域
Spring IOC容器创建一个Bean实例时,可以为Bean指定实例的作用域,作用域包含singleton(单例模式)、prototype(原型模式)、request(http请求)、session(会话)、global-session(全局会话)
image.png13、Spring事务传播机制详解
所谓事务传播机制,也就是在事务在多个方法的调用中是如何传递的,是重新创建事务还是使用父方法的事务?父方法的回滚对子方法的事务是否有影响?这些都是可以通过事务传播机制来决定的。
1、REQUIRED:如果有事务则加入事务,如果没有事务,则创建一个新的(默认值)
2、NOT_SUPPORTED:Spring不为当前方法开启事务,相当于没有事务
3、REQUIRES_NEW:不管是否存在事务,都创建一个新的事务,原来的方法挂起,新的方法执行完毕后,继续执行老的事务
4、MANDATORY:必须在一个已有的事务中执行,否则报错
5、NEVER:必须在一个没有的事务中执行,否则报错
6、SUPPORTS:如果其他bean调用这个方法时,其他bean声明了事务,则就用这个事务,如果没有声明事务,那就不用事务
14、spring有哪些主要模块?
Spring框架的七大模块
- Spring Core
框架的最基础部分,提供 IoC 容器,对 bean 进行管理。
2.Spring Context
基于 bean,提供上下文信息,扩展出JNDI、EJB、电子邮件、国际化、校验和调度等功能。
3.Spring DAO
提供了JDBC的抽象层,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码,还提供了声明性事务管理方法。
4.Spring ORM
提供了常用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate、MyBatis 等。
5.Spring AOP
提供了符合AOP Alliance规范的面向方面的编程实现。
6.Spring Web
提供了基础的 Web 开发的上下文信息,可与其他 web 进行集成。
7.Spring Web MVC
提供了 Web 应用的 Model-View-Controller 全功能实现。
15、BeanFactory 和 ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
可以从依赖关系、加载方式、创建方式、注册方式这四方面去讲。
依赖关系
BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。
ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
- 继承MessageSource,因此支持国际化。
- 统一的资源文件访问方式。
- 提供在监听器中注册bean的事件。
- 同时加载多个配置文件。
载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
加载方式
BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。
创建方式
BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。
注册方式
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
BeanFactory 简单粗暴,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器”。
ApplicationContext 可以称之为 “高级容器”。因为他比 BeanFactory 多了更多的功能。他继承了多个接口。因此具备了更多的功能。例如资源的获取,支持多种消息(例如 JSP tag 的支持),对 BeanFactory 多了工具级别的支持等待。所以你看他的名字,已经不是 BeanFactory 之类的工厂了,而是 “应用上下文”, 代表着整个大容器的所有功能。该接口定义了一个 refresh 方法,此方法是所有阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的 bean。
image.png
16、构造器依赖注入和 Setter方法注入的区别
构造函数注入 | setter 注入 |
---|---|
没有部分注入 | 有部分注入 |
不会覆盖 setter 属性 | 会覆盖 setter 属性 |
任意修改都会创建一个新实例 | 任意修改不会创建一个新实例 |
适用于设置很多属性 | 适用于设置少量属性 |
两种依赖方式都可以使用,构造器注入和Setter方法注入。最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖。
17、前后端分离跨域解决
我们知道一个http请求,先走filter,到达servlet后才进行拦截器的处理,如果我们把cors放在filter里,就可以优先于权限拦截器执行。
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}
现在可以通过实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
}
18、Spring Boot 中的 starter 到底是什么 ?
首先,这个 Starter 并非什么新的技术点,基本上还是基于 Spring 已有功能来实现的。首先它提供了一个自动化配置类,一般命名为 XXXAutoConfiguration ,在这个配置类中通过条件注解来决定一个配置是否生效(条件注解就是 Spring 中原本就有的),然后它还会提供一系列的默认配置,也允许开发者根据实际情况自定义相关配置,然后通过类型安全的属性注入将这些配置属性注入进来,新注入的属性会代替掉默认属性。正因为如此,很多第三方框架,我们只需要引入依赖就可以直接使用了。当然,开发者也可以自定义 Starter
19、Cglib能代理final方法吗?
不能,由于cglib是基于继承的方式实现类的动态代理,因此无法实现对final方法的代理。
20、@Conditional的使用
作用:根据条件,决定类是否加载到Spring Ioc容器中,在SpringBoot中有大量的运用
应用场景:在一些需要条件满足才是实例化的类中,使用此注解,我曾经在项目中需要根据不同的场景使用不同的mq中间件的时候使用过,在mq的实例化bean上,加上此注解,根据配置文件的不同,来决定这个bean是否加载至ioc容器中。
21、Spring与SpringMVC父子容器的区别和联系
1、 Spring 与SpringMVC 两个都是容器,存在父子关系(包含和被包含的关系)
2 、 Spring容器中存放着mapper代理对象,service对象,SpringMVC存放着Controller对象。子容器SpringMVC中可以访问父容器中的对象。但父容器Spring不能访问子容器SpringMVC的对象(存在领域作用域的原因,子容器可以访问父容器中的成员,而子容器的成员则只能被自己使用)。如:Service对象可以在Controller层中注入,反之则不行。
3、Spring容器导入的properties配置文件,只能在Spring容器中用而在SpringMVC容器中不能读取到。 需要在SpringMVC 的配置文件中重新进行导入properties文件,并且同样在父容器Spring中不能被使用,导入后使用@Value("${key}")在java类中进行读取。
22、注解service和component的区别
@Component
-
Component 用于将所标注的类加载到 Spring 环境中,需要搭配 component-scan 使用
-
泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类。
-
@service
@service和@controller引用来了@component注解,而@service是对@component进一步拓展,也就是component注解实现的功能@service都能实现,被@service注解标注的百类会被spring认定是业务逻辑层
23、Spring事务什么情况下回滚?
** Spring事务回滚机制是这样的:当所拦截的方法有指定异常抛出,事务才会自动进行回滚!**
- 默认配置下,事务只会对Error与RuntimeException及其子类这些UNChecked异常,做出回滚。一般的Exception这些Checked异常不会发生回滚(如果一般Exception想回滚要做出配置);
24、Spring事务trycatch会回滚吗?
依赖spring事物时,当service层进行try catch异常捕获时,事物不会产生回滚,代码如下
public void insertMsg(ConversationBean conversationBean){
try{
for(int i=0;i<100;i++){
if(i!=10){
testDao.insert2(i);
}else{
testDao.insert1(i);
}
}
}catch(Exception e){
}
}
此时异常被捕获,这种业务方法也就等于脱离了spring事务的管理,因为没有任何异常会从业务方法中抛出,全被捕获,导致spring异常抛出触发事务回滚策略失效。
解决此类问题时,需要在try catch中显示的抛出异常RuntimeException 然后在Controller层捕获异常并编写返回值,代码如下:
public void insertMsg(ConversationBean conversationBean){
try{
for(int i=0;i<100;i++){
if(i!=10){
testDao.insert2(i);
}else{
testDao.insert1(i);
}
}
}catch(Exception e){
throw new RuntimeException();
}
25、过滤器filter、拦截器interceptor、和AOP的区别与联系
filter过滤器
- 过滤器拦截web访问url地址。 严格意义上讲,filter只是适用于web中,依赖于Servlet容器,利用Java的回调机制进行实现。
- Filter过滤器:和框架无关,可以控制最初的http请求,但是更细一点的类和方法控制不了。
- 过滤器可以拦截到方法的请求和响应(ServletRequest request, ServletResponse response),并对请求响应做出像响应的过滤操作,
- 比如设置字符编码,鉴权操作等
Interceptor拦截器
- 拦截器拦截以 .action结尾的url,拦截Action的访问。 Interfactor是基于Java的反射机制(APO思想)进行实现,不依赖Servlet容器。
- 拦截器可以在方法执行之前(preHandle)和方法执行之后(afterCompletion)进行操作,回调操作(postHandle),可以获取执行的方法的名称,请求(HttpServletRequest)
- Interceptor:可以控制请求的控制器和方法,但控制不了请求方法里的参数(只能获取参数的名称,不能获取到参数的值)
- (用于处理页面提交的请求响应并进行处理,例如做国际化,做主题更换,过滤等)。
Spring AOP拦截器
- 只能拦截Spring管理Bean的访问(业务层Service)。 具体AOP详情参照 Spring AOP:原理、 通知、连接点、切点、切面、表达式
- 实际开发中,AOP常和事务结合:Spring的事务管理:声明式事务管理(切面)
- AOP操作可以对操作进行横向的拦截,最大的优势在于他可以获取执行方法的参数( ProceedingJoinPoint.getArgs() ),对方法进行统一的处理。
- Aspect : 可以自定义切入的点,有方法的参数,但是拿不到http请求,可以通过其他方式如RequestContextHolder获得(
ServletRequestAttributes servletRequestAttributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
)。- 常见**使用日志,事务,请求参数安全验证
26、Spring中使用哪些设计模式?
- 简单工厂模式:spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得bean对象
- 单例模式:Spring下默认的bean均为singleton,可以通过singleton=“true|false” 或者 scope="?"来指定。
- 代理模式:AOP
- 适配器模式:AOP的处理中有Adapter模式,由于Advisor链需要的是MethodInterceptor对象,所以每一个Advisor中的Advice都要适配成对应的MethodInterceptor对象。
- 包装器模式:
- 观察者模式:listener的实现。如ApplicationListener
- 策略模式:spring中在实例化对象的时候用到Strategy模式
- 模板方法模式:spring中的JdbcTemplate
27、@Transactional的参数配置
1、propagation参数,Propagation类型(枚举),默认值为Propogation.REQUIRED,支持的值有REQUIRED、MANDATORY、NESTED、NEVER、NOT_SUPPORTED、REQUIRE_NEW、SUPPORTS。关于这个问题的详细说明将在以后的文章中展开。
2、isolation参数,Isolation类型(枚举),默认值为Isolation.DEFAULT,支持的值有DEFAULT、READ_COMMITTED、READ_UNCOMMITTED、REPEATABLE_READ、SERIALIZABLE。关于这个问题的详细说明将在以后的文章中展开。
3、timeout参数,int类型,事务的超时时间,默认值为-1,即不会超时。
4、readOnly参数,boolean类型,true表示事务为只读,默认值为false。
5、rollbackFor参数,Class<? extends Throwable>[]类型,默认为空数组。
6、rollbackForClassName参数,String[]类型,默认为空数组。
7、noRollbackFor参数,Class<? extends Throwable>[]类型,默认为空数组。
8、noRollbackForClassName参数,String[]类型,默认为空数组。
最后四个参数都与回滚有关,首先,一般不推荐使用rollbackForClassName和noRollbackForClassName两个参数,而用另外两个参数来代替,从参数的类型上就可以看出区别,使用字符串的缺点在于:如果不是用类的完整路径,就可能导致回滚设置对位于不同包中的同名类都生效;且如果类名写错,也无法得到IDE的动态提示。
但是,如果不配置任何与回滚有关的参数,不代表事务不会进行回滚,如果没有配置这四个选项,那么DefaultTransactionAttribute配置将会生效,具体的行为是,抛掷任何unchecked Exception都会触发回滚,当然包括所有的RuntimeException。
网友评论