Spring Boot是一个依靠大量注解实现自动化配置的全新框架。约定优于配置;独立运行的 Spring 项目,内嵌servlet容器;Spring Boot 框架内部已经实现了与Spring以及其他常用第三方库的整合连接,并提供了默认最优化的整合配置,使用时基本上不需要额外生成配置代码和XML配置文件。在需要自定义配置的情况下,Spring Boot更加提倡使用Java config(Java 配置类)替换传统的XML配置方式,这样更加方便查看和管理。
IOC: 使用Spring框架之后对象的实例不再由调用者来创建,而是直接由Spring容器来创建,Spring容器会负责控制程序之间的关系,而不是调用者的程序代码直接控制。控制权由应用程序转移到Spring容器,控制权发生了反转。
AOP: 为开发者提供了一种描述横切关注点的机制,并能够自动将横切关注点织入到面向对象的软件系统中,从而实现了横切关注点的模块化。
AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理、日志管理、权限控制等,封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性
实现AOP的主要设计模式就是动态代理。
Spring的动态代理有两种:一是JDK的动态代理(只能代理接口);
另一个是cglib动态代理(可以代理类和接口)。
JDK代理实现的三个要点:
① 通过Java.lang.reflect.Proxy类来动态生成代理类;
② 代理类要实现InvocationHandler接口;
③ JDK代理只能基于接口进行动态代理的;
CGLib和JDK的原理类似,也是通过方法去反射调用目标对象的方法。
Springboot对于异常的处理也做了不错的支持,它提供了一个 @ControllerAdvice注解以及 @ExceptionHandler注解,前者是用来开启全局的异常捕获,后者则是说明捕获哪些异常,对那些异常进行处理。
- @ControllerAdvice
- public class MyExceptionHandler {
-
- @ExceptionHandler(value =Exception.class)
- public String exceptionHandler(Exception e){
- System.out.println("发生了一个异常"+e);
- return e.getMessage();
- }
- }
关于Spring的两三事:傻傻分不清楚的filter和interceptor - 知乎
Spring系列之Filter and Interceptor - 简书
SpringBoot系列(九)统一异常处理与统一结果返回-腾讯云开发者社区-腾讯云
1.注解语法
常用的Java注解如下:
1、@Deprecated – 所标注内容不再被建议使用;
2、@Override – 只能标注方法,表示该方法覆盖父类中的方法;
3、@Documented --所标注内容可以出现在javadoc中;
4、@Inherited – 只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性;
5、@Retention – 只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性;
6、@Target – 只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性;
7、@SuppressWarnings – 所标注内容产生的警告,编译器会对这些警告保持静默;
8、@interface – 用于定义一个注解;
java Annotation 的组成中,有 3 个非常重要的主干类。它们分别是:
Annotation.java
- package java.lang.annotation;
- public interface Annotation {
-
- boolean equals(Object obj);
-
- int hashCode();
-
- String toString();
-
- Class extends Annotation> annotationType();
- }
ElementType.java
- package java.lang.annotation;
-
- public enum ElementType {
- TYPE, /* 类、接口(包括注释类型)或枚举声明 */
-
- FIELD, /* 字段声明(包括枚举常量) */
-
- METHOD, /* 方法声明 */
-
- PARAMETER, /* 参数声明 */
-
- CONSTRUCTOR, /* 构造方法声明 */
-
- LOCAL_VARIABLE, /* 局部变量声明 */
-
- ANNOTATION_TYPE, /* 注释类型声明 */
-
- PACKAGE /* 包声明 */
- }
RetentionPolicy.java
- package java.lang.annotation;
- public enum RetentionPolicy {
- SOURCE, /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 */
-
- CLASS, /* 编译器将Annotation存储于类对应的.class文件中。默认行为 */
-
- RUNTIME /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
- }
source和class级别的注解需要继承AbstractProcessor,实现process方法实现我们的自定义注解处理逻辑,lombok的实现原理就在这。
2.注解原理
一个注解准确意义上来说,只不过是一种特殊的注释而已,如果没有解析它的代码,它可能连注释都不如。
而解析一个类或者方法的注解往往有两种形式,一种是编译期直接的扫描,一种是运行期反射。反射的事情我们待会说,而编译器的扫描指的是编译器在对 java 代码编译字节码的过程中会检测到某个类或者方法被一些注解修饰,这时它就会对于这些注解进行某些处理。
典型的就是注解 @Override,一旦编译器检测到某个方法被修饰了 @Override 注解,编译器就会检查当前方法的方法签名是否真正重写了父类的某个方法,也就是比较父类中是否具有一个同样的方法签名。
这一种情况只适用于那些编译器已经熟知的注解类,比如 JDK 内置的几个注解,而你自定义的注解,编译器是不知道你这个注解的作用的,当然也不知道该如何处理,往往只是会根据该注解的作用范围来选择是否编译进字节码文件,仅此而已。
反射注解的工作原理:
首先,我们通过键值对的形式可以为注解属性赋值,像这样:@Hello(value = "hello")。
接着,你用注解修饰某个元素,编译器将在编译期扫描每个类或者方法上的注解,会做一个基本的检查,你的这个注解是否允许作用在当前位置,最后会将注解信息写入元素的属性表。
然后,当你进行反射的时候,虚拟机将所有生命周期在 RUNTIME 的注解取出来放到一个 map 中,并创建一个 AnnotationInvocationHandler 实例,把这个 map 传递给它。
最后,虚拟机将采用 JDK 动态代理机制生成一个目标注解的代理类,并初始化好处理器。
那么这样,一个注解的实例就创建出来了,它本质上就是一个代理类,你应当去理解好 AnnotationInvocationHandler 中 invoke 方法的实现逻辑,这是核心。一句话概括就是,通过方法名返回注解属性值。
https://www.cnblogs.com/i-xq/p/13084959.html
3.lombok注解实现原理
通过 JDK 6 实现的 JSR 269: Pluggable Annotation Processing API (编译期的注解处理器) ,在编译期时把 Lombok 的注解转换为 Java 的常规方法的,我们可以通过继承 AbstractProcessor 类,重写它的 init() 和 process() 方法,实现一个简易版的 Lombok。但同时 Lombok 也存在这一些使用上的缺点,比如:降低了可调试性、可能会有兼容性等问题,因此我们在使用时要根据自己的业务场景和实际情况,来选择要不要使用 Lombok,以及应该如何使用 Lombok。
我们知道 Java 的编译过程大致可以分为三个阶段:
编译过程如下图所示:
而 Lombok 正是利用「注解处理」这一步进行实现的,Lombok 使用的是 JDK 6 实现的 JSR 269: Pluggable Annotation Processing API (编译期的注解处理器) ,它是在编译期时把 Lombok 的注解代码,转换为常规的 Java 方法而实现优雅地编程的。
https://www.cnblogs.com/vipstone/p/12597756.html
4.autowired 与 resource注解
@Resource和@Autowired都是用来进行依赖注入的注解,但是它们有一些不同之处。
@Autowired是Spring框架中的注解,它可以用来标注字段、构造函数、方法等,表示需要自动装配。它可以用来注入依赖的bean。如果有多个bean符合条件,可能会抛出异常。
@Resource是Java自带的注解,它可以用来标注字段、方法等,表示需要自动装配。它可以用来注入依赖的bean。如果有多个bean符合条件,会按照名称进行匹配。
总结:
@Autowired 是 Spring 框架中的注解,用来标注需要自动装配的 bean。
@Resource 是 Java 自带的注解,用来标注需要自动装配的 bean。
@Autowired 是按类型装配,如果有多个同类型的 bean,会抛出异常; @Resource 是按名称装配,如果名称不存在,会使用类型装配。
@Qualifier与@Autowired注解配合使用,通过名字挑选符合条件的。
当我们在使用依赖注入的时候,通常有三种方式:
1.通过构造器来注入;
2.通过setter方法来注入;
3.通过field变量来注入;
https://www.cnblogs.com/chansblogs/p/8343930.html
使用构造器注入的好处_构造注入的优点_AntChenxi的博客-CSDN博客
1.生命周期流程图
Spring Bean的生命周期分为四个阶段:实例化 Instantiation --> 属性赋值 Populate --> 初始化 Initialization --> 销毁 Destruction
生命周期1.png
(1)实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean
(2)设置对象属性(依赖注入):
实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成属性设置与依赖注入。
(3)处理Aware接口:
Spring会检测该对象是否实现了xxxAware接口,通过Aware类型的接口,可以让我们拿到Spring容器的一些资源:
(4)BeanPostProcessor前置处理:
如果想对Bean进行一些自定义的前置处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
(5)InitializingBean:
如果Bean实现了InitializingBean接口,执行afeterPropertiesSet()方法。
(6)init-method:
如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
(7)BeanPostProcessor后置处理:
如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
(8)DisposableBean:
当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
(9)destroy-method:
最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
2. 生命周期接口分类
Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:
(1)Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中
(2)Bean级生命周期接口方法:这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法
(3)容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
(4)工厂后处理器接口方法:这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器 接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。
@PostConstruct是java5的时候引入的注解,指的是在项目启动的时候执行这个方法,也可以理解为在spring容器启动的时候执行,可作为一些数据的常规化加载,比如数据字典之类的。
被@PostConstruct修饰的方法会在服务器加载Servle的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行
bean的构造方法-----》属性赋值-----》BeanPostProcessor的postProcessBeforeInitialization方法-----》@PostConstruct注解修饰的方法-----》InitializingBean接口afterPropertiesSet方法---》Init-method方法----》BeanPostProcessor的postProcessAfterInitialization方法。
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
下图是MyBatis架构图:
(1)mybatis-config.xml是Mybatis的核心配置文件,通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂
(2)基于SqlSessionFactory可以生成SqlSession对象
(3)SqlSession是一个既可以发送SQL去执行,并返回结果,类似于JDBC中的Connection对象,也是Mybatis中至关重要的一个对象。
(4)Executor是SqlSession底层的对象,用于执行SQL语句
(5)MapperStatement对象也是SqlSession底层的对象,用于接收输入映射(SQL语句中的参数),以及做输出映射(即将SQL查询的结果映射成相应的结果)
mybatis & ibatis
batis 是 Mybatis 的前身,两者都是优秀的持久层框架。
区别:
1、mybatis 实现接口绑定,不需要具体接口实现类。但是需要在xml文件中 的 namespace 绑定具体的接口。
这个实现原理是JDK的动态代理。
ibatis 需要定义具体接口的实现,并且在接口实现中获取SqlMapClient以及绑定xml文件。
2、XML文件不同
1)mybatis用的是
2)mybatis 支持 ognl 表达式,ibatis不支持
3)mybatis 接收参数的方式 #{id} ${id}$ ,ibatis 是 #id# $id$
ps: #与$ 的区别是# 是作为参数传递,预编译使用
$ 是作为sql 一部分拼接,会有sql注入的风险
4)mybatis 参数类型是 parameterType,ibatis 参数类型是parameterClass
5)动态语句写法不同
6)mybatis 迭代用的是 foreach ,ibatis用的是iterator
(1) dubbo架构
为了学习如何使用Dubbo,首先我们要了解dubbo的架构是怎么样的,如上图所示,dubbo 的核心架构中,分了4个角色:注册中心、服务提供者、服务消费者、监控中心。它们的功能分别是:
(2)dubbo扩展机制
dubbo支持的协议有:
1、dubbo 默认协议:
2、rmi 协议:
3、hessian 协议:
4、http 协议:
5、webservice 协议:
6、thrift 协议:
7、基于 Redis实现的 RPC 协议
8、基于 Memcached 实现的 RPC 协议
官方文档:http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-protocol.html
如何扩展协议? 基于dubbo扩展点机制
(3)dubbo异常处理
基于filter进行统一异常处理
@Activate(group = CommonConstants.PROVIDER, order = 2)
ZooKeeper 基础知识基本分为三大模块:数据模型、ACL 权限控制、Watch 监控。
数据模型是最重要的,很多 ZooKeeper 中典型的应用场景都是利用这些基础模块实现的。比如我们可以利用数据模型中的临时节点和 Watch 监控机制来实现一个发布订阅的功能。
数据模型就是 ZooKeeper 用来存储和处理数据的一种逻辑结构。ZooKeeper 数据模型最根本的功能就像一个数据库。
ZooKeeper 中的数据模型是一种树形结构,非常像电脑中的文件系统,有一个根文件夹,下面还有很多子文件夹。ZooKeeper 的数据模型也具有一个固定的根节点(/),我们可以在根节点下创建子节点,并在子节点下继续创建下一级节点。ZooKeeper 树中的每一层级用斜杠(/)分隔开,且只能用绝对路径(如“get /work/task1”)的方式查询 ZooKeeper 节点,而不能使用相对路径。
如何使用 ZooKeeper 的 ACL 机制来实现客户端对数据节点的访问控制?
一个 ACL 权限设置通常可以分为 3 部分,分别是:权限模式(Scheme)、授权对象(ID)、权限信息(Permission)。最终组成一条例如“scheme:id:permission”格式的 ACL 请求信息。
客户端在 ACL 权限请求发送过程的步骤比较简单:首先是封装该请求的类型,之后将权限信息封装到 request 中并发送给服务端。而服务器的实现比较复杂,首先分析请求类型是否是权限相关操作,之后根据不同的权限模式(scheme)调用不同的实现类验证权限最后存储权限信息。
ZooKeeper 的客户端也可以通过 Watch 机制来订阅当服务器上某一节点的数据或状态发生变化时收到相应的通知,我们可以通过向 ZooKeeper 客户端的构造方法中传递 Watcher 参数的方式实现:
new ZooKeeper(String connectString, int sessionTimeout, Watcher watcher)
我们先看一下客户端的实现过程,在发送一个 Watch 监控事件的会话请求时,ZooKeeper 客户端主要做了两个工作:标记该会话是一个带有 Watch 事件的请求、将 Watch 事件存储到 ZKWatchManager。
Zookeeper 服务端处理 Watch 事件基本有 2 个过程:解析收到的请求是否带有 Watch 注册事件、将对应的 Watch 事件存储到 WatchManager。
ZooKeeper 实现的方式是通过客服端和服务端分别创建有观察者的信息列表。客户端调用 getData、exist 等接口时,首先将对应的 Watch 事件放到本地的 ZKWatchManager 中进行管理。服务端在接收到客户端的请求后根据请求类型判断是否含有 Watch 事件,并将对应事件放到 WatchManager 中进行管理。
在事件触发的时候服务端通过节点的路径信息查询相应的 Watch 事件通知给客户端,客户端在接收到通知后,首先查询本地的 ZKWatchManager 获得对应的 Watch 信息处理回调操作。这种设计不但实现了一个分布式环境下的观察者模式,而且通过将客户端和服务端各自处理 Watch 事件所需要的额外信息分别保存在两端,减少彼此通信的内容。大大提升了服务的处理性能。
ZooKeeper - 知乎
Zookeeper的分布式锁实现
(1)Spring支持五个作用域:singleton、prototype、request、session、global session
1.singleton:默认作用域Spring IOC容器仅存在一个Bean实例,Bean以单例方式存在,在创建容器时就同时自动创建了一个Bean对象。作用域范围是ApplicationContext中。
2.prototype:每次从容器中调用Bean时,都会返回一个新的实例,即每次调用getBean时。作用域返回是getBean方法调用直至方法结束。
相当于执行newXxxBean().Prototype是原型类型,再我们创建容器的时候并没有实例化,而是当我们获取Bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。
3.request:每次HTTP请求都会创建一个新的Bean,作用域范围是每次发起http请求直至拿到相应结果。该作用域仅适用于WebApplicationContext环境。
4.session:首次http请求创建一个实例,作用域是浏览器首次访问直至浏览器关闭。
同一个HTTP Session共享一个Bean,不同Session使用不通的Bean,仅适用于WebApplicationContext环境。
5.global-session:作用域范围是WebApplicationContext中, 作用于集群环境的会话范围。一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境。
作用域范围比较:
prototype < request < session < global-session < singleton