面试八股-Java框架
1.Spring
1.1.特点
- 轻量级 不必接触其实现原理
- 通过控制反转(IOC)达到松耦合
- 提供面向切面编程(AOP),允许业务逻辑和系统级服务分离,比如日志功能分离
- 提供bean容器,管理java对象及其生命周期
- 是一种框架,可以简单的组合组件,比如redis,mybatis等
1.2.Spring中的设计模式
-
简单工厂 Spring在使用BeanFactory或者ApplicationContext获取对象的时候,使用工厂模式,根据传入的Bean标识符来获得对象。
-
工厂方法 有一种实现FactoryBean接口的bean实际上是一种工厂,在使用getBean方法时会调用对应bean的getObject方法来获取。
-
单例模式 创建的bean默认是单例的,在getBean时使用getSingleton方法创建。
-
适配器模式 典型的就是SpringMVC中的HandlerAdapter,mvc需要通过HandlerMapping去获得需要处理的handler,但实际handler类型不同,对请求的预处理,参数获取都不相同。如果使用适配器模式,即handler交由HandlerAdapter处理,只向DispatcherServlet提供一个handle接口。
-
装饰器 Spring在处理bean的时候,可以实现各种xxxWrapper的接口,可以用于动态修改对象属性,而且和原对象还是==的。
-
代理模式 AOP中的实现原理,在运行时要织入切面时,会动态创建一个目标对象的代理对象,来进行前置或者后置的一些增强。
-
观察者模式 Spring中的事件监听使用的是观察者模式,ApplicationContext容器,ApplicationEvent事件对象,ApplicationListener事件监听对象,当容器发布事件时,listener将被自动触发。
-
策略模式 Spring的资源访问Resource接口,通过实现该接口,实现对各种类型资源的访问。(比如访问网络资源,文件资源,输入流资源等)
1.3.Spring Boot、Spring MVC和Spring的区别
Spring是一个IOC容器,通过依赖注入的方式去实现控制反转,提供AOP机制改善了OOP的代码重复问题。可以很方便的整合各种框架。 Spring=Spring IOC+SpringAOP
SpringMVC是spring对web框架的一个解决方案,提供了一个总的前端控制器servlet来接收请求,然后定义了一套路由策略(url到handle的映射)及适配执行handle,将handle结果使用视图解析技术展现在前端。
Springboot是spring提供的一个快速开发工具包,让程序员能更方便,更快速的开发spring + springmvc应用,简化了配置,整合了一系列解决方案(starter)机制。
2.Spring IOC
-
将控制权从业务层转给用户层
-
是一种思想,DI依赖注入则是实现方法,先读取并创建对象存入容器,用的时候取出。
2.1.Spring容器启动流程
- 进行扫描,得到所有BeanDefinition对象存放在Map中,BeanDefintion定义了Bean在IoC容器内的基本数据结构,在容器启动时,会将Bean解析成BeanDefination结构存储。描述了一个Bean的属性,构造方法,参数值等。
- 筛选出非懒加载的单例BeanDefinition进行创建,对于多例Bean不需要在启动过程中进行创建,而是在每次获取Bean时利用Beandefinition创建
2.2.Bean
2.2.1.生命周期
总体上是四个
-
实例化 Instantiation
-
属性赋值 Populate
-
初始化 Initialization
-
销毁 Destruction
细化的话有七个
-
实例化Bean:spring扫描包下的类并变成bean definition对象,解析BeanDefinition对象中的信息进行实例化。这一步只是将bean实例化,里面的属性还没有注入。实例化的对象被包装在BeanWrapper中,BeanWrapper提供了设置对象属性的接口
-
依赖注入:根据BeanDefinition中的信息,使用BeanWrapper接口进行依赖注入
-
注入Aware接口:检测对象是否实现了xxxAware接口,并将相关的Aware实例注入,似乎是可以对上下文做出一些改动,实现aware子接口的bean可以获取到spring的底层组件
- 一个bean实现类bean name aware接口,工厂调用set bean name方法传入id
- 一个bean实现了bean factory aware接口,工厂调用set bean factory方法传入自身
- 至此,bean被正确的构造,如需要进行自定义的操作,就要实现beanpostprocessor接口
-
BeanPostProcessor:提供两个方法,一个是before一个是after,在Bean使用前后进行自定义增强处理
-
InitializingBean:先调用初始化前的方法,再实行初始化方法,然后调用初始化后的方法
-
使用bean
-
销毁:调用DisposableBean中的destroy方法。在bean销毁前执行指定逻辑
2.2.2.作用域
在bean标签的scope属性指定
- 单例,默认情况下为单例,即每个容器中只有一个bean的实例
- 原型,为每一个bean请求提供一个实例,每次get都会创建一个新的对象
- 请求request,为每个http请求创建一个对象,在同一个请求中使用的是一个bean
- 会话Session,与request类似,在一个session中有一个实例。
- 应用application,在servletContext中复用一个单例对象
- Websocket,在websocket生命周期中复用一个单例对象
2.2.3.注入方式
-
通过构造器注入(构造方法需要传入所依赖的bean)
-
使用set方法 + xml文件配置注入(当某个属性有set方法时,在xml文件配置注入即可)
-
注解(@component注入,@Configuration+@Bean配置类注入容器,@Autowaire注入属性)
-
通过Application context进行get(“beanId”)来获得bean
-
隐式,即自动装配 比如说People里面有一个Dog类型的变量,那么可以根据dog名称或者Dog类型找到对应的bean进行注入
2.2.4.标签定义
在xml中设置,由spring创建,属性由容器设置
- id 对象唯一标识
- value 具体值,基本数据类型
- ref 引用spring容器中创建好的对象
- class bean对象对应的全限定名 包名+类型
- name 也是别名,可以取多个别名
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("UserServiceImpl");
userServiceImpl.getUser();
2.2.5.线程安全
-
单例模式下所有线程共享bean,框架并没有对bean进行多线程的封装处理,存在安全问题。
-
如果bean无状态,即不存储数据,只是调用方法,那么单例就可以。
-
如果bean有状态,即有数据存储功能,便不再是安全的。
-
-
在Dao层操作数据库Connection时,connection是有状态的,spring采用ThreadLocal为每个线程维护独立的connection副本,保证线程间互不影响。
-
对于有状态的bean一般需要进行多线程处理,可以使用ThreadLocal,如果要在多个线程中共享,那就要使用sychronized,lock这些实现同步的方法了。
2.2.6.循环依赖问题
原因
1)基于构造器的循环依赖,即a和b的构造器都需要对方
2)属性注入的循环依赖,在单例模式下,创建新的A时,发现要注入B,又创建新的B发现要注入原型字段A。此时就造成了循环依赖。
解决
- 三级缓存解决对于属性的依赖
- 单例工厂的cache,保存实际创建工程
- 提前曝光的单例对象的cache,保存提前暴露的对象(没有设置属性)
- 单例对象的cache,保存创建成功的对象
- 无法解决构造器依赖
- 来解决循环依赖,将还未注入的对象也保存下来。即一个对象在被实例化后即使属性还没被填充,也可以通过三级缓存向外暴露引用值。但其前提是要被实例化后,所以构造器的循环依赖是无法解决的。
2.2.7.import
通常用于多人开发,将多个xml合并到一个中
<import resource="xx.xml"/>
如果有重名,会选择其中一个。
2.3.注解自动装配
2.3.1.声明
- @Component 组件类
- @Repository dao中,可以自动处理数据库抛出的异常,将其处理为Spring专属数据库异常,方便排查处理。
- @Service service中
- @Controller controller中,配合@RequestMapping使用
2.3.2.使用
- 属性上使用@Autowired自动注入,Autowired(require=false),可使属性为空
- 如果多个候选bean,可以使用@Qualifier(value=“xxx”)实现,value为容器中具体bean的id
- @Resource先通过byname,失败则bytype,Autowired默认使用bytype
- 在xml文件中增加扫描命令
2.4.@Component和@Bean的区别
@Component注解表明一个类会作为组件类,并告知Spring要为这个类创建bean。通过类路径扫描自动检测。
@Bean注解告诉Spring这个方法将会返回一个对象,这个对象要注册为Spring应用上下文中的bean。通常方法体中包含了最终产生bean实例的逻辑。通常和@Configuration注解一起使用,@Configuration用来表明该类是一个注解类,底下有一些@bean。比如说,如果要使用第三方的一些bean,如果想把他们加载到容器中,那就要在其代码中加上@Component注解,这样显然是不可行的,所以@Configuration和@bean组合使用的方式就解决了此问题。
2.5.IOC的优点
- 实现组件间的解耦,不用再程序里创建依赖。而是由配置文件决定。
- 方便修改和维护,比如原来a中要手动创建b,如果b的构造方法改变了,那么a和b的代码都需要修改,控制反转后由容器将创建好的b注入a中,不涉及到依赖修改问题。
2.6.BeanFactory和ApplicationContext的区别
-
ApplicationContext继承BeanFactory,实现了更多功能,提供在监听器中注册的bean时间,同时加载多个配置文件。唯一缺点是启动相对较慢。
-
BeanFactory采用的是延迟加载来注入Bean,只有在get的时候才会加载,这样就不好发现配置问题,异常在调用的时候才抛出
-
ApplicationContext在启动时,就一次性加载了所有的Bean,可以即使发现配置错误,有利于检查依赖属性是否被正确注入。需要的时候直接get创建好的类即可。
3.Spring AOP
-
面向切面编程
-
底层实现为代理模式
-
将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,注入到业务逻辑中。可以对某个对象或其功能化进行增强。
3.1.代理模式
- 静态代理 客户 真实角色 代理角色 实现接口
- 可以使真实角色操作更加纯粹,不关注公共业务
- 公共业务交给代理,拓展时方便集中管理
- 动态代理 和静态代理优点一样,但是代码动态生成,不是自己写好的,不需要一个代理对象对应一个类了,一个代理可以对应多个类,使用反射机制加载
- 基于接口: JDK动态代理 实现
InvocationHandler
接口,并实现 invoke 方法 Proxy.newProxyInstance - 基于类(未实现接口):cglib,字节码处理 创建一个类实现 MethodInterceptor接口 Enhancer
- 基于接口: JDK动态代理 实现
3.2.JDK动态代理和Cglib的区别
3.2.1.JDK动态代理
-
利用反射机制,代理类实现invocationHandler来处理逻辑
-
如果要为一类对象进行代理时,前提是这些目标对象必须实现了统一的接口,代理类可以对实现该接口的所有目标对象进行代理
-
如果目标对象没有实现统一接口,那jdk动态代理就失去了本身的意义
3.2.2.cglib动态代理
- 生成目标对象的一个子类,重写父类所有非final的方法,扩展方法功能
3.2.3.使用区别
-
如果目标对象实现了接口,默认情况下采用JDK动态代理实现AOP
-
如果目标对象没有实现接口,使用jdk则会变得像静态代理一样,没有意义,必须采用cglib
3.3.核心概念
- 通知(Advice) AOP框架中的增强处理,描述了切面何时执行以及如何执行增强处理
- 连接点(Join Point) 表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用
- 切入点(Point Cut) 可以插入增强处理的连接点
- 切面(Aspect) 切面是通知和切点的结合
- 引入(Introduction) 允许我们向现有的类添加新的方法或者属性
- 织入(Weaving) 将增强处理添加到目标对象中,并创建一个被增强的代理对象
将多个地方需要实现的非主要业务逻辑剥离为切面,如log日志打印,不需要修改原业务逻辑,在相关操作切入原业务逻辑特定位置即可。
3.4.配置方式
3.4.1.注解
切点
使用@Pointcut注解声明切点表达式,然后使用表达式
execution(* com.alibaba.spring.aop.Instrument.play(…))
- execution表示在方法执行时触发
- *表示任意返回类型
- com.alibaba.spring.aop.Instrument表示方法所属的类型
- play表示切点切入的方法名称
- …表示使用任意参数
多个条件可以使用&&、||、!来表示
此外
- within(xx.xx.xx.*) 限定切点匹配的包
- bean(xxx) 限制切点匹配的bean
此外此外,可以为切点传入参数
@Pointcut("execution(String com.alibaba.spring.aop.IBuy.buy(double)) && args(price) && bean(girl)")
通知类型
- @Before 目标方法之前执行
- @After 目标方法返回或异常后调用
- @AfterReturning 目标返回后调用
- @AfterThrowing 目标抛出异常后调用
- @Around 将目标方法封装起来,使用xx.proceed()来调用
配置织入
- @EnableAspectJAutoProxy(proxyTargetClass = true)
- proxyTargetClass=true 基于cglib动态代理,缺陷是final方法无法织入
- proxyTargetClass=false 基于jdk动态代理,接口方式织入
3.4.2.xml
切点表达式
<bean id="boy" class="com.alibaba.spring.aop.Boy"></bean>
<bean id="girl" class="com.alibaba.spring.aop.Girl"></bean>
<bean id="buyAspectJ" class="com.alibaba.spring.aop.BuyAspectJ"></bean>
<aop:config proxy-target-class="true">
<aop:pointcut id="apoint" expression="execution(* com.alibaba.spring.aop.IBuy.buy(..))"/>
<aop:aspect id="qiemian" ref="buyAspectJ">
<aop:before pointcut-ref="apoint" method="hehe"/>
<aop:after pointcut-ref="apoint" method="haha"/>
<aop:after-returning pointcut-ref="apoint" method="xixi"/>
<aop:around pointcut-ref="apoint" method="xxx"/>
</aop:aspect>
</aop:config>
参数获取
<bean id="boy" class="com.alibaba.spring.aop.Boy"></bean>
<bean id="girl" class="com.alibaba.spring.aop.Girl"></bean>
<bean id="buyAspectJ" class="com.alibaba.spring.aop.BuyAspectJ"></bean>
<aop:config proxy-target-class="true">
<aop:pointcut id="apoint" expression="execution(String com.alibaba.spring.aop.IBuy.buy(double)) and args(price) and bean(girl)"/>
<aop:aspect id="qiemian" ref="buyAspectJ">
<aop:around pointcut-ref="apoint" method="hehe"/>
</aop:aspect>
</aop:config>
配置织入
<aop:config proxy-target-class="true"> </aop:config>
<aop:config proxy-target-class="false"> </aop:config>
3.5.嵌套问题
场景:类中方法1调用了该类的方法2时,调用的方法2将是未增强的。
原因:AOP的原理是动态代理,为原对象生成一个代理对象再执行,但是原对象方法1调用方法2使用的是this,即原对象自身的方法2,而不是代理对象的方法2.
解决:改代码,不用this.方法2,而是currentProxy().方法2,便可执行代理对象方法2.
3.6.事务@Transactional
3.6.1.实现
-
编程方法,实际上是调用API,在代码中去提交,回滚等。
-
使用注解的方式,在接口上使用@transactional,参数中可以注明隔离级别和传播机制。加上@transaction注解后,Spring会基于这个类生成一个代理对象,代理逻辑会先将自动提交设置为false,然后执行原本的业务逻辑,如果没有出现异常的化就会对该事务进行提交,否则回滚。当然对哪些异常回滚是可以配置的。
3.6.2.事务传播机制
多个事务方法相互调用的情况下,叫做事务的传播。
在@trancactional注解中通过参数方式进行规定
当a事务方法调用b事务方法时
-
required(spring默认事务传播类型)如果当前a没有事务,则b自己创建一个事务,如果两个都有的话,将b的事务加入到a,合并成一个。
-
support 若a存在事务,则将b事务加入,否则以非事务方式执行
-
mandatory 若存在则加入事务,否则抛出异常
-
requires_new 为b新建事务,分开执行
-
not_supported 如果当前存在事务,把当前事务挂起
-
never 不允许有事务,有的话抛出异常
-
nested 嵌套
3.6.3.事务什么时候失效
Spring事务的原理是AOP,生成代理对象,进行切面增强,失效的根本原因是AOP不起作用。
-
发生自调用,原来的类里面可能存在通过this调用本类的方法,此时这个this指的是对象本身,而不是代理对象。因此在对代理类执行时,会失去效果。
-
方法不是public,则无法被外部调用
-
数据库本身不支持事务
-
没有被spring管理
-
异常被吃掉,事务中的异常需要被抛出来才能够回滚,如果被catch则不能被回滚。
4.Spring MVC
4.1.SpringMVC工作流程(处理请求流程)
SSM框架流程(Spring + SpringMVC + MyBatis)
-
用户发送请求到DispatcherServlet
-
DispatcherServlet收到请求调用Handler处理器映射器HandleMapping(维护url到handler映射关系)
-
处理器映射器找到具体的处理器(可根据xml配置或注解进行查找),生成处理器或处理器拦截器一并返回给DispatcherServlet。
-
DispatcherServlet调用HandlerAdapter处理器适配器
-
处理器适配器调用真正的handle(controller)
-
Controller执行完成后返回ModelAndView
-
处理器适配器将ModelAndView再返回给DispatcherServlet
-
DispatcherServlet将ModelAndView传给ViewReslover视图解析器
-
ViewReslover解析后返回具体View
-
DispatcherServlet根据View进行视图渲染,即将模型数据填充至视图中
-
DispatcherServlet响应用户
4.2.常见概念
- Servlet(Servlet Applet) 是用JAVA编写的服务器端程序,通过实现Servlet接口创建,用来扩展服务器的性能。
用户发送请求给服务器 - 服务器把请求发给servlet - servlet生成响应内容发给服务器 - 服务器把响应返回给客户
-
HandlerMapping 根据用户请求的资源URL来查找Handler
-
HandlerAdapter 提供统一的handle方法,去执行不同的handler
-
Handler 直接对应MVC中的controller层,它的具体表现形式有很多,可以是类,也可以是方法。在Controller层中@RequestMapping标注的方法可以是一个Handler,实现controller接口的类也可以是一个handler,HandlerAdapter使用适配器模式进行统一的处理。
-
ModelAndView ModelAndView是Http请求过程中返回的模型和视图,以ModelMap的形式来保持模型数据,ModelMap中保持的模型数据将会在视图渲染阶段,由具体的View实现类来获取并使用。
4.3.拦截器和过滤器
过滤器Filter:过滤器作用在请求到达servlet容器(比如tomcat),但是未进入servlet时,主要用于对用户请求进行预处理,或者在responce后处理。即对请求和响应做额外的处理。
拦截器Interceptor:拦截器是对某些功能进行补充,是AOP的一种实现,一般作在方法前后拦截进行处理。比如在访问资源的方法前,使用登录拦截器进行拦截,判断用户是否登录是否有权限访问。拦截器可以将一些通用功能独立出来,提高代码复用率。
区别
-
过滤器基本对所有的请求起作用,而拦截器只是作用于特定的方法或功能
-
过滤器先执行,拦截器在servlet处理时执行
-
过滤器依赖于servlet容器,拦截器不依赖
-
过滤器基于函数回调,拦截器基java反射机制,
5.SpringBoot
5.1.SpringBoot的优势
-
自动配置:不用再像spring那样繁琐的配置,可以实现自动配置,通过maven项目的pom文件中添加相关依赖包,可以将第三方依赖自动注入。也就是他的starter机制。按照jar包中META-INF下的spring.factories来进行配置。可以很好的整合第三方框架,比如mybatis,dubbo
-
约定大于配置:由SpringBoot本身来配置目标结构,由开发者在结构中添加信息的软件设计范式。这一特点虽降低了部分灵活性,增加了BUG定位的复杂性,但减少了开发人员需要做出决定的数量,同时减少了大量的XML配置,并且可以将代码编译、测试和打包等工作自动化。
-
内嵌servlet容器,比如一般使用的tomcat
-
提供运行时监控
5.2.SpringBoot自动装配
@SpringBootApplication是一个组合注解,由三个注解构成
-
@SpringBootConfiguration 作用和@Configuration基本一样(类似xml文件,一般和bean一起使用),内含@Configuration注解,表明是一个配置类
-
EnabaleAutoConfiguration 与自动配置直接相关,通过这个注解把spring应用所需的bean注入容器中。@EnableAutoConfiguration作用就是从classpath中搜寻所有的META-INF/ spring.factories配置文件,帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到IOC容器中。这些配置生效的前提是,所对应的jar包都存在。
-
@ComponentScan spring里有四大注解:@Service,@Repository,@Component,@Controller用来定义一个bean.@ComponentScan注解就是用来自动扫描被这些注解标识的类,最终生成ioc容器里的bean。并且可以控制扫描的路径。默认是扫描所在类的包中的文件
5.3.如何理解SpringBoot中的starter
-
在原来的Spring开发中,如果需要引入mybatis等框架,是需要到xml中定义mybatis需要的bean的。
-
starter就是定义一个starter的jar包,写一个@Configuration配置类,将这些bean定义在里面,然后在starter包的META-INF/spring.factories中写入该配置类,springboot就会按照约定来加载该配置类。
-
开发人员只需要将需要的starter包依赖进应用,就可以直接进行代码开发。
5.4.SpringBoot启动流程
启动就是实例化SpringApplication并执行run方法
-
实例化SpringApplication,构造器里实现了四个功能。
-
推断应用类型是普通项目还是web项目
-
查找并加载所有可用初始化器,设置到initializers属性中
-
找出所有的应用程序监听器,设置到listeners中
-
推断并设置main方法的定义类,找到运行主类
-
-
run方法执行流程
-
记录启动时间,
-
获取并启动监听器,用来监听容器中发生的事件
-
创建一些环境,配置信息
-
创建应用上下文 创建ApplicationContext容器
-
初始化应用上下文
-
刷新应用上下文 真正将bean装配到容器中
-
5.5.注解底层原理
注解的底层都是通过反射
两种处理策略
- 类上的注解:像component,service,controller这种,spring会根据过滤规则把他们扫描并使用反射机制注册到容器中
- 类内的注解:像autowire,resource这种,spring通过bean对象实例化的后置处理器来实现。当容器启动时扫描所有的bean,当发现bean中有autowired注解时将bean注入。
- 通过反射获取到该类,并获取到该类的所有字段,遍历每一个字段以及上面的注解
- 如果该字段被autowired修饰了,则把该字段放入到列表中(属性和方法是分别处理的),这样就得到了需要注入的信息列表
- 调用inject方法实现注入,如果是属性则注入成员变量,如果是方法则调用方法注入
5.6.嵌入式服务器Tomcat
SpringBoot默认使用的是Tomcat作为内嵌服务器,不用我们再去下载Tomcat,其已经内置了tomcat.jar, 运行是会自动去启动tomcat,并利用Tomcat的SPI机制加载springMVC
5.6.1.Tomcat
Tomcat是一种web容器,创建并装载servlet(加载网页动态数据),这些servlet来提供服务。servlet就是在服务器端的java程序,用来提供服务
一个tomcat服务器管理多个service,每个sevice中有一个容器(管理业务逻辑)和多个连接器(管理连接)。
1)connector,负责接收连接请求,并创建线程让container处理请求
2)container处理具体的业务逻辑
5.6.2.SPI
SPI,Service Provider Interface,主要是被框架的开发人员使用,比如java.sql.Driver接口,其他不同厂商可以针对同一接口做出不同的实现,mysql和postgresql都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现。
当服务的提供者提供了一种接口的实现之后,需要在classpath下的META-INF/services/目录里创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类。当其他的程序需要这个服务的时候,就可以通过查找这个jar包(一般都是以jar包做依赖)的META-INF/services/中的配置文件,配置文件中有接口的具体实现类名,可以根据这个类名进行加载实例化,就可以使用该服务了。
6.Shiro
Shiro是java的一个安全框架
6.1.功能
-
身份验证:即登录,证明用户是谁
-
授权:访问控制,控制谁可以访问什么资源,验证用户的角色是否可以访问资源
-
会话管理:管理用户特定的会话
-
加密:通过使用加密算法保持数据安全且易用
6.2.核心组件
-
subject主体,即当前操作用户,(需要被认证的对象)
-
Security management安全管理器,shiro框架的核心,管理所有用户的安全操作。具体的认证,授权,会话管理,加密都由subject调用安全管理器执行。
-
Realm负责从数据层获取业务数据
6.3.和传统方式的对比
6.3.1.传统方式
-
用户发送请求给controller
-
controller接收用户名和密码后调用service
-
service负责进行具体操作,调用数据库判断用户名和密码,正确则将用户信息保存至session
6.3.2.shiro方式
-
用户发送请求给controller
-
controller调用shiro处理,将认证和授权抽取出来
-
认证完成后,从shiro中提取认证结果即可
这个过程相比于早期的操作,相当于验证用户名和密码的业务逻辑交给shiro安全框架来做。并且加密也交给shiro安全框架来做,然后由shiro安全框架来加密
7.Dubbo
- 分布式服务框架,里面用到了netty,zookeeper等技术
- 高性能的RPC框架
- SOA面向服务架构的方案
7.1.角色
-
provider服务提供方,服务间调用是NIO的,客户端只需要一个线程就能完成多个服务的调用
-
consumer服务消费者
-
Registry注册中心(一般使用zookeeper为注册中心)
- 注册中心挂了还是可以继续提供服务,因为注册中心服务返回的服务器列表会缓存在消费者中,即使中心挂了还可以根据缓存内容继续访问
-
Monitor监控中心,统计服务调用次数,调用时间等
7.2.调用流程
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心注册自己所需要的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更信息给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台进行调用
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定期发送到监控中心
7.3.负载均衡策略
Dubbo的负载均衡在客户端,避免了单点问题。其提供了四种负载均衡策略
- 随机负载均衡
- 轮询负载均衡
- 最少活跃调用数,使慢的provider收到更少的请求。
- 一致性哈希负载均衡,相同参数的请求总是落在同一个机器上
7.4.Netty Dubbo和RPC三者的关系
-
RPC是远程调用协议,一般用于分布式节点间的通讯
-
Dubbo是一种RPC框架,内部使用Netty做组件间的异步通信
-
Netty是异步,事件驱动的网络应用框架/工具。是一种NIO框架,基于java NIO进行封装和抽象的异步IO框架,使用简单。并且相比于java NIO有更强的功能。Dubbo就用户netty来进行异步通信
7.5.和Springcloud的比较
springcloud是一套微服务框架,相对与dubbo而言
-
springcloud是基于http的,而dubbo是基于RPC的,dubbo更快一些。
-
springcloud的功能更多,包括服务限流啊等等。