springboot(1)
1.说说对springmvc的理解
什么是MVC
mvc是一种设计模式(设计模式就是日常开发中编写代码的一种好的方法和经验的总结)。模型(model)-视图(view)-控制器(controller),三层架构的设计模式。用于实现前端页面的展现与后端业务数据处理的分离。mvc设计模式的好处
1.分层设计,实现了业务系统各个组件之间的解耦,有利于业务系统的可扩展性,可维护性。
2.有利于系统的并行开发,提升开发效率。
SpringMVC流程
1、 用户发送请求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
核心组件
DispatcherServlet(前端控制器)
说明:Spring MVC 的入口函数,接收请求,响应结果,相当于转发器,中央处理器,它就相当于mvc模式中DispatcherServlet的存在降低了组件之间的耦合性。
HandlerMapping(处理器映射器)
说明:根据请求的url查找Handler(即处理器Controller),映射方式有配置文件方式,实现接口方式,注解方式等。
HandlerAdapter(处理器适配器)
说明:HandlerAdapter是适配器模式的应用,按照HandlerAdapter要求的规则去执行Handler。
Handler(处理器)
说明:Handler需要开发工程师按照HandlerAdapter的要求去做,是后端控制器,处理具体的业务逻辑。
View resolver(视图解析器)
说明:进行视图解析,首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
视图View
说明:View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf等)springMVC是一个MVC的开源框架,springMVC=struts2+spring,springMVC就相当于是Struts2加上sring的整合,但是这里有一个疑惑就是,springMVC和spring是什么样的关系呢?这个在百度百科上有一个很好的解释:意思是说,springMVC是spring的一个后续产品,其实就是spring在原有基础上,又提供了web应用的MVC模块,可以简单的把springMVC理解为是spring的一个模块(类似AOP,IOC这样的模块),网络上经常会说springMVC和spring无缝集成,其实springMVC就是spring的一个子模块,所以根本不需要同spring进行整合。
2.说说ioc和aop理解和原理
IOC
IOC叫做控制反转,指的是通过Spring来管理对象创建、配置和生命周期,这样相当于把控制权交给了Spring,不需要人工来管理对象之间的复杂的依赖关系,这样做的好处就是解耦!
在Spring里面,主要提供BeanFactory和ApplicationContext两种IOC容器,通过它们来实现对Bean的管理!
AOP
叫做面向切面编程,他是一个编程范式,目的就是提高代码的模块性。Spring AOP基于动态代理的方式实现,如果是实现了接口的话就会使用JDK动态代理,反之则使用CGLIB代理。Spring中AOP的应用主要体现在事务、日志、异常处理等方面,通过在代码的前后做一些增强处理,可以实现对业务的逻辑隔离,提高代码的模块化能力,同时也是解耦。Spring主要提供了Aspect切面,JoinPoint连接点、PointCut切入点、Advice增强等实现方式。
3.说说springboot的理解
在使用spring框架的时候,我们需要配置applicationContext.xml的配置文件,并且在pom文件中,我们需要导入相关的依赖jar包以及版本,这样在使用的过程中,就显得有些复杂.
而springboot利用起步依赖和自动装配就很好的解决了一个问题,首先,我们来说说起步依赖,在springboot的pom文件中,我们依赖
父工程 ,在父工程中,定义了相关的坐标以及版本信息,这样我们继承了这个父工程的时候,就不需要指定版本信息,在我们的项目中.依赖了start-web这个坐标,而这个坐标依赖了spring以及springmvc的坐标,这样,根据依赖传递我们的项目就间接依赖了spring和mvc坐标,所有我们只需要导入start-web这一个坐标就可以了 接下来我们说说自动装配,在springboot的启动类上有一个@SpringBootApplication注解,这个注解也是springboot项目的核心注解,在@SpringBootApplication注解中,有一个@EnableAutoConfiguration注解,也就是开启自动配置的意思,这个注解的关键功能由@Import提供,其导入的AutoConfigurationImportSelector中的selectImports()方法能够找到META-INF/spring.factories配置文件中的所有启动配置类,并对其进行加载,而这些自动配置类都是以AtuoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,通过@ConfigurationProperties注解,绑定到对应的以properties结尾的配置实体类上封装为一个bean,然后在通过@EnableAutoConfiguration注解导入到Spring容器中,这样自动装配就完成了.
4.使用过过滤器或者拦截器吗,说说拦截器的方法和实现的接口
使用过
用过滤器主要做过全局网关配置请求token和跨域问题,实现Filter接口
用拦截器主要做日志输出,实现HandlerInterceptor 接口,有三个方法,preHandle,postHandle,afterCompletion,分别是请求之前调用,之后调用,结束后调用,然后相比过滤器,它需要在springmvc注入,在启动类添加配置代码。实现WebMvcConfigurer接口添加拦截器。
5.aop在什么情况下会使用到
AOP的应用场景:
1.日志处理
2.用户登录
3.权限(Authentication )
4.性能优化(Performance optimization)
5.事务(Transactions )
6.记录跟踪 优化 校准(logging, tracing, profiling and monitoring)
7.调试(Debugging)
8.懒加载(Lazy loading)
9.错误处理(Error handling)
10.资源池(Resource pooling)
11.同步(Synchronization)
6.如果有过滤器和拦截器和aop,他们的执行顺序是什么
执行顺序依次是过滤器、拦截器、切面
7.Spring 中的bean 是线程安全的吗
Spring本身并没有针对Bean做线程安全的处理,所以:
1.如果Bean是无状态的,那么Bean则是线程安全的
2.如果Bean是有状态的,那么Bean则不是线程安全的
另外,Bean是不是线程安全,跟Bean的作用域没有关系,Bean的作用域只是表示Bean的生命周期范围,对于任何生命周期的Bean都是一个对象,这个对象是不是线程安全的,还是得看这个Bean对象本身。
(有状态会话bean :每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。简单来说,有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存数据,是非线程安全的。
无状态会话bean :bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean 的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。但无状态会话bean 并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的。简单来说,无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象 .不能保存数据,是不变类,是线程安全的。)
8.BeanFactory和ApplicationContext的区别
BeanFactory:
是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;
ApplicationContext:
应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能;
国际化(MessageSource)
访问资源,如URL和文件(ResourceLoader)
载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
消息发送、响应机制(ApplicationEventPublisher)
AOP(拦截器)
9.@Transactional 注解的失效场景
1、@Transactional 应用在非 public 修饰的方法上
如果Transactional注解应用在非public 修饰的方法上,Transactional将会失效。
注意:protected、private 修饰的方法上使用 @Transactional 注解,虽然事务无效,但不会有任何报错,这是我们很容犯错的一点。
2、@Transactional 注解属性 propagation 设置错误
这种失效是由于配置错误,若是错误的配置以下三种 propagation,事务将不会发生回滚。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。3、@Transactional 注解属性 rollbackFor 设置错误
rollbackFor 可以指定能够触发事务回滚的异常类型。Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务,其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定rollbackFor属性。
4、同一个类中方法调用,导致@Transactional失效
开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。当外界调用方法A之后,方法B的事务是不会起作用的。这也是经常犯错误的一个地方。那为什么会出现这种情况?其实这还是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。
10.spring运用了哪些设计模式
工厂模式
Spring使用工厂模式可以通过
BeanFactory
或ApplicationContext
创建 bean 对象。代理模式
Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用JDK Proxy去进行代理了,这时候Spring AOP会使用Cglib,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理。
模板方法模式
Spring中jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到模板模式。一般情况下,我们都是使用继承的方式来实现模板模式,但是Spring并没有使用这种方式,而是使用Callback模式与模板方法配合,既达到了代码复用的效果,同时增加了灵活性。
观察者模式
观察者设计模式是一种对象行为模式。它表示的是一种对象与对象之间具有依赖关系,当一个对象发生改变时,这个对象锁依赖的对象也会做出反应。Spring事件驱动模型就是观察者模式很经典的应用。
适配器 模式
适配器设计模式将一个接口转换成客户希望的另一个接口,适配器模式使得接口不兼容的那些类可以一起工作,其别名为包装器。在Spring MVC中,DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler,解析到对应的Handler(也就是我们常说的Controller控制器)后,开始由HandlerAdapter适配器处理。为什么要在Spring MVC中使用适配器模式?Spring MVC中的Controller种类众多不同类型的Controller通过不同的方法来对请求进行处理,有利于代码的维护拓展。
装饰者模式
装饰者设计模式可以动态地给对象增加些额外的属性或行为。相比于使用继承,装饰者模式更加灵活。Spring 中配置DataSource的时候,DataSource可能是不同的数据库和数据源。我们能否根据客户的需求在少修改原有类的代码下切换不同的数据源?这个时候据需要用到装饰者模式。
策略模式
Spring 框架的资源访问接口就是基于策略设计模式实现的。该接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource接口来访问底层资源。Resource接口本身没有提供访问任何底层资源的实现逻辑,针对不同的额底层资源,Spring将会提供不同的Resource实现类,不同的实现类负责不同的资源访问类型。
11.Springboot中常用注解有哪些,简述一下注解的作用
@SpringBootApplication
- 这个注解很常见了,每次在启动SpringBoot项目的时候,都会见到它,它作用在类上,标识该类为SpringBoot项目启动类。
并且让SpringBoot自动给程序进行必要的配置,等同于@Configuration、@EnableAutoConfiguration、@ComponentScan这三个注解。@Configuration
- 相当于传统Spring的xml配置文件。
- 如果第三方库需要用到xml文件,建议通过@Configuration类作为项目的配置主类,可以使用@ImportResource注解加载xml配置文件。
@EnableAutoConfiguration 自动配置。
- SpringBoot自动配置(auto-configuration),尝试根据你添加的启动器(starter)自动配置你的SpringBoot应用。
- 你可以将@EnableAutoConfiguration注解或者@SpringBootApplication注解添加到一个@Configuration类上来选择自动配置。
- 如果发现应用了你不想要的特定自动配置类,你可以使用@EnableAutoConfiguration注解的排除属性来禁用它们。
@ComponentScan
- 如果某个类加上@ComponentScan注解,则该类会自动发现扫描组件。
- 也就是说,如果扫描到有@Component、@Controller、@Service等这些注解的类,并注册为Bean,可以自动收集所有的Spring组件,包括@Configuration类。
- 我们经常使用@ComponentScan注解搜索beans,并结合@Autowired注解导入。如果没有配置的话,SpringBoot会扫描启动类所在包下以及子包下的使用了@Component、@Controller、@Service、@Repository等注解的类。
@Controller
- @Controller注解用于定义控制器类,在SpringBoot中由控制器负责将用户发来的URL请求转发到对应的服务接口(Controller层)。
- 一般这个注解用在类上,控制器方法需要加上@RequestMapping注解。
@ResponseBody
- 如果控制器方法加上@ResponseBody注解,该方法的返回结果将直接写入HTTP response body中,一般在异步获取数据时使用,用于构建RESTful的api。
- 在使用@RequestMapping后,返回值通常解析为跳转路径,加上@esponsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。
- 比如异步获取json数据,加上@Responsebody后,会直接返回json数据。该注解一般会配合@RequestMapping一起使用。
@RestController
- @RestController注解是@Controller和@ResponseBody的合集。
- 使用在类上,表示该类是控制器,并且类中所有控制器方法的返回值直接填入HTTP响应体中,是RESTful风格的控制器,控制器方法返回JSON数据。
@RequestMapping
- 提供路由信息,负责URL到Controller中的具体方法的映射。
@Import
- 用来导入其他配置类(加了@Configuration注解的类)。
@ImportResource
- 用来加载xml配置文件。
@PathVariable
- 获取URL上的参数(Restful风格接口)。
@Service
- 一般用于修饰service层的组件
@Repository
- 使用@Repository注解可以确保DAO或者repositories提供异常转译,这个注解修饰的DAO或者repositories类会被ComponetScan发现并配置,同时也不需要为它们提供XML配置项。
@Bean
- 用@Bean标注方法等价于XML中配置的bean,意思是产生一个bean,并交给SpringBoot管理。
@Value
- 注入SpringBoot中的配置文件——application.properties配置的属性的值。
@Inject
- 等价于默认的@Autowired,只是没有required属性。
@Component
- 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@AutoWired
- 自动导入依赖的bean。byType方式。把配置好的Bean拿来用,完成属性、方法的组装,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。当加上(required=false)时,就算找不到bean也不报错。
@Qualifier
- 当有多个同一类型的Bean时,可以用@Qualifier(“name”)来指定。与@Autowired配合使用。@Qualifier限定描述符除了能根据名字进行注入,但能进行更细粒度的控制如何选择候选者。
@Resource(name=”name”,type=”type”)
- 没有括号内内容的话,默认byName。与@Autowired干类似的事。
附页
注解 含义 @Component 最普通的组件,可以被注入到spring容器进行管理 @Repository 作用于持久层 @Service 作用于业务逻辑层 @Controller 作用于表现层(spring-mvc的注解) 这几个注解几乎可以说是一样的:因为被这些注解修饰的类就会被Spring扫描到并注入到Spring的bean容器中。
@Autowired是根据类型进行自动装配的,如果找到多个类型相同的,会按照名称进行匹配,如果名称相同,会报错,如果需要按指定名称进行装配,则需要配合@Qualifier;
@Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named;
@Resource是根据名称进行自动装配的,一般会指定一个name属性
总结:
1、@Autowired是spring自带的,@Inject是JSR330规范实现的,@Resource是JSR250规范实现的,需要导入不同的包
2、@Autowired、@Inject用法基本一样,不同的是@Autowired有一个request属性
3、@Autowired、@Inject是默认按照类型匹配的,@Resource是按照名称匹配的
4、@Autowired如果需要按照名称匹配需要和@Qualifier一起使用,@Inject和@Name一起使用