关于spring:Controller-RestController

@Controller在Spring中曾经应用很久了,@RestController是在Spring 4.0呈现的,它是@Controller和@ResponseBody两个注解的联合。 @Controller经典的Spring controller类会应用@Controller注解标注。被@Controller标注的类为@Component类,并且能够被主动扫描发现。@Controller注解个别会和@RequestMapping注解一起应用。 @Controller@RequestMapping("books")public class SimpleBookController { @GetMapping("/{id}", produces = "application/json") public @ResponseBody Book getBook(@PathVariable int id) { return findBookById(id); } private Book findBookById(int id) { // ... }}@RespondBody注解:将办法返回值主动转换为HttpResponse对象。 @RestController@RestController简化了controller类的实现,它是@Controller和@RespondBody的联合。 @RestController@RequestMapping("books-rest")public class SimpleBookRestController { @GetMapping("/{id}", produces = "application/json") public Book getBook(@PathVariable int id) { return findBookById(id); } private Book findBookById(int id) { // ... }}应用了@RestController,@RespondBody就不再须要了。 The Spring @Controller and @RestController Annotations

January 27, 2021 · 1 min · jiezi

关于spring:Mybatis-plus通用字段自动填充的最佳实践总结

在进行长久层数据保护(新增或批改)的时候,咱们通常须要记录一些非业务字段,比方:create_time、update_time、update_by、create_by等用来保护数据记录的创立工夫、批改工夫、批改人、创建人等信息。通常状况下咱们须要对这些字段进行手动赋值。赋值的过程也比拟冗余,都是反复操作。 通常是为create_time赋值为零碎的以后工夫、update_time赋值为零碎批改操作执行时的以后工夫。create_by(创建人)、update_by(批改人)赋值为以后的登录用户的用户名xxxYyyZzz.setUpdateBy("zimug"); //数据记录更新操作人xxxYyyZzz.setUpdateTime(new Date()); //数据记录更新操作的工夫Mybatis plus 为咱们提供了一种一劳永逸的自动化赋值形式。 一、调整数据库表构造以mysql数据库环境下的xxx_yyy_zzz表为例,在原有的表字段的根底上,增加上面的四个通用数据保护字段。 ALTER TABLE `xxx_yyy_zzz` ADD COLUMN `create_by` VARCHAR(64) NOT NULL COMMENT '本条记录创建人';ALTER TABLE `xxx_yyy_zzz` ADD COLUMN `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '本条记录创立工夫';ALTER TABLE `xxx_yyy_zzz` ADD COLUMN `update_by` VARCHAR(64) NOT NULL COMMENT '本条记录批改人';ALTER TABLE `xxx_yyy_zzz` ADD COLUMN `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '本条记录的批改工夫';二、通用保护信息父类-主动赋值的字段既然咱们对某一张表的数据进行新增创立、批改信息的保护,咱们的实体类也要做必要的调整。为了防止为每一个实体类都加上这四个成员变量,咱们定义一个父类BaseColumns。 @Datapublic class BaseColumns { /** * 本条记录创建人,insert操作的时候主动为该字段赋值 */ @TableField(fill = FieldFill.INSERT private String createBy; /** * 本条记录创立工夫,insert操作的时候主动为该字段赋值 */ @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; /** * 本条记录更新人,insert或update操作的时候主动为该字段赋值,select = false */ @TableField(fill = FieldFill.INSERT_UPDATE,select = false) private String updateBy; /** * 本条记录更新工夫,insert或update操作的时候主动为该字段赋值,select = false */ @TableField(fill = FieldFill.INSERT_UPDATE,select = false) private LocalDateTime updateTime;}fill = FieldFill.INSERT示意insert操作的时候主动为该字段赋值fill = FieldFill.INSERT_UPDATE示意nsert或update操作的时候主动为该字段赋值select = false示意在应用Mybatis Wrapper条件结构器进行查问的时候,不查问这个属性对应的数据库字段。数据批改工夫操作人通常对于运维更有意义,所以通常不须要展现在web页面上,所以通常select查问的时候不蕴含它。(这个内容与咱们本机的字段主动填充没有太间接的分割,然而在理论利用中是有意义的)三、实体类的实现下文实体类XxxYyyZzz对应数据库中的xxx_yyy_zzz表,除了以上四个通用字段,xxx_yyy_zzz表还蕴含其余的业务字段。 ...

January 27, 2021 · 1 min · jiezi

关于spring:Mybatis-Plus-34版本之后分页插件的变化

一、MybatisPlusInterceptor从Mybatis Plus 3.4.0版本开始,不再应用旧版本的PaginationInterceptor ,而是应用MybatisPlusInterceptor。MybatisPlusInterceptor是一系列的实现InnerInterceptor的拦截器链,也能够了解为一个汇合。能够包含如下的一些拦截器 主动分页: PaginationInnerInterceptor(最罕用)多租户: TenantLineInnerInterceptor动静表名: DynamicTableNameInnerInterceptor乐观锁: OptimisticLockerInnerInterceptorsql性能标准: IllegalSQLInnerInterceptor避免全表更新与删除: BlockAttackInnerInterceptor二、旧版分页插件配置办法(Mybatis Plus 3.4.0版本之前)@Configuration@MapperScan(basePackages = {"com.zimug.**.mapper"})public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // 设置申请的页面大于最大页后操作, true调回到首页,false 持续申请 默认false // paginationInterceptor.setOverflow(false); // 设置最大单页限度数量,默认 500 条,-1 不受限制 // paginationInterceptor.setLimit(500); // 开启 count 的 join 优化,只针对局部 left join paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); return paginationInterceptor; }}三、新的分页插件配置办法(Mybatis Plus 3.4.0版本及其之后的版本)新的分页插件,一弛缓二缓遵循mybatis的规定,须要设置 MybatisConfiguration#useDeprecatedExecutor = false 防止缓存呈现问题 @Configuration@MapperScan(basePackages = {"com.zimug.**.mapper"})public class MybatisPlusConfig { /** * 新的分页插件,一弛缓二缓遵循mybatis的规定,须要设置 MybatisConfiguration#useDeprecatedExecutor = false 防止缓存呈现问题(该属性会在旧插件移除后一起移除) */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //向Mybatis过滤器链中增加分页拦截器 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //还能够增加i他的拦截器 return interceptor; } @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setUseDeprecatedExecutor(false); }}四、分页查问的应用办法分页查问的应用办法没有变动,依然和Mybatis之前的版本统一,没有变动。 这里简略举一个例子 ...

January 25, 2021 · 1 min · jiezi

关于spring:一个程序员的自述

从业四年,摸爬滚打的我,非常感激路上碰到的给予过领导的徒弟们,明天记录下已经经验与大家分享,心愿对刚入行的小朋友有点帮忙。 16年7月末,大三完结后,在老家呆了7天就到了北京找实习工作。 分明记得过后是两家单位叫我去面试,其中一家须要培训就没再思考,在另一家单位面试通过,回顾下过后的场景: 大学并没有开设JAVA的课程,所以我去面试怀揣的仅仅就是从网上学习的简略的Struts2开发方法(无知者无畏)面试官过后并没有问一丝丝对于JAVA根底或者框架的内容,问了在学校的一些状况,还问了爸妈的生日(没答上)16年8月开始,稀里糊涂进了单位开始了作为一JAVA开发工程师的生涯(这个期间真的是最渴望学习的时候,对将来的无所不知、神往让一个人那么酷爱学习,然而如果你是一个人的话,学习效率却又那么低): 记得过后我的项目有一部分用的Spring框架,有一部分用的简略的Servlet记得过后会学习怎么建一个工程并跑起来,说是学习其实就是照着一个好的工程抄一遍,记不住就多抄几遍记得过后用的是Eclipse,在配置工程的时候会有很多简单操作记得过后配置Spring工程的XML文件时会因为xsd配置、命名空间配置搞出很多问题记得过后调JSP款式只会硬写px,仅仅是在我的显示器上能看的悦目而已记得过后照着教程学习如何在Linux装置Mysql,装置Nginx,Nginx尤其简单记得过后也曾有拜读过JAVA编程思维、HTTP权威指南记得过后学习如何配置多数据源,如果读写拆散,还理解了MyCat,过后基本用不上的货色,用上了就靠那程度也不可能用好的货色,不晓得为啥始终在看,有意思记得过后我负责Servlet的我的项目,捎带着装一些一体机,尽管代码程度无限,然而装机程度我还是很不错的记得过后有一些对浏览器的非凡需要,还编译了Google Chromiuml浏览器,记得是正文了些代码把浏览器解体后再启动的弹窗给屏蔽了,把浏览器的地址栏给屏蔽了,还把这个点子交给了同一个探讨群的弟兄,那弟兄给我发了60多的红包,美当初想想都感觉本人过后对学习广度的要求真是太过分了,啥都想懂,那哪行啊记得过后作为一个程序员在楼下装机的工夫比在楼上工位敲代码的工夫都长,导致我跟市场部的人混的挺熟,哎之后要做毕业设计就回校呆了俩月,做出了赫赫有名的学生信息管理系统,此时是17年4月份(工作一阵子后的假期是那么的爽,前一半人生的最初一个长假): 论文次要倒不是探讨怎么写JAVAWEB,是讲怎么搞一个简略的分布式系统过后筹备的很充沛,工程用了dubbo,过后打算是部署两个后端利用,演示的时候会kill掉其中一个利用,然而零碎还是能运行,以突出分布式的劣势最牛逼的中央来了,过后一上台缓和的手抖的不受管制,这部分演示间接放弃了,淦毕业后,回到单位,没过俩月(17年11月)被外派到了一个我的项目(打游戏都有新的征程,换了新我的项目就像换了个单位一样,什么都是陈腐的,什么都是能够学习的,意识更多的人,学更多的货色): 记得过后一水的Spring框架记得过后好多人开发一个我的项目,还有专门的前端,跟之前齐全不一样记得过后开发的时候,开发组长会建好所有的类,并在类里写好正文,只须要负责填空就好了,刚一接触这个模式都给我整不会了,开发很简略但也很无聊记得起初开发工作实现了会看整个我的项目的大框架,接触了Spring Security,单点登陆,Activiti工作流记得起初领导忽然叫我接手了Activiti工作流的开发,过后为了让它用起来很敌对,做了些改变,尽管不太简略,然而很有意思算上实习也工作一年多了,然而在学习的时候依然是照着他人的工程剽窃配置,知其然而不知其所以然之后有一个紧急的小我的项目要做,这是一个没有组长正文的新我的项目,这是我第一次真正意义上开发一个我的项目,最初做的很失败,后续bug的解决根本就是代码重写和硬补充,开发前的构思真的很重要之后开始学习一些HTTP、JVM等一些理论知识,开始了一个看了就忘的一个过程,不晓得是无奈了解还是什么起因,过后感觉看懂了,然而又跟事实利用无奈联合,所以忘的也很快记得过后看源码催熟的速度比大学看数据催熟的速度还要快记得过后针对分布式问题专门搜了分布式事务相干实现,后果还是只知其一;不知其二记得过后对设计模式的了解它就只是停留在书本上的一些常识,无奈利用的常识2018年5月开始,搭建了一个本人的博客,开始记录一些平时工作的小教训,在翻了翻之前的博客之后,发现过后写的根本都是读书笔记,有零散几篇记录了过后感觉设计的很奇妙的代码,当然当初在看的话都有点小童稚了。(在过后工作两年的状况下,对代码深度还是无所不知,感觉本人后方的路还是判若两人的含糊,就问你慌不慌,没心没肺的我必定不慌) 2019年中旬,糊里糊涂的工作3年,记得是在看了一个读Mybatis源码的视频,感觉是相当有意思,有人带着读代码,还是很难受的,就找了他们平台的Spring相干的视频,看了一遍。(看完之后怎么说呢,感觉就有种醍醐灌顶的感觉,不晓得是因为工作年限到了,还是说因为有人教会了读源码的办法,就感觉对代码如同多懂了点什么。) 之后可能本人从头读Spring源码,理解Spring组件的所以然能从异样中跟踪源码找到问题学习HTTP,TCP,JVM理论知识也不再读了就忘学习新的框架,在读完根底的文档后大抵能想到一些实现,并通过源码来验证2020疫情的一年,实际操作中常识用的越来越纯熟,数据库死锁剖析、线程dump剖析也都在线上碰到了,理论知识越来越能融入到实际中,对理论知识的需求量也越来越大,不论是当前的工作和面试,都越发的考验对根底的了解。 总结: 不要感觉大学的课没用不要本人漫无目的的学习,加群聊,倍速看视频教程学办法不要在本人刚入行的时候就充斥对将来的放心 可能想表白的没表白分明,越写越不晓得怎么写,然而心愿从事代码行业的各位可能踏踏实实的学习提高,没有哪个单位会淘汰一个牛逼的人

January 23, 2021 · 1 min · jiezi

关于spring:长文干货-一文搞懂IoC的依赖注入

有幻想,有情怀,有温度,干货满满; 关注一下我吧。一、注解驱动IoCxml驱动的IoC容器应用的是ClassPathXmlApplicationContext读取xml内bean信息 注解驱动的IoC容器应用的是AnnotationConfigApplicationContext读取Java类中的bean信息 1. AnnotationConfigApplicationContext 的注册应用相比于xml文件作为驱动, 注解驱动须要指明配置类 一个配置类能够了解为"相当于"一个xml 配置类只须要在类上标注注解 @Configuration @Configurationpublic class DemoConfiguration {}在xml中申明bean的形式 <bean id="person" class="com.huodd.bean.Person"></bean>在配置类中应用的是@Bean注解 @Beanpublic Person person() { return new Person();}阐明: 向IoC容器注册一个类型为Persion,id为Person的Bean 办法名示意的是bean的id 返回值示意的是注册的bean的类型 @Bean注解也能够显示的申明bean的id 如 @Bean("person1") 2. 注解IoC容器的初始化public class AnnotationConfigApplication { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(DemoConfiguration.class); Person person = ctx.getBean(Person.class); System.out.println(person); }}运行后Person控制台打印后果 com.huodd.bean.Person@55536d9e3. 组件的注册和扫描上述初始化时 咱们在应用AnnotationConfigApplicationContext时传递了参数 Class<?>... componentClasses 翻看AnnotationConfigApplicationContext的构造方法能够发现还能够传递参数的参数类型还有 String... basePackages 这里就波及到组件的注册和扫描 这里能够思考一个问题, 如果咱们要注册的组件特地多, 那进行编写这些@Bean的时候代码工作量也会特地多,这时候该如何解决呢?Spring 给咱们提供了几个注解,能够帮忙咱们疾速注册须要的组件, 这些注解被称为模式注解(stereotype annotations) @Component@Component能够说是所有组件注册的本源 在类上标注 @Component 代表该类被注册到IoC容器中作为一个Bean ...

January 22, 2021 · 3 min · jiezi

关于spring:一文带你搞懂从动态代理实现到Spring-AOP

摘要:本文次要讲了Spring Aop动静代理实现的两种形式。1. Spring AOPSpring是一个轻型容器,Spring整个系列的最最外围的概念当属IoC、AOP。可见AOP是Spring框架中的外围之一,在利用中具备十分重要的作用,也是Spring其余组件的根底。AOP(Aspect Oriented Programming),即面向切面编程,能够说是OOP(Object Oriented Programming,面向对象编程)的补充和欠缺。OOP引入封装、继承、多态等概念来建设一种对象层次结构,用于模仿公共行为的一个汇合。不过OOP容许开发者定义纵向的关系,但并不适宜定义横向的关系,例如日志性能。 对于AOP的基础知识,并不是本文的重点,咱们次要来看下AOP的外围性能的底层实现机制:动静代理的实现原理。AOP的拦挡性能是由java中的动静代理来实现的。在指标类的根底上减少切面逻辑,生成加强的指标类(该切面逻辑或者在指标类函数执行之前,或者指标类函数执行之后,或者在指标类函数抛出异样时候执行。不同的切入机会对应不同的Interceptor的品种,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。 那么动静代理是如何实现将切面逻辑(advise)织入到指标类办法中去的呢?上面咱们就来具体介绍并实现AOP中用到的两种动静代理。 AOP的源码中用到了两种动静代理来实现拦挡切入性能:jdk动静代理和cglib动静代理。两种办法同时存在,各有优劣。jdk动静代理是由java外部的反射机制来实现的,cglib动静代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比拟高效,而asm在生成类之后的相干执行过程中比拟高效(能够通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。 上面咱们别离来示例实现这两种办法。 2. JDK动静代理2.1 定义接口与实现类 下面代码定义了一个被拦挡对象接口,即横切关注点。上面代码实现被拦挡对象接口。 2.2 JDK动静代理类 上述代码实现了动静代理类JDKProxy,实现InvocationHandler接口,并且实现接口中的invoke办法。当客户端调用代理对象的业务办法时,代理对象执行invoke办法,invoke办法把调用委派给targetObject,相当于调用指标对象的办法,在invoke办法委派前判断权限,实现办法的拦挡。 2.3 测试 后果如下: 3. CGLIB字节码生成3.1 要代理的类CGLIB既能够对接口的类生成代理,也能够针对类生成代理。示例中,实现对类的代理。 该类的实现和下面的接口实现一样,为了放弃对立。 3.2 CGLIB动静代理类 上述实现了创立子类的办法与代理的办法。getProxy(SuperClass.class)办法通过入参即父类的字节码,扩大父类的class来创立代理对象。intercept()办法拦挡所有指标类办法的调用,obj示意指标类的实例,method为指标类办法的反射对象,args为办法的动静入参,methodProxy为代理类实例。method.invoke(targetObject, args)通过代理类调用父类中的办法。 3.3 测试 后果如下: 4. 总结本文次要讲了Spring Aop动静代理实现的两种形式,并别离介绍了其优缺点。jdk动静代理的利用前提是指标类基于对立的接口。如果没有该前提,jdk动静代理不能利用。由此能够看出,jdk动静代理有肯定的局限性,cglib这种第三方类库实现的动静代理利用更加宽泛,且在效率上更有劣势。 JDK动静代理机制是委托机制,不须要以来第三方的库,只有要JDK环境就能够进行代理,动静实现接口类,在动静生成的实现类外面委托为hanlder去调用原始实现类办法;CGLib 必须依赖于CGLib的类库,应用的是继承机制,是被代理类和代理类继承的关系,所以代理类是能够赋值给被代理类的,如果被代理类有接口,那么代理类也能够赋值给接口。 参考jdk动静代理代理与cglib代理原理探索AOP的底层实现-CGLIB动静代理和JDK动静代理本文分享自华为云社区《还不懂Spring AOP?一文带你搞懂动静代理》,原文作者:aoho 。 点击关注,第一工夫理解华为云陈腐技术~

January 22, 2021 · 1 min · jiezi

关于spring:SpringBoot-整合-Log4j2-日志框架

前言代码运行日志对于我的项目来说非常重要。本文记录的是 SpringBoot 与 Log4j2 的整合配置过程,至于其余日志框架和 Log4j2 的比照,小伙伴们可自行查阅材料。 环境JDK 8Gradle 6.7筹备排除 Logback 依赖先排除 SpringBoot 默认应用的 Logback 日志框架,在 build.gradle 里增加上面的配置。 configurations { implementation.exclude module: 'spring-boot-starter-logging'}引入 Log4j2 依赖咱们采纳 Log4j2 反对的 YAML 格局配置文件,反对该格局须要退出 jackson-dataformat-yaml 依赖,详情可查阅文档。 dependencies { implementation 'org.springframework.boot:spring-boot-starter-log4j2' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml'}理解日志等级Standard LevelInt LevelOFF0FATAL100ERROR200WARN300INFO400DEBUG500TRACE600ALLInteger.MAX_VALUE级别从低到高别离是:ALL、TRACE、DEBUG、INFO、WARN、ERROR、FATAL、OFF 但因为咱们应用的是 Slf4j 门面,所以 ALL、FATAL 和 OFF 级别无奈应用。可阅读文章 为什么阿里巴巴禁止工程师间接应用日志零碎(Log4j、Logback)中的 API 理解日志门面相干常识。 配置文件构造Appenders Appender LayoutFilterPolicyStrategy...Loggers LoggerRootLoggerAppender能够了解为「管道」,管制日志保留的地位。上面的其它配置参数都是以 rollingFileAppender 为例。 其余 Appender 相干文档可参考:Log4j2 官网文档 Appender 局部。Layout参数阐明%d日志工夫%level日志级别%pid过程 ID%t线程名%cLogger 名称%msg日志文本%n换行符%highlight色彩高亮管制日志格局,个别采纳 patternLayout。 appenders: rollingFile: patternLayout: # 日志格局模板 pattern: "%d{DEFAULT} %5level %pid --- %c : %msg%n"如果想在「控制台」中打印出有色彩的日志信息,可退出 consoleAppender 后在 pattern 字段中退出 %highlight 参数。 ...

January 22, 2021 · 2 min · jiezi

关于spring:Spring-源码学习-16单例-Bean-创建

前言在 finishBeanFactoryInitialization 中介绍了创立 Bean 的流程大略流程,这里进入单例 Bean 的创立过程。 这里次要分为三个局部创立单例 Bean getSingletoncreateBeangetObjectForBeanInstance上面进入源码: getSingletonpublic Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); // 加锁 synchronized (this.singletonObjects) { // 查看 singletonObjects 缓存中是否有 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { // 查看是否在执行销毁 if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } // 将 Bean 增加到 singletonsCurrentlyInCreation 汇合中, 示意正在创立 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 调用工厂办法 // 也就是调用 createBean(beanName, mbd, args) singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } // 创立胜利, 从 singletonsCurrentlyInCreation 移除 afterSingletonCreation(beanName); } if (newSingleton) { // 将给定的单例对象增加到该工厂的单例缓存中 // this.singletonObjects.put(beanName, singletonObject); // this.singletonFactories.remove(beanName); // this.earlySingletonObjects.remove(beanName); // this.registeredSingletons.add(beanName); addSingleton(beanName, singletonObject); } } return singletonObject; }}返回以给定名称注册的(原始)单例对象,如果尚未注册,则创立并注册一个新对象。 ...

January 21, 2021 · 6 min · jiezi

关于spring:小马哥讲Spring核心编程思想第一章学习笔记1

《小马哥讲Spring外围编程思维》-第一章学习笔记(1)一、课程介绍[1、为什么要学习spring?][2、深刻学习spring的难点有哪些?][3、课程的设计思路是怎么的?]二、内容综述三、课前筹备四、个性总览五、Spring版本个性六、Spring 模块化设计七、Spring 对 Java 语言个性使用Java语法变动Spring 对 Java 语言个性使用Java 5 语法个性Java 6 语法个性Java 7 语法个性Java 8 语法个性八、Spring 对 JDK API 实际九、Spring 对 Java EE API 整合十、Spring 编程模型一、课程介绍1、为什么要学习spring?生态系统宏大SpringBoot SpringCloud …… Spring是生态基石Spring Framework是一个优良的框架,很多细节值得咱们学习第一点:java语言个性:反射,动静,代理,枚举,泛型,注解、Lambda语法;第二点:设计思维与模式的实现,如OOP、IoC DDD TDD GoF23等;第三点:Java API的封装和简化 如JDBC事务 TransactionServlet,JPA,JMX,Bean,Validation;第四点:JSR标准的适配和实现;第五点:第三方框架的整合,如mybatis整合,Hibernetes和Redis。Spring的胜利不仅得益于作者在哲学层面上的思考,也受害于丰盛的软件工程教训。 2、深刻学习spring的难点有哪些?从性能个性到编程模型从设计模式到技术规范从实践根底到实战演练 3、课程的设计思路是怎么的?面试题+编程模式、设计思维、技术规范+实战-把握个性、了解原理 二、内容综述 三、课前筹备心态、办法(根底、思考、剖析、实际)、工具 四、个性总览 五、Spring版本个性Java版本依赖与反对: Spring Framework 版本Java 标准版Java 企业版1.x1.3+J2EE 1.3 +2.x1.4.2+J2EE 1.3 +3.x5+J2EE 1.4 和 Java EE 54.x6+Java EE 6 和 75.x8+Java EE 7六、Spring 模块化设计七、Spring 对 Java 语言个性使用Java语法变动 Spring 对 Java 语言个性使用Java 5 语法个性语法个性Spring 反对版本代表实现注解(Annotation)1.2 +@Transactional枚举(Enumeration)1.2 +Propagationfor-each 语法3.0 +AbstractApplicationContext主动装箱(AutoBoxing)3.0 + 泛型(Generic)3.0 +ApplicationListenerJava 6 语法个性语法个性Spring 反对版本代表实现接口 @Override4.0 + Java 7 语法个性语法个性Spring 反对版本代表实现Diamond 语法5.0 +DefaultListableBeanFactorytry-with-resources 语法5.0 +ResourceBundleMessageSourceJava 8 语法个性语法个性Spring 反对版本代表实现Lambda 语法5.0 +PropertyEditorRegistrySupport八、Spring 对 JDK API 实际九、Spring 对 Java EE API 整合十、Spring 编程模型 ...

January 21, 2021 · 1 min · jiezi

关于spring:SpringCloud整合之Eureka

前言咱们后面的博客曾经学习了 springboot 如何整合 dubbo 框架springboot整合dubbo 在整合 SpringCloud 前,大家有没有想过他和 dubbo 有什么差别: 起源(背景): Dubbo,是阿里巴巴服务化治理的外围框架,并被广泛应用于阿里巴巴团体的各成员站点。Spring Cloud,从命名咱们就能够晓得,它是Spring Source的产物,Spring社区的弱小背书能够说是Java企业界最有影响力的组织了,除了Spring Source之外,还有Pivotal和Netfix是其弱小的后盾与技术输入。其中Netflix开源的整套微服务架构套件是Spring Cloud的外围。简而言之dubbo是阿里写的属于国产,springcloud 属于国际版利用更广。2.注册核心: dubbo反对的注册核心为:Zookeeper(官网举荐)、Multicast、Redis、Simple,咱们罕用为zk。springcloud 反对的注册核心有Eureka、Zookeeper、Consul、Nacos,各个注册核心的区别请查阅springcloud四个注册核心的比拟这里我应用的是曾经闭源的Eureka。ZooKeeper是个CP强一致性和分区容错性,而Eureka为AP准则,舍弃了强一致性,保障了高可用。 传输: Dubbo因为是二进制的传输,占用带宽会更少;Spring Cloud是http协定传输,带宽会比拟多,同时应用http协定个别会应用JSON报文,耗费会更大。然而在国内95%的公司内,网络耗费不是什么太大问题,如果真的成了问题,通过压缩、二进制、高速缓存、分段降级等办法,很容易解。开发难度: Dubbo的开发难度较大,起因是dubbo的jar包依赖问题很多大型工程无奈解决;Spring Cloud的接口协议约定比拟自在且涣散,须要有强有力的行政措施来限度接口无序降级后续改良: Dubbo通过dubbofilter,很多货色没有,须要本人继承,如监控,如日志,如限流,如追踪配置核心: dubbo:如果咱们应用配置核心、分布式跟踪这些内容都须要本人去集成,无形中减少了应用难度。核心部件的比拟:Dubbo: Provider:裸露服务的提供方,能够通过 jar 或者容器的形式启动服务。Consumer:调用近程服务的服务生产方。Registry:服务注册核心和发现核心。Monitor:统计服务和调用次数,调用工夫监控核心。(Dubbo 的控制台页面中能够显示,目前只有一个简略版本。)Container:服务运行的容器。Spring Cloud: Service Provider: 裸露服务的提供方。Service Consumer:调用近程服务的服务生产方。EureKa Server: 服务注册核心和服务发现核心。Spring Cloud:提供了微服务的一整套解决方案:服务发现注册、配置核心、音讯总线、负载平衡、断路器、数据监控等 架构的残缺度: Dubbo只是实现了服务治理;Spring Cloud上面有17个子我的项目(可能还会新增)别离笼罩了微服务架构下的方方面面,服务治理只是其中的一个方面;肯定水平来说,Dubbo只是Spring Cloud Netflix中的一个子集。服务依赖形式: Dubbo:服务提供方与生产方通过接口的形式依赖,服务调用设计如下:Interface 层:服务接口层,定义了服务对外提供的所有接口。Molel 层:服务的 DTO 对象层。Business层:业务实现层,实现 Interface 接口并且和 DB 交互。因而须要为每个微服务定义各自的 Interface 接口,并通过继续集成公布到公有仓库中。调用方利用对微服务提供的形象接口存在强依赖关系,开发、测试、集成环境都须要严格的治理版本依赖。 Spring Cloud:服务提供方和服务生产方通过 Json 形式交互,因而只须要定义好相干 Json 字段即可,生产方和提供方无接口依赖。通过注解形式来实现服务配置,对于程序有肯定入侵。通过 Json 交互,省略了版本治理的问题,然而具体字段含意须要对立治理,本身 Rest API 形式交互,为跨平台调用奠定了根底。 总体: Dubbo:应用Dubbo构建的微服务架构就像组装电脑,各环节咱们的抉择自由度很高,然而最终后果很有可能因为一条内存品质不行就点不亮了,总是让人不怎么释怀,然而如果你是一名高手,那这些都不是问题; Spring Cloud就像品牌机,在Spring Source的整合下,做了大量的兼容性测试,保障了机器领有更高的稳定性,然而如果要在应用非原装组件外的货色,就须要对其根底有足够的理解。 ...

January 18, 2021 · 4 min · jiezi

关于spring:Spring-Framework-502-Release-版本源码构建

筹备工作下载源码git clone -b 5.0.2 https://github.com/spring-projects/spring-framework.gitcd spring-framework装置gradle下载gradleSpring Framework 5.0.2版本指定gradle版本号是4.3.1,所以我本地装置的gradle版本与指定版本一只。 下载地址:https://gradle.org/next-steps/?version=4.3.1&format=all解压缩gradle将下载的gradle-4.3.1-all解压缩。我解压缩的目录是E盘,解压缩目录能够本人自在指定。 批改环境变量增加GRADLE_HOME=E:/gradle-4.3.1批改Path值,追加;%GRADLE_HOME%\bin 验证执行命令: gradle -v呈现如上界面装置胜利。 构建代码批改配置文件因为现有的依赖源下载速度较慢,所以在build.gradle增加阿里源。 构建执行如下命令: gradlew build呈现以上界面阐明构建胜利。 导入idea在idea中,抉择工具栏File>New>Project From Existing Sources to Import,在对话框中抉择曾经构建的spring版本后,点击OK开始导入。 构建过程问题记录问题一 org.jetbrains.dokka:integration:0.9.15 not found本地打包,上传到maven私服库,maven私服搭建办法能够自行百度。最初将私服库增加到build.gradle。我用的是此办法解决。 下载源码git clone -b 0.9.15 https://github.com/Kotlin/dokka.gitcd dokkagradlew build上传私服从新在spring-framework目录下构建。 问题二 cglib 401 无权限下载jar包在build.gradle 配置文件中增加mavenCentral()或者阿里源maven {url "http://maven.aliyun.com/nexus/content/groups/public"},在从新构建。 问题三 asciidoctor (SystemCallError) Unknown error 123 - FindFirstFile with AsciidoctorJ-PDF on Win10更新asciidoctor版本,从新编译。 参考:(SystemCallError) Unknown error 123 - FindFirstFile with AsciidoctorJ-PDF on Win10 问题四 schema.zip不存在该文件因为windows系统目录是'\'反斜杠,与linux目录不同,所以在执行生成schema.zip失败。将docs.gradle做以下批改,适配windows文件系统。参考:Fix schemaZip Gradle task on MS Windows ...

January 18, 2021 · 1 min · jiezi

关于spring:Mybatis应用分析和最佳实践2

Mybatis利用剖析和最佳实际 以下是一些 MyBatis 的高级用法或者扩大形式,帮忙咱们更好地应用 MyBatis。 为什么要动静SQL 防止因为前端传入的查问参数不同,所以导致写很多的if else,还须要十分留神SQL语句中的and,空格,逗号和本义的单引号,拼接和调试sql十分耗时。 Mybatis的动静SQL就解决了这个问题,其是基于OGNL表达式的。 动静标签if<select id="findActiveBlogWithTitleLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <if test="title != null"> AND title like #{title} </if></select>choose(when,otherwise)<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose></select>trim(where,set)个别用来去掉前缀后者或追 <trim prefix="WHERE" prefixOverrides="AND |OR "> ...</trim>foreach须要遍历汇合的时候动静生成语句 <select id="selectPostIn" resultType="domain.blog.Post"> SELECT * FROM POST P WHERE ID in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach></select>批量操作 咱们在生产的我的项目中会有一些批量操作的场景,比方导入文件批量解决数据的状况(批量新增商户、批量批改商户信息),当数据量十分大,比方超过几万条的时候,在Java 代码中循环发送 SQL 到数据库执行必定是不事实的,因为这个意味着要跟数据库创立几万次会话,即便咱们应用了数据库连接池技术,对于数据库服务器来说也是不堪重负的。 ...

January 17, 2021 · 7 min · jiezi

关于spring:Java-框架领域佼佼者-Spring-初识篇

Spring 简介Spring 是一个轻量级的 Java 开发框架,它是为了解决企业应用开发的复杂性而创立的,长年雄踞于企业开发必选框架之首。Spring 的外围是管制反转(IoC)和面向切面编程(AOP)。简略来说,Spring 是一个分层的 Java EE 一站式轻量级开源框架。 Spring 的次要作用就是为代码 解耦,升高代码间的耦合度。 在一个零碎中,依据性能的不同,代码分为 主业务逻辑 与 零碎级业务逻辑 两类。它们各自具备显明的特点:主业务代码间逻辑联系严密,有具体的业余业务利用场景,复用性绝对较低;零碎级业务绝对性能独立,没有具体的业余业务利用场景,次要是为主业务提供零碎级服务,如日志、平安、事务等,复用性强。 Spring 依据代码的性能特点,将升高耦合度的形式分为了以下两类。 IoC:使得主业务在互相调用过程中,不必再本人保护关系了,即不必再本人创立要应用的对象了,而是由 Spring 容器对立治理,实现主动 注入。AOP:使得零碎级服务失去了最大复用,且不必再手工将零碎级服务混淆到主业务逻辑中了,而是由 Spring 容器对立实现 织入。Spring 体系结构Spring 由 20 多个模块组成,它们能够分为数据拜访/集成(Data Access/Integration)、Web、面向切面编程(AOP, Aspects)、应用服务器设施治理(Instrumentation)、音讯发送(Messaging)、外围容器(Core Container)和测试(Test)。 Spring 的特点非侵入式所谓非侵入式是指,Spring 框架的 API 不会在业务逻辑上呈现,即业务逻辑是 POJO。因为业务逻辑中没有 Spring 的 API,所以业务逻辑能够从 Spring 框架疾速的移植到其余框架, 即与环境无关。 容器Spring 作为一个容器,能够治理对象的生命周期、对象与对象之间的依赖关系。能够通过配置文件,来定义对象,以及设置与其余对象的依赖关系。 管制反转(IoC)管制反转(Inversion of Control),即创立被调用者的实例不是由调用者实现,而是由 Spring 容器实现,并注入调用者。一个对象依赖的其它对象会通过被动的形式传递进来,而不是这个对象本人创立或者查找依赖对象。即,不是对象从容器中查找依赖,而是容器在对象初始化时不等对象申请就被动将依赖传递给它。 面向切面编程(AOP)面向切面编程(Aspect Orient Programming),是一种编程思维,是面向对象编程 OOP 的补充。容许通过拆散利用的业务逻辑与零碎级服务(例如日志和事务管理)进行开发。开发者只有专一实现业务逻辑,并不需要负责其它的零碎级关注点,例如日志或事务反对。 Spring 外围 IoC管制反转的外围性能在于通过将程序代码获取对象调用权,来实现对象的拆卸和治理。管制反转就是对对象控制权的转移,从程序代码自身反转到了内部容器。 以后比拟风行的实现形式有两种: 依赖注入和依赖查找,依赖注入形式利用更为宽泛。 依赖查找(DL):Dependency Lookup,容器提供回调接口和上下文环境给组件,程序代码则须要提供具体的查找形式。依赖注入(DI):Dependency Injection,指程序运行过程中,若须要调用另一个对象帮助时,毋庸在代码中创立被调用者,而是依赖于内部容器,由内部容器创立后传递给程序。依赖注入是目前最优良的解耦形式。依赖注入让 Spring 的 Bean 之间以配置文件的形式组织在一起,而不是以硬编码的形式耦合在一起的。 ...

January 17, 2021 · 1 min · jiezi

关于spring:9-细节见真章Formatter注册中心的设计很讨巧

你好,我是A哥(YourBatman)。 Spring设计了org.springframework.format.Formatter格式化器接口形象,对格式化器进行了大一统,让你只须要关怀对立的API,而无需关注具体实现,相干议题上篇文章 有具体介绍。 Spring内建有不少格式化器实现,同时对它们的治理、调度应用也有专门的组件负责,堪称若明若暗,职责清晰。本文将围绕Formatter注册核心FormatterRegistry开展,为你介绍Spring是如何优雅,奇妙的实现注册治理的。 学习编码是个模拟的过程,绝大多数时候你并不需要发明货色。当然这里指的模拟并非一般的CV模式,而是取精髓为己所用,本文所述奇妙设计便是精髓所在,任君提取。 这几天进入小寒天气,北京迎来最低-20℃,最高-11℃的冰点温度,外出留神保暖本文提纲 版本约定Spring Framework:5.3.xSpring Boot:2.4.x✍注释对Spring的源码浏览、剖析这么多了,会发现对于组件治理大体思维都一样,离不开这几个组件:注册核心(注册员) + 散发器。 一龙生九子,九子各不同。尽管大体思路保持一致,但每个实现在其场景下都有本人的施展空间,值得咱们向而往之。 FormatterRegistry:格式化器注册核心field属性格式化器的注册表(注册核心)。请留神:这里强调了field的存在,先混个眼生,前面你将能有较深领会。 public interface FormatterRegistry extends ConverterRegistry { void addPrinter(Printer<?> printer); void addParser(Parser<?> parser); void addFormatter(Formatter<?> formatter); void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter); void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser); void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);}此接口继承自类型转换器注册核心ConverterRegistry,所以格式化注册核心是转换器注册核心的加强版,是其超集,性能更多更弱小。 对于类型转换器注册核心ConverterRegistry的具体介绍,可翻阅本系列的这篇文章,看完后门清尽管FormatterRegistry提供的增加办法挺多,但其实根本都是在形容同一个事:为指定类型fieldType增加格式化器(printer或parser),绘制成图如下所示: 阐明:最初一个接口办法除外,addFormatterForFieldAnnotation()和格式化注解相干,因为它十分重要,因而放在下文专门撰文解说FormatterRegistry接口的继承树如下: 有了学过ConverterRegistry的教训,这种设计套路很容易被看穿。这两个实现类按层级进行分工: FormattingConversionService:实现所有接口办法DefaultFormattingConversionService:继承自下面的FormattingConversionService,在其根底上注册默认的格式化器事实上,性能分类的确如此。本文重点介绍FormattingConversionService,这个类的设计实现上有很多讨巧之处,只有你来,要你难看。 FormattingConversionService它是FormatterRegistry接口的实现类,实现其所有接口办法。 FormatterRegistry是ConverterRegistry的子接口,而ConverterRegistry接口的所有办法均已由GenericConversionService全副实现了,所以能够通过继承它来间接实现 ConverterRegistry接口办法的实现,因而本类的继承构造是这样子的(请细品这个构造): FormattingConversionService通过继承GenericConversionService搞定“左半边”(父接口ConverterRegistry);只剩“右半边”待处理,也就是FormatterRegistry新增的接口办法。 FormattingConversionService: @Override public void addPrinter(Printer<?> printer) { Class<?> fieldType = getFieldType(printer, Printer.class); addConverter(new PrinterConverter(fieldType, printer, this)); } @Override public void addParser(Parser<?> parser) { Class<?> fieldType = getFieldType(parser, Parser.class); addConverter(new ParserConverter(fieldType, parser, this)); } @Override public void addFormatter(Formatter<?> formatter) { addFormatterForFieldType(getFieldType(formatter), formatter); } @Override public void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter) { addConverter(new PrinterConverter(fieldType, formatter, this)); addConverter(new ParserConverter(fieldType, formatter, this)); } @Override public void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser) { addConverter(new PrinterConverter(fieldType, printer, this)); addConverter(new ParserConverter(fieldType, parser, this)); }从接口的实现能够看到这个“惊天大机密”:所有的格式化器(含Printer、Parser、Formatter)都是被当作Converter注册的,也就是说真正的注册核心只有一个,那就是ConverterRegistry。 ...

January 15, 2021 · 4 min · jiezi

关于spring:详解线程池的作用及Java中如何使用线程池

服务端应用程序(如数据库和 Web 服务器)须要解决来自客户端的高并发、耗时较短的申请工作,所以频繁的创立解决这些申请的所须要的线程就是一个十分耗费资源的操作。惯例的办法是针对一个新的申请创立一个新线程,尽管这种办法仿佛易于实现,但它有重大毛病。为每个申请创立新线程将破费更多的工夫,在创立和销毁线程时破费更多的系统资源。因而同时创立太多线程的 JVM 可能会导致系统内存不足,这就须要限度要创立的线程数,也就是须要应用到线程池。 一、什么是 Java 中的线程池?线程池技术就是线程的重用技术,应用之前创立好的线程来执行当前任务,并提供了针对线程周期开销和资源抵触问题的解决方案。 因为申请达到时线程曾经存在,因而打消了线程创立过程导致的提早,使应用程序失去更快的响应。 Java提供了以Executor接口及其子接口ExecutorService和ThreadPoolExecutor为核心的执行器框架。通过应用Executor,实现线程工作只需实现 Runnable接口并将其交给执行器执行即可。为您封装好线程池,将您的编程工作侧重于具体任务的实现,而不是线程的实现机制。若要应用线程池,咱们首先创立一个 ExecutorService对象,而后向其传递一组工作。ThreadPoolExcutor 类则能够设置线程池初始化和最大的线程容量。 上图示意线程池初始化具备3 个线程,工作队列中有5 个待运行的工作对象。 执行器线程池办法 办法形容newFixedThreadPool(int)创立具备固定的线程数的线程池,int参数示意线程池内线程的数量newCachedThreadPool()创立一个可缓存线程池,该线程池可灵便回收闲暇线程。若无闲暇线程,则新建线程解决工作。newSingleThreadExecutor()创立一个单线程化的线程池,它只会用惟一的工作线程来执行工作newScheduledThreadPool创立一个定长线程池,反对定时及周期性工作执行在固定线程池的状况下,如果执行器以后运行的所有线程,则挂起的工作将放在队列中,并在线程变为闲暇时执行。 二、线程池示例在上面的内容中,咱们将介绍线程池的executor执行器。 创立线程池解决工作要遵循的步骤 创立一个工作对象(实现Runnable接口),用于执行具体的工作逻辑应用Executors创立线程池ExecutorService将待执行的工作对象交给ExecutorService进行工作解决停掉 Executor 线程池//第一步: 创立一个工作对象(实现Runnable接口),用于执行具体的工作逻辑 (Step 1) class Task implements Runnable { private String name; public Task(String s) { name = s; } // 打印工作名称并Sleep 1秒 // 整个解决流程执行5次 public void run() { try{ for (int i = 0; i<=5; i++) { if (i==0) { Date d = new Date(); SimpleDateFormat ft = new SimpleDateFormat("hh:mm:ss"); System.out.println("工作初始化" + name +" = " + ft.format(d)); //第一次执行的时候,打印每一个工作的名称及初始化的工夫 } else{ Date d = new Date(); SimpleDateFormat ft = new SimpleDateFormat("hh:mm:ss"); System.out.println("工作正在执行" + name +" = " + ft.format(d)); // 打印每一个工作解决的执行工夫 } Thread.sleep(1000); } System.out.println("工作执行实现" + name); } catch(InterruptedException e) { e.printStackTrace(); } }}测试用例 ...

January 14, 2021 · 2 min · jiezi

关于spring:Spring-源码学习-14initApplicationEventMulticasteronRefresh

前言上一篇介绍了国际化的应用以及初始化音讯源的源码,接下来接着往下浏览,将进入 initApplicationEventMulticaster 、onRefresh 和 registerListeners 的相干操作逻辑。 这一部分次要是初始化事件播送器以及注册监听器。而 onRefresh 局部则须要子类去实现。 所以本文次要介绍以下几个局部: 什么是 Spring 事件?监听器是如何应用的?什么是 Spring 事件? 这块的介绍在官网 1.15.2. Standard and Custom Events 局部有介绍。 Spring 通过 ApplicationEvent 类和 ApplicationListener 接口提供 ApplicationContext 中的事件处理。如果将实现 ApplicationListener 接口的 bean 部署到上下文中,则每次将 ApplicationEvent 公布到 ApplicationContext 时,都会告诉该 bean。实质上,这是规范的观察者设计模式。演绎下来次要就是三个局部: 事件、事件发布者、事件监听器。 事件:ApplicationEvent,要自定义事件,则须要创立一个类继承 ApplicationEvent。事件发布者:ApplicationEventPublisher 和 ApplicationEventMulticaster,因为 ApplicationContext 实现了 ApplicationEventPublisher,所以事件公布能够间接应用 ApplicationContext。事件监听器:ApplicationListener,通过创立一个实现了 ApplicationListener 并注册为 Spring bean 的类来接管音讯。Spring 也提供了也有一些内置的监听器,能够在官网查看,这里就不做介绍了。 应用监听器简略来说次要分为以下几个局部: 注册事件注册监听器公布事件在接口调用公布事件时,监听器就会做出相应的操作。 1. 注册事件创立 MyApplicationEvent 类并继承 ApplicationEvent public class MyApplicationEvent extends ApplicationEvent { private static final long serialVersionUID = 5366526231219883438L; private String message; /** * Create a new {@code ApplicationEvent}. * * @param source the object on which the event initially occurred or with * which the event is associated (never {@code null}) */ public MyApplicationEvent(Object source, String message) { super(source); this.message = message; } public String getMessage() { return message; }}2. 注册监听器@Componentpublic class MyApplicationListener implements ApplicationListener<MyApplicationEvent> { @Override public void onApplicationEvent(MyApplicationEvent event) { System.out.println("MyApplicationListener 收到音讯: " + event.getMessage()); }}当然这里也能够应用注解 @EventListener 的形式来应用。 ...

January 13, 2021 · 2 min · jiezi

关于spring:8-格式化器大一统-Spring的Formatter抽象

你好,我是A哥(YourBatman)。 上篇文章 介绍了java.text.Format格式化体系,作为JDK 1.0就提供的格式化器,除了设计上存在肯定缺点,过于底层无奈标准化对使用者不够敌对,这都是对格式化器提出的更高要求。Spring作为Java开发的规范基建,本文就来看看它做了哪些补充。 本文提纲 版本约定Spring Framework:5.3.xSpring Boot:2.4.x✍注释在利用中(特地是web利用),咱们常常须要将前端/Client端传入的字符串转换成指定格局/指定数据类型,同样的服务端也心愿能把指定类型的数据依照指定格局 返回给前端/Client端,这种状况下Converter曾经无奈满足咱们的需要了。为此,Spring提供了格式化模块专门用于解决此类问题。 首先能够从宏观上先看看spring-context对format模块的目录构造安顿: public interface Formatter<T> extends Printer<T>, Parser<T> {}能够看到,该接口自身没有任何办法,而是聚合了另外两个接口Printer和Parser。 Printer&Parser这两个接口是相同性能的接口。 Printer:格式化显示(输入)接口。将T类型转为String模式,Locale用于管制国际化@FunctionalInterfacepublic interface Printer<T> { // 将Object写为String类型 String print(T object, Locale locale);}Parser:解析接口。将String类型转到T类型,Locale用于管制国际化。@FunctionalInterfacepublic interface Parser<T> { T parse(String text, Locale locale) throws ParseException;}Formatter格式化器接口,它的继承树如下: 由图可见,格式化动作只需关怀到两个畛域: 工夫日期畛域数字畛域(其中包含货币)工夫日期格式化Spring框架从4.0开始反对Java 8,针对JSR 310日期工夫类型的格式化专门有个包org.springframework.format.datetime.standard: 值得一提的是:在Java 8进去之前,Joda-Time是Java日期工夫解决最好的解决方案,应用宽泛,甚至失去了Spring内置的反对。当初Java 8未然成为支流,JSR 310日期工夫API 齐全能够 代替Joda-Time(JSR 310的贡献者其实就是Joda-Time的作者们)。因而joda库也逐步辞别历史舞台,后续代码中不再举荐应用,本文也会选择性疏忽。 除了Joda-Time外,Java中对工夫日期的格式化还需分为这两大阵营来解决: Date类型尽管曾经2020年了(Java 8于2014年公布),但谈到工夫日期那必然还是得有java.util.Date,毕竟积重难返。所以呢,Spring提供了DateFormatter用于反对它的格式化。 因为Date早就存在,所以DateFormatter是随同着Formatter的呈现而呈现,@since 3.0// @since 3.0public class DateFormatter implements Formatter<Date> { private static final TimeZone UTC = TimeZone.getTimeZone("UTC"); private static final Map<ISO, String> ISO_PATTERNS; static { Map<ISO, String> formats = new EnumMap<>(ISO.class); formats.put(ISO.DATE, "yyyy-MM-dd"); formats.put(ISO.TIME, "HH:mm:ss.SSSXXX"); formats.put(ISO.DATE_TIME, "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); ISO_PATTERNS = Collections.unmodifiableMap(formats); }}默认应用的TimeZone是UTC标准时区,ISO_PATTERNS代表ISO规范模版,这和@DateTimeFormat注解的iso属性是一一对应的。也就是说如果你不想指定pattern,能够疾速通过指定ISO来实现。 ...

January 11, 2021 · 3 min · jiezi

关于spring:spring源码总结笔记深入浅出从入门讲到源码建议先收藏再看

本篇次要内容Spring 概述(根本状况)核⼼思维 IoC 和 AOP⼿写实现 IoC 和 AOP(⾃定义spring框架)Spring IoC ⾼级应⽤基础知识⾼级个性Spring IoC 源码深度分析设计⾮常优雅设计模式留神:准则、⽅法和技巧Spring AOP ⾼级应⽤申明式事务管制Spring AOP 源码深度分析必要的笔记、必要的图、通俗易懂的语⾔化解常识难点Spring 概述Spring 是分层的 full-stack(全栈) 轻量级开源框架,以 IoC 和 AOP 为内核,提供了展示层 SpringMVC 和业务层事务管理等泛滥的企业级应⽤技术,还能整合开源世界泛滥驰名的第三⽅框架和类库,曾经成为使⽤最多的 Java EE 企业应⽤开源框架。 Spring 倒退历程1997年 IBM 提出了EJB的思维;1998年,SUN 制订开发标准规范EJB1.0;1999年,EJB 1.1公布;2001年,EJB 2.0公布;2003年,EJB 2.1公布;2006年,EJB 3.0公布;2017 年 9 ⽉份公布了 Spring 的最新版本 Spring 5.0 通⽤版(GA) Spring 的劣势⽅便解耦,简化开发AOP编程的⽀持申明式事务的⽀持⽅便程序的测试⽅便集成各种优良框架升高JavaEE API的使⽤难度源码是经典的 Java 学习范例 Spring 的核⼼构造Spring是⼀个分层⾮常清晰并且依赖关系、职责定位⾮常明确的轻量级框架,次要包含⼏个⼤模块:数据处理模块、Web模块、AOP(Aspect Oriented Programming)/Aspects模块、Core Container模块和 Test 模块,如下图所示,Spring依附这些根本模块,实现了⼀个令⼈愉悦的交融了现有解决⽅案的零侵⼊的轻量级框架。 Spring核⼼容器(Core Container) 容器是Spring框架最核⼼的局部,它治理着Spring应⽤中bean的创立、配置和治理。在该模块中,包含了Spring bean⼯⼚,它为Spring提供了DI的性能。基于bean⼯⼚,咱们还会发现有多种Spring应⽤高低⽂的实现。所有的Spring模块都构建于核⼼容器之上。⾯向切⾯编程(AOP)/Aspects Spring对⾯向切⾯编程提供了丰盛的⽀持。这个模块是Spring应⽤零碎中开发切⾯的根底,与DI⼀样,AOP能够帮忙应⽤对象解耦。数据拜访与集成(Data Access/Integration)Spring的JDBC和DAO模块封装了⼤量样板代码,这样能够使得数据库代码变得简洁,也能够更专一于咱们的业务,还能够防止数据库资源开释失败⽽引起的问题。 另外,Spring AOP为数据拜访提供了事务管理服务,同时Spring还对ORM进⾏了集成,如Hibernate、MyBatis等。该模块由JDBC、Transactions、ORM、OXM 和 JMS 等模块组成。Web 该模块提供了SpringMVC框架给Web应⽤,还提供了多种构建和其它应⽤交互的近程调⽤⽅案。 SpringMVC框架在Web层晋升了应⽤的松耦合⽔平。Test 为了使得开发者可能很⽅便的进⾏测试,Spring提供了测试模块以至⼒于Spring应⽤的测试。 通过该模块,Spring为使⽤Servlet、JNDI等编写单元测试提供了⼀系列的mock对象实现。什么是IoC?IoC Inversion of Control (管制反转/反转管制),留神它是⼀个技术思维,不是⼀个技术实现形容的事件:Java开发畛域对象的创立,治理的问题传统开发⽅式:⽐如类A依赖于类B,往往会在类A中new⼀个B的对象IoC思维下开发⽅式:咱们不⽤⾃⼰去new对象了,⽽是由IoC容器(Spring框架)去帮忙咱们实例化对象并且治理它,咱们须要使⽤哪个对象,去问IoC容器要即可咱们丢失了⼀个权力(创立、治理对象的权力),失去了⼀个福利(不⽤思考对象的创立、治理等⼀系列事件)为什么叫做管制反转?管制:指的是对象创立(实例化、治理)的权力反转:控制权交给外部环境了(spring框架、IoC容器) ...

January 6, 2021 · 1 min · jiezi

关于spring:设计模式组合模式

组合模式定义也称为 整体局部模式也叫合成模式主旨是通过单个对象(叶子节点)和组合对象(树枝节点)用雷同的接口进行示意 作用 让客户端对单个对象和组合对象保持一致的形式解决属于结构型模式组合和聚合的区别如果是心在一起就是一个团队,人在一起只是团伙 头和身材就是组合 学生和老师就是聚合 没有互相的生命周期生存中的案例公司组织架构电脑的文件治理实用场景如果咱们心愿客户端代码以雷同形式解决简略和简单元素,能够应用该模式对象档次具备整体和局部,呈树形构造 树形菜单操作系统目录构造公司组织架构通用构造 通明写法public abstract class Component { protected String name; public Component(String name) { this.name = name; } public abstract String operation(); public boolean addChild(Component component) { throw new UnsupportedOperationException("addChild not supported!"); } public boolean removeChild(Component component) { throw new UnsupportedOperationException("removeChild not supported!"); } public Component getChild(int index) { throw new UnsupportedOperationException("getChild not supported!"); }}在形象办法中属于根的办法都抛出异样,而后具体的根重写这个办法 public class Composite extends Component { private List<Component> mComponents; public Composite(String name) { super(name); this.mComponents = new ArrayList<Component>(); } @Override public String operation() { StringBuilder builder = new StringBuilder(this.name); for (Component component : this.mComponents) { builder.append("\n"); builder.append(component.operation()); } return builder.toString(); } @Override public boolean addChild(Component component) { return this.mComponents.add(component); } @Override public boolean removeChild(Component component) { return this.mComponents.remove(component); } @Override public Component getChild(int index) { return this.mComponents.get(index); }}子节点不须要重写这个办法 ...

January 6, 2021 · 4 min · jiezi

关于spring:设计模式享元模式

享元模式把现有的资源重复利用起来 Java中常见的OOm有以下两种 内存透露 有意识的代码缺点,导致内存透露,JVM不能取得间断的内存空 间。对象太多 代码写得很烂,产生的对象太多,内存被耗尽。现没有内存透露,那只有一种起因 代码太差把内存耗尽。有的对象咱们用完能够复用的,不必等到oom定义又称为轻量级模式,对象池的一种实现相似于线程池,线程池能够防止不停地创立和销毁多个对象,耗费性能提供了缩小对象数量而改善利用所需的对象构造的形式共享细粒度对象,将多个对同一对象的拜访集中起来结构型模式 生存中的例子中介 房源共享的机制全国社保联网公共类图 形象的享元角色Iflyweight它简略地说就是一个产品的抽象类,同时定义出对象的内部状态和 外部状态的接口或实现。 具体的享元角色ConcreteFlyweight 具体的一个产品类,实现形象角色定义的业务。该角色中须要留神 的是外部状态解决应该与环境无关,不应该呈现一个操作扭转了外部状 态,同时批改了内部状态,这是相对不容许的。 public class ConcreteFlyweight implements IFlyweight { private String intrinsicState; public ConcreteFlyweight(String intrinsicState) { this.intrinsicState = intrinsicState; } public void operation(String extrinsicState) { System.out.println("Object address: " + System.identityHashCode(this)); System.out.println("IntrinsicState: " + this.intrinsicState); System.out.println("ExtrinsicState: " + extrinsicState); }}FlyweightFactory享元工厂职责非常简单,就是结构一个池容器,同时提供从池中取得对象的办法。享元模式的目标在于使用共享技术,使得一些细粒度的对象能够共 享,咱们的设计的确也应该这样,多应用细粒度的对象,便于重用或重构。public class FlyweightFactory { private static Map<String, IFlyweight> pool = new HashMap<String, IFlyweight>(); // 因为外部状态具备不变性,因而作为缓存的键 public static IFlyweight getFlyweight(String intrinsicState) { if (!pool.containsKey(intrinsicState)) { IFlyweight flyweight = new ConcreteFlyweight(intrinsicState); pool.put(intrinsicState, flyweight); } return pool.get(intrinsicState); }}状态外部状态外部状态是对象可共享进去的信息,存储在享元对象外部不会随环境扭转而扭转,它们能够作为 一个对象的动静附加信息,不用间接贮存在具体某个对象中,属于能够共享的局部。内部状态对象能够被依赖的标记,不可共享的状态 ...

January 6, 2021 · 3 min · jiezi

关于spring:设计模式适配器模式

适配器模式智者千虑必有一失,愚者千虑必有一得在咱们做设计的时候总是会呈现一些意外,适配器模式就是帮咱们来补救这些意外的 定义变压模式,也叫包装模式,然而包装模式可不止一个。装璜者也是。 性能是将 一个类的接口编程客户端所冀望的另一个接口,从而使本来接口不匹配而无奈在一起工作的两个类可能一起工作 属于结构型设计模式例子Switch的港版电压在国内是不实用的,须要两脚转三角插头 有点亡羊补牢的感觉 通用写法类适配器 Target指标角色 该角色定义把其余类转换为何种接口,也就是咱们的冀望接口,例 子中的IUserInfo接口就是指标角色。 public interface Target { int request();} 指标角色是一个曾经在正式运行的角色,你不可能去批改角色中的办法,你能做的就是如何去实现接口中的办法,而且通常状况下,指标角色是一个接口或者是抽象类,个别不会是实现类。 Adaptee源角色 你想把谁转换成指标角色,这个“谁”就是源角色,它是曾经存在的、运行良好的类或对象,通过适配器角色的包装,它会成为一个簇新、靓丽的角色。 public class Adaptee{ public int specificRequest() { return 220; }}Adapter适配器角色 适配器模式的外围角色,其余两个角色都是曾经存在的角色,而适配器角色是须要新建设的,它的职责非常简单:把源角色转换为指标角色,怎么转换? 罕用的三种形式1.通过继承源角色 public class Adapter extends Adaptee implements Target { public int request() { return super.specificRequest() / 10; }}2.通过组合源角色 public class Adapter implements Target { private Adaptee adaptee; public Adapter(Adaptee adaptee){ this.adaptee = adaptee; } public int request() { return adaptee.specificRequest() / 10; }}3.接口适配,实现交给客户端public abstract class Adapter implements Target { protected Adaptee adaptee; public Adapter(Adaptee adaptee){ this.adaptee = adaptee; } public int request1() { return 0; } public int request2() { return 0; } public int request3() { return 0; } public int request4() { return 0; }}public class Test { public static void main(String[] args) { Target adapter = new Adapter(new Adaptee()) { @Override public int request1() { return adaptee.specificRequest() / 10; } }; int result = adapter.request1(); System.out.println(result); }}对象适配器合乎开闭准则 ...

January 6, 2021 · 5 min · jiezi

关于spring:设计模式桥接模式

桥接模式定义形象局部和具体实现局部拆散 让他们能够独立的变动通过组合的形式建设两个类之间的关系而不是继承结构型模式生存中的场景桥连贯了两个维度的货色 网络连接桥接模式 虚构网卡和物理网卡连在一起 通用的写法 外面有几个要害角色 Abstraction——抽象化角色 它的主要职责是定义出该角色的行为,同时保留一个对实现化角色的援用,该角色个别是抽象类。 Implementor——实现化角色它是接口或者抽象类,定义角色必须的行为和属性。 RefinedAbstraction——修改抽象化角色它援用实现化角色对抽象化角色进行修改。 ConcreteImplementor——具体实现化角色它实现接口或抽象类定义的办法和属性。 public class RefinedAbstraction extends Abstraction { public RefinedAbstraction(IImplementor implementor) { super(implementor); } @Override public void operation() { super.operation(); System.out.println("refined operation"); }}public class Test { public static void main(String[] args) { //定义一个实现化角色 Implementor imp = new ConcreteImplementor1(); //定义一个抽象化角色 Abstraction abs = new RefinedAbstraction(imp); //执行行文 abs.request(); }}}测试用例public class Test { public static void main(String[] args) { // 来一个实现化角色 IImplementor imp = new ConcreteImplementorA(); // 来一个抽象化角色,聚合实现 Abstraction abs = new RefinedAbstraction(imp); // 执行操作 abs.operation(); }} 各位可能要问,为什么要减少一个构造函数?答案是为了揭示子类,你必须做这项工作,指定实现者,特地是曾经明确了实现者,则尽量清晰明确地定义进去。 ...

January 6, 2021 · 3 min · jiezi

关于spring:通过Spring-Boot构建一个购物车微服务

在Spring MVC中,您能够创立REST应用程序。 您创立一个应用@RestController正文的控制器类。 而后定义应用@RequestMapping正文的处理程序办法。 您还能够应用@PathVariable正文的URI模板参数。 此处显示的代码示例公开了REST端点/ users / {user}。 {user}的代码是用于自定义REST申请的门路变量。 Spring Boot提供了一个Jackson ObjectMapper的主动配置,用于JSON无效负载和POJO对象之间的主动编组。 Spring在构建REST资源时,通常应用@RestController和@RequestMapping来定义。而JavaEE定义的时候,通常应用JAX-RS实现@Path。当然,在Spring中也能够应用JAX-RS。 作为开发的另一种抉择,您能够应用JAX-RS。 默认的Spring Boot JAX-RS实现是Jersey,它是Glassfish Jax-RS实现。 您能够应用spring-boot-starter-jersey Spring Boot启动器。 Spring Boot提供Jersey servlet和Jackson数据绑定的主动配置。 您能够应用规范的JAX-RS正文构建REST端点,例如@ javax.ws.rs.Path,@ javax.ws.rs.Produces和javax.ws.rs.GET。此代码示例演示如何应用JAX-RS在Spring中构建REST资源。 REST资源类须要在Jersey上下文中注册。这里显示了一个例子。 Spring Boot包含对嵌入式Tomcat,Jetty和Undertow服务器的反对。 默认状况下,Spring Boot启动程序(特地是spring-boot-starter-web)应用Tomcat作为嵌入式容器。要应用备用服务器,请排除Tomcat依赖项并蕴含所需的依赖项。 这里的代码片段显示了如何排除Tomcat并蕴含Undertow服务器所需的依赖关系。 Spring Framework为应用SQL数据库提供了宽泛的反对。 您能够应用JdbcTemplate间接进行JDBC拜访。 您还能够将JPA对象关系映射与Hibernate一起应用。 Spring Data为反对SQL,NoSQL,MapReduce框架和基于云的数据服务的数据拜访提供了基于Spring的编程模型。 Spring Boot提供以下启动器:spring-boot-starter-jdbc和spring-boot-starter-data-jpa。 Spring Boot的一个很好的性能是内存数据库的主动配置,非常适合测试。 此外,Spring Boot还提供具备内部配置属性的数据源的主动配置。Spring Framework还提供实体类扫描,以及Spring Data Repository类的主动注册。 Spring JPA存储库是封装数据拜访的接口。 JPA查问是从办法名称主动创立的。这里显示了一个例子。 Spring Boot配置能够内部化,以便雷同的利用程序代码能够在不同的环境中工作。 您能够应用属性文件,YAML文件,环境变量和命令行参数来内部化配置。 能够应用@Value正文将属性值间接注入bean,通过Spring的Environment形象拜访,或通过@ConfigurationProperties绑定到结构化对象。 Spring Boot应用一个有序的序列来指定属性,以便容许正当地笼罩值。程序如下: @TestPropertySource 命令行参数 Java零碎属性 OS环境变量 打包JAR之外的特定于配置文件的应用程序属性 打包的JAR中的特定于配置文件的应用程序属性 默认属性 ...

January 5, 2021 · 7 min · jiezi

关于spring:Spring-源码学习-13initMessageSource

前言在浏览完 registerBeanPostProcessors 源码之后, 下一步就进入到 initMessageSource,这一步次要作用是初始化国际化文件。 仍然如之前所示,先通过官网理解到国际化的用法,而后再对源码进行钻研。 MessageSource 国际化 如官网1.15.1. Internationalization using MessageSource所示,次要作用就是应用国际化,定制不同的音讯。 须要留神的是 MessageSource 定义的 Bean 名字必须为 messageSource, 而如果找不到则会默认注册 DelegatingMessageSource 作为 messageSource 的 Bean。 应用1. 创立国际化文件 2. 申明 MessageSource在 JavaConfig 中 申明 MessageSource , 记得名字肯定要叫做 messageSource ! @Configuration@ComponentScan("com.liuzhihang")public class JavaConfig { @Bean(name = "messageSource") public MessageSource getMessageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setDefaultEncoding("UTF-8"); messageSource.addBasenames("message", "message_en"); return messageSource; }}3. 测试后果public class AnnotationConfigApplicationTest { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(JavaConfig.class); context.refresh(); MessageSource messageSource = context.getBean(MessageSource.class); String zhMessage = messageSource.getMessage("user.name", null, null, Locale.CHINA); String enMessage = messageSource.getMessage("user.name", null, null, Locale.ENGLISH); System.out.println("zhMessage = " + zhMessage); System.out.println("enMessage = " + enMessage); }}如上所示,执行之后输入后果如下: ...

January 4, 2021 · 2 min · jiezi

关于spring:设计模式装饰器模式

装璜器模式定义装璜器模式也叫包装模式 在不扭转原有对象的根底上,把性能附加到对象上,提供了比继承更有弹性的代替计划可能扩大原有对象的性能属于结构型模式生存中的例子买煎饼 咱们煎饼能够加鸡蛋,加香肠蛋糕 能够加豆沙加各种各样的货色通用构造 个别都是在构造方法当中来传入对应须要包装的对象 Component 是一个接口或者是抽象类,就是定义咱们最外围的对象,也就是最原始的对象。ConcreteComponent 具体构件 ConcreteComponent是最外围、最原始、最根本的接口或抽象类的实现,你要装璜的就是它。Decorator装璜角色 个别是一个抽象类,做什么用呢? 实现接口或者形象办法,它外面 可不肯定有形象的办法呀,在它的属性里必然有一个private变量指向 Component形象构件。具体装璜角色 ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装璜类,要把你最外围的、最原始的、最根本的货色装璜成其余货色。案例煎饼煎饼须要加香肠,鸡蛋,等 public class SauageDecorator extends BattercakeDecorator{ public SauageDecorator(Battercake battercake) { super(battercake); } protected String getMsg(){ return super.getMsg() + "1根香肠";} public int getPrice(){ return super.getPrice() + 2;}}public class Test { public static void main(String[] args) { Battercake battercake; battercake = new BaseBattercake(); battercake = new EggDecorator(battercake); battercake = new EggDecorator(battercake); battercake = new SauageDecorator(battercake); System.out.println(battercake.getMsg() + ",总价" + battercake.getPrice()); }}能够利用装璜器模式疾速的去抉择须要减少的货色包装日志 ...

January 4, 2021 · 3 min · jiezi

关于spring:设计模式门面模式

门面模式参考资料图解设计模式 大话设计模式 设计模式之禅 github我见过最好的设计模式 http://c.biancheng.net/view/1... 定义也称为外观模式 外观模式是一种结构型设计模式, 能为程序库、 框架或其余简单类提供一个简略的接口。 让子系统更加容易应用,属于结构型模式例子App订单接口 后盾提供一个聚合接口 在外部别离调用了订单,物流,用户零碎可能节俭前端的申请实用场景子系统越来越简单,减少门面模式来提供简略接口构建多层系统结构,利用门面对象作为每层的入口,简化层间调用生存中的例子前台接待员 用来做向导包工头 通过包工头来找粉刷匠,找泥工等通用写法 物流零碎案例 门面业务帮咱们聚合扣款,监测,发货的性能,客户端只须要找门面就行了 源码中的案例Spring的JdbcUtilspublic static boolean supportsBatchUpdates(Connection con) { try { DatabaseMetaData dbmd = con.getMetaData(); if (dbmd != null) { if (dbmd.supportsBatchUpdates()) { logger.debug("JDBC driver supports batch updates"); return true; } else { logger.debug("JDBC driver does not support batch updates"); } } } catch (SQLException ex) { logger.debug("JDBC driver 'supportsBatchUpdates' method threw exception", ex); } return false;}帮咱们包装了对连贯的操作,这样客户端只须要应用JdbcUtils就行了 ...

January 4, 2021 · 1 min · jiezi

关于spring:设计模式代理模式

代理模式参考资料图解设计模式 大话设计模式 设计模式之禅 github我见过最好的设计模式 http://c.biancheng.net/view/1... 定义代理模式为其余对象提供一种代理,用来管制对于这个对象的拜访在客户类和指标类之间起到中介作用结构型设计模式类图 生存中的代理模式房产中介快递小哥黄牛党应用场景爱护指标对象加强指标对象的性能案例动态代理显示申明被代理的对象 public class ZhangLaosan implements IPerson { private IPerson zhangsan; public ZhangLaosan(IPerson person) { this.zhangsan = person; } public void findLove() { System.out.println("张老三开始物色"); person.findLove(); System.out.println("开始来往"); }}编译期就分明了 有点相似于装璜者模式动静代理JDKProxy#newProxyInstanceInvocationHandler public class JdkMeipo implements InvocationHandler { private IPerson target; public IPerson getInstance(IPerson target){ this.target = target; Class<?> clazz = target.getClass(); return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(this.target,args); after(); return result; } private void after() { System.out.println("双方同意,开始来往"); } private void before() { System.out.println("我是媒婆,曾经收集到你的需要,开始物色"); }}问题 ...

January 4, 2021 · 11 min · jiezi

关于spring:设计模式建造者模式

建造者模式也叫生成器模式,他是一个创立型模式通用类图 Product产品类 通常是实现了模板办法模式,也就是有模板办法和根本办法. public class Product { public void doSomething(){ //独立业务解决 }}Builder形象建造者 标准产品的组建,个别是由子类实现。例子中的CarBuilder就属于 形象建造者。 public abstract class Builder { //设置产品的不同局部,以取得不同的产品 public abstract void setPart(); //建造产品 public abstract Product buildProduct();}ConcreteBuilder具体建造者 实现抽象类定义的所有办法,并且返回一个组建好的对象。例子中 的BenzBuilder和BMWBuilder就属于具体建造者。 public class ConcreteProduct extends Builder { private Product product = new Product(); //设置产品整机 public void setPart(){ /* * 产品类内的逻辑解决 */ } //组建一个产品 public Product buildProduct() { return product; }}Director导演类 负责安顿已有模块的程序,而后通知Builder开始建造,在下面的例 子中就是咱们的老大,××公司找到老大,说我要这个或那个类型的车辆 模型,而后老大就把命令传递给我,我和我的团队就开始拼命地建造, 于是一个我的项目建设结束了。 public class Director { private Builder builder = new ConcreteProduct(); //构建不同的产品 public Product getAProduct(){ builder.setPart(); /* * 设置不同的整机,产生不同的产品 */ return builder.buildProduct(); }}定义将一个简单对象的构建和他的示意拆散,使得同样的构建过程能够创立不同的示意。 ...

January 3, 2021 · 2 min · jiezi

关于spring:设计模式原型模式

原型模式 原型实例指定创建对象的品种,并且通过拷贝这些原型创立新的对象,并且通过拷贝这些原型创立新的对象 调用者不须要晓得任何创立细节,不调用构造函数 其属于一种创立型模式 通用类图 长处性能好 是在内存二进制流的拷贝,比间接new一个对象性能好,而且循环体内产生大量对象时,能够更好地提现长处回避构造函数的束缚 间接在内存中拷贝构造函数是不会执行的实用场景类初始化耗费资源较多new 产生的一个对象须要十分繁琐的过程(数据筹备、拜访权限等) 省略了本人去get,set的过程构造函数比较复杂时循环体中产生大量对象时应用通过一个特定的办法来拷贝对应的对象本人提供接口并且实现应用JDK的clone办法浅克隆测试@Datapublic class ConcretePrototype implements Cloneable { private int age; private String name; private List<String> hobbies; @Override public ConcretePrototype clone() { try { return (ConcretePrototype)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } }}public static void main(String[] args) { ConcretePrototype prototype = new ConcretePrototype(); prototype.setAge(18); prototype.setName("zzy"); List<String> hobbies = new ArrayList<String>(); hobbies.add("music"); hobbies.add("article"); prototype.setHobbies(hobbies); //拷贝原型对象 ConcretePrototype cloneType = prototype.clone(); cloneType.getHobbies().add("program"); System.out.println("原型对象:" + prototype); System.out.println("克隆对象:" + cloneType); System.out.println(prototype == cloneType); System.out.println("原型对象的喜好:" + prototype.getHobbies()); System.out.println("克隆对象的喜好:" + cloneType.getHobbies()); System.out.println(prototype.getHobbies() == cloneType.getHobbies());}原型对象:ConcretePrototype{age=18, name='zzy', hobbies=[music, article, program]}克隆对象:ConcretePrototype{age=18, name='zzy', hobbies=[music, article, program]}false原型对象的喜好:[music, article, program]克隆对象的喜好:[music, article, program]true通过后果能够看到通过clone拷贝进去对象的汇合类型的内存地址没有扭转 ...

January 3, 2021 · 2 min · jiezi

关于spring:Spring-源码学习-12registerBeanPostProcessors

前言后面通过 invokeBeanFactoryPostProcessors 这一步理解到了什么是 BeanFactoryPostProcessor ,以及 BeanFactoryPostProcessor 的应用及作用,并通过 invokeBeanFactoryPostProcessors 这一步源码,对 BeanFactoryPostProcessor 的加载流程有了进一步理解。 当初就一起进入下一个环节: registerBeanPostProcessors(beanFactory); 这一步次要的作用是加载 BeanPostProcessor,从名字也能够看出,只是加载,并没有执行。 不过,在进入源码之前,仍然是联合官网,先理解以下几个问题: 什么是 BeanPostProcessor?BeanPostProcessor 是如何应用的?BeanPostProcessor 有什么用?什么是 BeanPostProcessor ? 如截图所示,在官网 1.8.1 Customizing Beans by Using a BeanPostProcessor 中介绍, BeanPostProcessor 接口定义回调办法,能够实现这些办法,从而在 Bean 实例化期间批改 Bean 的属性。 BeanPostProcessor 是如何应用的?@Componentpublic class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof UserComponent) { System.out.println("BeanPostProcessor 开始执行 初始化前..." + beanName); UserComponent userComponent = (UserComponent) bean; userComponent.setUserName("liuzhihang-postProcessBeforeInitialization"); return userComponent; } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof UserComponent) { System.out.println("BeanPostProcessor 开始执行 初始化后..." + beanName); UserComponent userComponent = (UserComponent) bean; userComponent.setUserName("liuzhihang-postProcessAfterInitialization"); return userComponent; } return bean; }}如代码所示,只须要申明一个本人的 MyBeanPostProcessor 来实现 BeanPostProcessor 并重写其办法: ...

January 2, 2021 · 3 min · jiezi

关于spring:15张图带你彻底弄明白spring循环依赖再也不用怕了

1.由共事抛的一个问题开始最近项目组的一个共事遇到了一个问题,问我的意见,一下子引起的我的趣味,因为这个问题我也是第一次遇到。平时自认为对spring循环依赖问题还是比拟理解的,直到遇到这个和前面的几个问题后,从新刷新了我的意识。 咱们先看看过后出问题的代码片段: @Servicepublicclass TestService1 { @Autowired private TestService2 testService2; @Async public void test1() { }}@Servicepublicclass TestService2 { @Autowired private TestService1 testService1; public void test2() { }}这两段代码中定义了两个Service类:TestService1和TestService2,在TestService1中注入了TestService2的实例,同时在TestService2中注入了TestService1的实例,这里形成了循环依赖。 只不过,这不是一般的循环依赖,因为TestService1的test1办法上加了一个@Async注解。 大家猜猜程序启动后运行后果会怎么? org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testService1': Bean with name 'testService1' has been injected into other beans [testService2] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.报错了。。。起因是呈现了循环依赖。 ...

December 31, 2020 · 3 min · jiezi

关于spring:设计模式工厂模式

参考资料图解设计模式 大话设计模式 设计模式之禅 github我见过最好的设计模式 设计准则回顾设计准则解释开闭准则对扩大凋谢,对批改敞开依赖倒置准则通过形象让哥哥模块互不影响,松耦合,面向接口编程繁多职责准则一个接口,类,办法只做一件事接口隔离准则保障纯洁性,不应该依赖于本人不须要的接口,有时候没方法能够通过适配器来解决迪米特法令起码晓得准则,一个类对其所依赖的类晓得的越少越好里氏替换准则子类能够扩大父类的性能然而不能扭转父类原有的性能合成复用准则尽量应用聚合和组合,少用继承巧用Json工具类来做json转化JDBC这一块是固定的,能够应用模板办法工厂模式简略工厂案例日历类比如说日历类中获取对应日历的办法,通过传入参数来进行对应的对象的生成 日志又或者说 logfactory中的log public class CourseFactory { // public ICourse create(String name){ // if("java".equals(name)){ // return new JavaCourse(); // }else if("python".equals(name)){ // return new PythonCourse(); // }else { // return null; // } // } // public ICourse create(String className){ // try { // if (!(null == className || "".equals(className))) { // return (ICourse) Class.forName(className).newInstance(); // } // // }catch (Exception e){ // e.printStackTrace(); // } // return null; // } //泛型束缚 public ICourse create(Class<? extends ICourse> clazz){ try { if (null != clazz) { return clazz.newInstance(); } }catch (Exception e){ e.printStackTrace(); } return null; }}Mybatis SqlsesssionFactory创立Executororg.apache.ibatis.session.Configuration#newExecutor(Transaction, ExecutorType) ...

December 30, 2020 · 3 min · jiezi

关于spring:设计模式七大软件设计原则

设计模式参考资料图解设计模式 大话设计模式 设计模式之禅 github我见过最好的设计模式 http://c.biancheng.net/view/1... 根本准则开闭准则在设计的时候尽可能的思考,需要的变动,新需要来了尽可能少的改变代码,拥抱变动定义:指的是软件中一个实体,如类、模块和函数应该对扩大凋谢,对批改敞开。 面向形象编程开闭是对扩大和批改的束缚 强调:用形象构建框架,用实现扩大细节。 长处:进步软件系统的可复用性及可维护性 面向对象最根底的设计准则领导咱们构建稳固的零碎 代码不是一次性的,更多工夫在保护大多是代码版本的更新迭代咱们最好对已有的源码很少批改 个别都是新增扩大,类来批改可能升高危险对于变动逻辑变动 比如说算法从a*b*c变动成a*b+c其实是能够间接批改的,前提是所有依赖或者关联类都依照雷同的逻辑来解决子模块变动 子模块变动可能间接引起整体也就是高层的变动可见视图变动 如果说需要上多了一些原有逻辑不存在的,可能这种变动是恐怖的,须要咱们灵便的设计例子弹性工作工夫,工夫是固定的,上下班是可变的顶层接口 接口是标准,形象是实现 通过继承来解决 价格的含意曾经变动了,所以不可能子类间接继承getPrice(),因为以后曾经是折扣价格了,可能须要价格和折扣价格 问题为什么要遵循开闭准则,从软件工程角度怎么了解这点。 开闭准则对扩大凋谢对批改敞开,程序和需要肯定是一直批改的,咱们须要把共性和根底的货色抽出来,把经常批改的货色让他可能扩大进来,这样咱们程序前期保护的危险就会小很多为什么重要对于测试的影响 一处变更可能导致原有测试用例都不论用了进步复用性 高内聚,低耦合进步可维护性面向对象开发的要求如何应用形象束缚参数抽到配置中 例如sql的连贯信息国际化信息指定我的项目章程 约定我的项目中Bean都是用主动注入,通过注解来做拆卸团队成员达成统一公共类走对立的入口,大家都是用对立的公共类封装变动提前预知变动依赖倒置准则定义高层模块不应该依赖低层模块,二者都应该依赖其形象。形象不应该依赖细节,细节应该依赖形象。 说白了就是针对接口编程,不要针对实现编程 什么是倒置不可分割的原子逻辑是底层模块,原子逻辑在组装就是高层模块形象就是接口或者抽象类 都不能被实例化的细节 细节就是具体实现类长处通过依赖倒置,可能缩小类和类之间的耦合性,进步零碎的稳定性,进步代码的可读性和稳定性。升高批改程序的危险例子 public class DipTest { public static void main(String[] args) { //===== V1 ======== // Tom tom = new Tom(); // tom.studyJavaCourse(); // tom.studyPythonCourse(); // tom.studyAICourse(); //===== V2 ======== // Tom tom = new Tom(); // tom.study(new JavaCourse()); // tom.study(new PythonCourse()); //===== V3 ======== // Tom tom = new Tom(new JavaCourse()); // tom.study(); //===== V4 ======== Tom tom = new Tom(); tom.setiCourse(new JavaCourse()); tom.study(); }}重点先顶层后细节自顶向下来思考全局不要一开始沉浸于细节高层不依赖于低层,关系应该用形象来保护针对接口编程不要针对实现编程以形象为基准比以细节为基准搭建起来的架构要稳固得多,因而大家在拿到需要之后, 要面向接口编程,先顶层再细节来设计代码构造。问题为什么要依赖形象,形象示意我还能够扩大还没有具体实现,依照本人的话来解释一遍 ...

December 30, 2020 · 2 min · jiezi

关于spring:Spring-源码学习-11invokeBeanFactoryPostProcessors

前言invokeBeanFactoryPostProcessors 会执行 BeanFactory 的后置处理器。看到这里会有疑难: 什么是 BeanFactoryPostProcessor ?BeanfactoryPostProcessor 该如何应用?晓得了下面两个问题的答案,对 BeanFactoryPostProcessor 有了理解之后,而后再深刻源码,持续浏览 invokeBeanFactoryPostProcessors 这个办法。 作用材料还是在官网能够找到答案: 浏览了一下,大略意思是 Spring IoC 容器容许 BeanFactoryPostProcessor 读取配置元数据,并有可能在容器实例化除 BeanFactoryPostProcessor 实例以外的任何 bean 之前更改它。 同样能够应用 Ordered 接口对 BeanFactoryPostProcessor 进行排序。 留神 BeanFactoryPostProcessor 操作的是 BeanDefinition ,即元数据。然而同样能够通过获取到 BeanFactory 进行实例化 Bean,然而官网很不倡议这样应用。 示例应用 BeanFactoryPostProcessor@Componentpublic class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 批改 BeanDefinition 信息 BeanDefinition userComponentBeanDefinition = beanFactory.getBeanDefinition("userComponent"); userComponentBeanDefinition.setLazyInit(true); // 批改 Bean 的信息 // xxx 十分不举荐 beanFactory.getBean 过早的实例化 Bean UserComponent bean = beanFactory.getBean(UserComponent.class); bean.setUserName("liuzhihang-01"); }}创立本人的 BeanFactoryPostProcessor 并实现 BeanFactoryPostProcessor 接口,增加注解即可。 ...

December 28, 2020 · 5 min · jiezi

关于spring:安利一个基于Spring-Cloud-的面试刷题系统面试毕设项目经验一网打尽

举荐????: 靠近100K star 的Java学习/面试指南Github 95k+点赞的Java面试/学习手册.pdf明天给小伙伴们举荐一个敌人开源的面试刷题零碎。 这篇文章我会从零碎架构设计层面详解介绍这个开源我的项目,并且会把微服务罕用的一些技术都介绍一下。即便你对这个我的项目不感兴趣,也能理解到很多微服务相干的常识。美滋滋! 昨晚肝了很久~原创不易,若有帮忙,求赞求转发啊! 不得不说,这个刷题零碎的确是有点货色,你真的值得领有!首先,这是一个微服务的我的项目,其次这个零碎涵盖了市面上罕用的支流技术比方 SpringBoot、Spring Cloud 等等(前面会具体介绍)。 不论是你想要学习分布式的技术,还是想找一个实战我的项目练手或者作为本人的我的项目教训,这个我的项目都非常适合你。 另外,因为我的项目作者提供了具体的技术文档,所以你不必放心上手太难! 效果图咱们先来看看这个面试刷题零碎的效果图。这里咱们只展现的是这个零碎的前端(微信小程序),后盾管理系统这里就不展现了。 能够看到,除了少部分中央的色彩搭配比拟难看之外,页面整体 UI 还是比拟好看的。 技术栈再聊聊大家最关怀的问题:“这套零碎的技术栈是什么样的呢?”。 这套零碎采纳了目前企业都在用的支流技术:SpringBoot(根底框架)、Spring Cloud(微服务)、MyBatis(ORM框架)、Redis(缓存)、MySql(关系型数据库)、MongoDB(NoSQL)、RabbitMQ(音讯队列)、Elasticsearch(搜索引擎)。并且,这个零碎是以 Docker 容器化的形式进行部署的。十分实用! 零碎架构设计理解了技术栈之后,那必然须要简略理解一下整个 零碎的架构设计 ,这是零碎的灵魂所在了(图源:PassJava 官网文档)。 网关网关负责认证受权、限流、熔断、降级、申请散发、负载平衡等等操作。个别状况下,网关个别都会提供这些性能。 这里应用的是 Spring Cloud Gateway 作为网关。Spring Cloud Gateway 是 Spring Cloud 官网推出的第二代网关框架,目标是取代 netflix 的 Zuul 网关。 注册核心和配置核心注册核心和配置核心这块应用的是阿里巴巴开源的 Nacos 。Nacos 目前属于 Spring Cloud Alibaba 中的一员。次要用于发现、配置和治理微服务,相似于 Consul、Eureka。并且,提供了分布式配置管理性能。 Nacos 的根本介绍如下(图源:官网文档-什么是 Nacos): 详解介绍一下 Nacos 在这个我的项目中提供的两个外围性能: 注册核心 :API 网关通过注册核心实时获取到服务的路由地址,精确地将申请路由到各个服务。配置核心 :传统的配置形式须要重新启动服务。如果服务很多,则须要重启所有服务,十分不不便。通过 Nacos,咱们能够动静配置服务。并且,Nacos 提供了一个简洁易用的 UI 帮忙咱们治理所有的服务和利用的配置。对于配置核心,咱们这里再拓展一下,除了 Nacos ,还有 Apollo、SpringCloud Config、K8s ConfigMap 可供选择。 ...

December 28, 2020 · 1 min · jiezi

关于spring:6-抹平差异统一类型转换服务ConversionService

分享、成长,回绝浅藏辄止。关注公众号【BAT的乌托邦】,回复关键字专栏有Spring技术栈、中间件等小而美的原创专栏供以收费学习。本文已被 https://www.yourbatman.cn 收录。✍前言你好,我是YourBatman。 通过前两篇文章的介绍曾经十分相熟Spirng 3.0全新一代的类型转换机制了,它提供的三种类型转换器(Converter、ConverterFactory、GenericConverter),别离可解决1:1、1:N、N:N的类型转换。依照Spring的设计习惯,必有一个注册核心来对立治理,负责它们的注册、删除等,它就是ConverterRegistry。 对于ConverterRegistry在文首多说一句:我翻阅了很多博客文章介绍它时简直无一例外的提到有查找的性能,但实际上是没有的。Spring设计此API接口并没有裸露其查找性能,抉择把最为简单的查找匹配逻辑私有化,目标是让开发者使可无需关怀,细节之处充分体现了Spring团队API设计的卓越能力。另外,内建的绝大多数转换器拜访权限都是default/private,那么如何应用它们,以及屏蔽各种转换器的差异化呢?为此,Spring提供了一个对立类型转换服务,它就是ConversionService。 版本约定Spring Framework:5.3.1Spring Boot:2.4.0 ✍注释ConverterRegistry和ConversionService的关系密不可分,前者为后者提供转换器治理撑持,后者面向使用者提供服务。本文波及到的接口/类有: ConverterRegistry:转换器注册核心。负责转换器的注册、删除ConversionService:对立的类型转换服务。属于面向开发者应用的门面接口ConfigurableConversionService:上两个接口的组合接口GenericConversionService:上个接口的实现,实现了注册治理、转换服务的简直所有性能,是个实现类而非抽象类DefaultConversionService:继承自GenericConversionService,在其根底上注册了一批默认转换器(Spring内建),从而具备根底转换能力,能解决日常绝大部分场景 ConverterRegistrySpring 3.0引入的转换器注册核心,用于治理新一套的转换器们。 public interface ConverterRegistry { void addConverter(Converter<?, ?> converter); <S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter); void addConverter(GenericConverter converter); void addConverterFactory(ConverterFactory<?, ?> factory); // 惟一移除办法:依照转换pair对来移除 void removeConvertible(Class<?> sourceType, Class<?> targetType);}它的继承树如下: ConverterRegistry有子接口FormatterRegistry,它属于格式化器的领域,故不放在本文探讨。但仍旧属于本系列专题内容,会在接下来的几篇内容里染指,敬请关注。 ConversionService面向使用者的对立类型转换服务。换句话说:站在应用层面,你只须要晓得ConversionService接口API的应用形式即可,并不需要关怀其外部实现机制,堪称对使用者十分敌对。 public interface ConversionService { boolean canConvert(Class<?> sourceType, Class<?> targetType); boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType); <T> T convert(Object source, Class<T> targetType); Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);}它的继承树如下: ...

December 28, 2020 · 4 min · jiezi

关于spring:Spring-源码学习-10prepareBeanFactory-和-postProcessBeanFactory

前言依据 refresh 流程,当 obtainFreshBeanFactory 执行完结后,下一步会执行 prepareBeanFactory ,顾名思义,这个办法次要是筹备 BeanFactory,上面一起看一看这部分逻辑。 prepareBeanFactoryprotected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. // 设置beanFactory的类加载器 beanFactory.setBeanClassLoader(getClassLoader()); // spring.spel.ignore 属性管制是否解析 SpEL 表达式 if (!shouldIgnoreSpel) { beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); } // 设置属性解析器 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. // 增加到后置处理器列表, 新创建的 ApplicationContextAwareProcessor 入参为以后 ApplicationContext beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 疏忽主动拆卸 // 默认状况下 只有BeanFactoryAware 被疏忽 要疏忽其余类型,须要独自设置 beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.ignoreDependencyInterface(ApplicationStartup.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. // 注册主动拆卸的类 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners. beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. // 是否须要类加载期间织入 减少Aspectj的反对 if (!IN_NATIVE_IMAGE && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // Register default environment beans. // 注册其余的 bean if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) { beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup()); }}这块代码比拟长,然而逻辑比较简单,就间接贴代码了。 ...

December 27, 2020 · 2 min · jiezi

关于spring:SpringMVC第一个页面

历史倒退Java Applet:须要浏览器插件反对,须要客户端Java运行时,太麻烦Servlet:Server Applet,即运行在服务器端(server)的Java  Applet。所有内容在服务器端生成,而后以HTML格局发送到客户端JSP:servlet技术是将HTML页面嵌入到Java类外面,简单难用。借鉴PHP,间接在JSP文件里写HTML代码,Java代码嵌入到HTML页面中。但后盾实现仍基于Servlet技术,即JSP中Java局部内容仍由servlet简单解析生成Java Bean:形象出一些Java类专门负责和数据库交互等,JSP专一于HTTP申请和响应struts:分为struts1和struts2,首次引入了MVC模式MVC在Java营垒,目前支流的是Spring MVC tomcat收费开源的解决HTTP申请的Java利用的Web服务器。 比拟:tomcat vs apache 下载tomcat Dynamic Web Projectinstall new software:装置模板 为了麻烦,全副选上…… target runtimenew server runtime environment 勾选生成 web.xml 批改: window - preferences - server 我的项目右键 - build path 查看web.xml 增加index.html(留神:门路) 要害https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...

December 27, 2020 · 1 min · jiezi

关于spring:Spring和SpringMVC

Spring管制反转(IoC)和依赖注入(DI) Inverse of Controller:目标,很多形式都能够实现。原本new一个对象,由源代码管制;反转成由内部(比方.xml文件)管制 Dependency Injection:实现,实现IoC的一种形式。 其实最开始都一样 (Martin Fowler改名) context:容器 和 eclipse环境 Marketplace 装置实现: 能够失去spring相干的jar MVC为什么须要Spring? HTTP申请须要由不同的Java对象予以解决,这些Java对象就由Spring生成 Maven一个项目管理工具,能够对 Java 我的项目进行构建、依赖治理。 add dev tool 抉择本人曾经配置好的Java版本 在New Spring Starter Project Dependencies中抉择SpringMVC 外面就曾经蕴含了:https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...http://github.com/hdfgfgh546/...https://github.com/hdfgfgh546...https://www.github.com/hdfgfg...

December 27, 2020 · 1 min · jiezi

关于spring:迷茫了我们到底该不该用lombok

前言最近上网查资料发现很多人对lombok褒贬不一,引起了我的趣味,因为咱们我的项目中也在大量应用lombok,大家不同的观点让我也困惑了几天,明天联合我理论的我的项目教训,说说我的集体倡议。 轻易搜搜就找到了这几篇文章: 这些人倡议应用 lombok,感觉它是一个神器,能够大大提高编码效率,并且让代码更优雅。 在搜寻的过程中,有些文章却又不举荐应用: 这些人感觉它有一些坑,容易给我的项目埋下隐患,咱们到底该听谁的呢? 为什么倡议应用lombok?1.传统javabean在没应用lombok之前,咱们个别是这样定义javabean的: public class User { private Long id; private String name; private Integer age; private String address; public User() { } public User(Long id, String name, Integer age, String address) { this.id = id; this.name = name; this.age = age; this.address = address; } public Long getId() { return id; } public String getName() { return name; } public Integer getAge() { return age; } public String getAddress() { return address; } public void setId(Long id) { this.id = id; } public void setName(String name) { this.name = name; } public void setAge(Integer age) { this.age = age; } public void setAddress(String address) { this.address = address; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(age, user.age) && Objects.equals(address, user.address); } @Override public int hashCode() { return Objects.hash(id, name, age, address); } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", address='" + address + '\'' + '}'; }}该User类中蕴含了:成员变量、getter/setter办法、构造方法、equals、hashCode办法。 ...

December 23, 2020 · 2 min · jiezi

关于spring:如何通过-Spring-框架进行JDBC操作

通过 Spring 框架如何进行JDBC操作呢?Spring 整合 JDBC 的形式增加依赖编写配置文件 db.propertiesbean.xml 配置批改配置数据源模板类配置测试整合后果案例实操增加依赖数据库驱动 jar 包mysql-connector-java-5.1.25-bin.jar 数据库连接池相干 jar 包c3p0-0.9.5.2.jar、mchange-commons-java-0.2.11.jar Spring jdbc 相干 jarspring-jdbc-4.3.2.RELEASE.jar、spring-tx-4.3.2.RELEASE.jar <!-- spring 框架坐标依赖增加 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version></dependency><!-- aop --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version></dependency><!-- mysql 驱动包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.39</version></dependency><!-- c3p0 连接池 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version></dependency><!-- spring jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.2.RELEASE</version></dependency><!-- springs事务 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.3.2.RELEASE</version></dependency> ...

December 23, 2020 · 2 min · jiezi

关于spring:Spring-源码学习-08register-注册配置类

前言看完无参结构的源码及流程之后,前面将会执行 register 办法。 register 办法,入参是咱们的配置类 JavaConfig.class ,上面跟着源码持续往下走! 源码剖析 this.reader.register(componentClasses); 这里执行的是 reader 的办法,入参就是传入的 JavaConfig.class。 reader 在之前初始化,就是注册一些 PostProcessor。 循环,注册所有的配置类;doRegisterBean 开始注册。doRegisterBean 才是真正注册 Bean 的逻辑,从名字也能够有所猜想。上面开始进入 doRegisterBean 的源码浏览: doRegisterBean 此处代码较长,以截图代替。 通过源码能够看出,这块次要流程: 校验传入的 JavaConfig.class 的注解(是否须要疏忽);解决通用注解;封装为 BeanDefinitionHolder 后,注册到容器中。debug 通过 debug 能够看出,在执行完 register 之后,相当于将 JavaConfig 作为一个 Bean 注册到容器中。 总结 在我看来后面的局部次要波及到筹备工作,至于更深层次的钻研,剖析,临时没有深刻。 相干举荐Spring 源码学习 07:ClassPathBeanDefinitionScannerSpring 源码学习 06:AnnotatedBeanDefinitionReaderSpring 源码学习 05:BeanDefinition 概念及其实现

December 23, 2020 · 1 min · jiezi

关于spring:Github标星26k一个神奇的软件1分钟即可打造了一个科幻风格的终端

Github掘金打算我的项目分类汇总(原创不易,若有帮忙,欢送分享/点赞): 编程根底 :精选编程根底如学习路线、编程语言相干的开源我的项目。计算机根底:精选计算机根底(操作系统、计算机网络、算法、数据结构)相干的开源我的项目。技术面试 :精选技术面试相干的开源我的项目。我的项目实战 :精选实战类型的开源我的项目。如果你也是科幻电影迷,想要让本人的终端变得更加极客。就像上面 ???? 这样。 你能够试试明天的举荐的开源我的项目。 Github 上有一个名字叫做 edex-ui 的我的项目,开源之后便受到了宽广开发者的青睐,屡次登上了 Github Trending 榜单! 简略来说,通过这个开源我的项目你能够非常简单地搭建一个科幻格调的终端仿真器,这个模拟器的外观和感觉都像科幻计算机界面一样。 非常适合用来装逼~ 有点科幻电影既视感的感觉! 并且,界面款式是能够自定义的,能够满足大部分小伙伴的需要。 常见的支流操作系统比方 Linux、Windows、MacOS 都能够装置这个我的项目。 你能够在 https://github.com/GitSquared... 这里进行下载安装。 咱们只须要抉择一个适宜本人操作系统的版本即可! 如果你拜访 Github 的速度比较慢的话,能够下方链接进行下载: 链接: https://pan.baidu.com/s/1P2AC... 明码: 3p7f 下载实现之后,咱们间接双击装置即可,整个过程非常简单! 装置实现之后,咱们间接点击运行即可!你能够把它当做一个一般的软件来运行,十分不便。 下图是在我的电脑运行的效果图。 你能够通过双击settings.json 这个文件的形式来批改一些默认配置比方主题。 如下图所示,我这里把主题的批改为了 apollo 的款式。 我是Guide哥。我从大二就开始保持写博客。不怕大家笑话,我其实在大二的时候连 Linux 、Github 是啥都不晓得。不过,目前我曾经在Github上播种了100k+ star 以及 5.7k +的关注。我的Github地址 :https://github.com/Snailclimb ,欢送来一起游玩啊! 不过说句心里话,我的这些我的项目都不过是本人小打小闹的玩具罢了!写这些我的项目的目标次要也是为了进步本人的能力的同时来帮忙到更多的小伙伴。 我更心愿的是本人可能参加或者写出一个被更宽泛应用的软件/框架。 我想这也是每一个技术人的幻想!共勉,路漫漫其修远兮!

December 22, 2020 · 1 min · jiezi

关于spring:5-穿过拥挤的人潮Spring已为你制作好高级赛道

分享、成长,回绝浅藏辄止。关注公众号【BAT的乌托邦】,回复关键字专栏有Spring技术栈、中间件等小而美的原创专栏供以收费学习。本文已被 https://www.yourbatman.cn 收录。✍前言你好,我是YourBatman。 上篇文章 大篇幅把Spring全新一代类型转换器介绍完了,曾经至多可能考个及格分。在介绍Spring泛滥内建的转换器里,我成心留下一个尾巴,放在本文专门撰文解说。 为了让本人能在“拥挤的人潮中”显得不(更)一(突)样(出),A哥特意筹备了这几个非凡的转换器助你破局,穿梭拥挤的人潮,踏上Spring已为你制作好的高级赛道。 版本约定Spring Framework:5.3.1Spring Boot:2.4.0 ✍注释本文的焦点将集中在上文留下的4个类型转换器上。 StreamConverter:将Stream流与汇合/数组之间的转换,必要时转换元素类型这三个比拟非凡,属于“最初的”“兜底类”类型转换器: ObjectToObjectConverter:通用的将原对象转换为指标对象(通过工厂办法or结构器)IdToEntityConverter:本文重点。给个ID主动帮你兑换成一个Entity对象FallbackObjectToStringConverter:将任何对象调用toString()转化为String类型。当匹配不到任何转换器时,它用于兜底默认转换器注册状况Spring新一代类型转换内建了十分多的实现,这些在初始化阶段大都被默认注册进去。注册点在DefaultConversionService提供的一个static动态工具办法里: static静态方法具备与实例无关性,我集体感觉把该static办法放在一个xxxUtils里对立治理会更好,放在具体某个组件类里反倒容易产生语义上的误导性DefaultConversionService: public static void addDefaultConverters(ConverterRegistry converterRegistry) { // 1、增加标量转换器(和数字相干) addScalarConverters(converterRegistry); // 2、增加解决汇合的转换器 addCollectionConverters(converterRegistry); // 3、增加对JSR310工夫类型反对的转换器 converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry)); converterRegistry.addConverter(new StringToTimeZoneConverter()); converterRegistry.addConverter(new ZoneIdToTimeZoneConverter()); converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter()); // 4、增加兜底转换器(下面解决不了的全交给这几个哥们解决) converterRegistry.addConverter(new ObjectToObjectConverter()); converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry)); converterRegistry.addConverter(new FallbackObjectToStringConverter()); converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry)); } }该静态方法用于注册全局的、默认的转换器们,从而让Spring有了根底的转换能力,进而实现绝大部分转换工作。为了不便记忆这个注册流程,我把它绘制成图供以你保留: 特别强调:转换器的注册程序十分重要,这决定了通用转换器的匹配后果(谁在前,优先匹配谁)。 针对这幅图,你可能还会有疑难: JSR310转换器只看到TimeZone、ZoneId等转换,怎么没看见更为罕用的LocalDate、LocalDateTime等这些类型转换呢?难道Spring默认是不反对的? 答:当然不是。 这么常见的场景Spring怎能会不反对呢?不过与其说这是类型转换,倒不如说是格式化更适合。所以会在后3篇文章格式化章节在作为重中之重讲述个别的Converter都见名之意,但StreamConverter有何作用呢?什么场景下会失效 答:本文讲述对于兜底的转换器,有何含意?这种极具通用性的转换器作用为何 答:本文讲述StreamConverter用于实现汇合/数组类型到Stream类型的互转,这从它反对的Set<ConvertiblePair> 汇合也能看进去: @Overridepublic Set<ConvertiblePair> getConvertibleTypes() { Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>(); convertiblePairs.add(new ConvertiblePair(Stream.class, Collection.class)); convertiblePairs.add(new ConvertiblePair(Stream.class, Object[].class)); convertiblePairs.add(new ConvertiblePair(Collection.class, Stream.class)); convertiblePairs.add(new ConvertiblePair(Object[].class, Stream.class)); return convertiblePairs;}它反对的是双向的匹配规定: ...

December 22, 2020 · 3 min · jiezi

关于spring:微服务之间如何共享DTO

1. 概述近些年来,微服务变得越来越风行。微服务基本特征是模块化、独立、易于扩大的。它们之间须要协同工作并替换数据。为了实现这一点,咱们创立了名为 DTO 的共享数据传输对象。在本文中,咱们将介绍在微服务之间共享DTO的办法。 2. 将域对象公布为DTO应用微服务治理示意应用程序域的模型。域模型的关注点与 DTO 不同,咱们将它们与DAO层中的数据模型离开。这样做的次要起因是咱们不想通过服务向客户裸露咱们畛域的复杂性。 恰恰相反,咱们通过 REST API 裸露 DTO 为客户端提供服务。当DTO在这些服务之间传递时,咱们将它们转换为域对象。 下面的 面向服务架构 示意性地显示了DTO到域对象的组件和流程。 3. 微服务间共享DTO以客户订购产品的过程为例。此过程基于 Customer-Order 模型,从服务体系结构的角度来看看这个过程。假如客户服务将申请数据发送到订单服务: "order": { "customerId": 1, "itemId": "A152"}Customer 和 Order 服务应用 contracts (契约) 进行通信。contract(或者是服务申请)以JSON格局显示。作为 Java 模型,OrderDTO 类示意客户服务和订单服务之间的契约: public class OrderDTO { private int customerId; private String itemId; // constructor, getters, setters}3.1. 应用客户端模块共享DTO微服务须要来自其余服务的某些信息来解决任何申请。假如有第三个微服务接管订单付款申请。与订单服务不同,此服务须要不同的客户信息: public class CustomerDTO { private String firstName; private String lastName; private String cardNumber; // constructor, getters, setters}如果咱们还增加了送货服务,客户信息将具备: ...

December 22, 2020 · 1 min · jiezi

关于spring:4-上新了Spring全新一代类型转换机制

分享、成长,回绝浅藏辄止。关注公众号【BAT的乌托邦】,回复关键字专栏有Spring技术栈、中间件等小而美的原创专栏供以收费学习。本文已被 https://www.yourbatman.cn 收录。✍前言你好,我是YourBatman。上篇文章 介绍完了Spring类型转换晚期应用的PropertyEditor具体介绍,对于PropertyEditor现存的材料其实还蛮少的,心愿这几篇文章能补救这块空白,奉献一份微薄之力。如果你也吐槽过PropertyEditor不好用,那么本文将对会有帮忙。Spring自3.0版本开始自建了一套全新类型转换接口,这就是本文的次要内容,接下来逐渐开展。 阐明:Spring自3.0后笑傲群雄,进入大一统。Java从此步入Spring的时代版本约定Spring Framework:5.3.1Spring Boot:2.4.0 ✍注释在理解新一代的转换接口之前,先思考一个问题:Spring为何要本人造一套轮子呢? 一贯秉承不反复造轮子准则的Spring,不是无可奈何的话是不会去动别人奶酪的,毕竟互利共生能力短暂。类型转换,作为Spring框架的基石,扮演着异样重要的角色,因而对其可扩展性、可维护性、高效性均有很高要求。基于此,咱们先来理解下PropertyEditor设计上到底有哪些缺点/有余(不能满足现代化需要),让Spring“被迫”走上了自建路线。 PropertyEditor设计缺点前提阐明:本文指出它的设计缺点,只探讨把它当做类型转换器在转换场景下存在的一些缺点。 职责不繁多:该接口有十分多的办法,但只用到2个而已类型不平安:setValue()办法入参是Object,getValue()返回值是Object,依赖于约定好的类型强转,不平安线程不平安:依赖于setValue()后getValue(),实例是线程不平安的语义不清晰:从语义上基本不能晓得它是用于类型转换的组件只能用于String类型:它只能进行String <-> 其它类型的转换,而非更灵便的Object <-> ObjectPropertyEditor存在这五宗“罪”,让Spring决定本人设计一套全新API用于专门服务于类型转换,这就是本文题目所述:新一代类型转换Converter、ConverterFactory、GenericConverter。 对于PropertyEditor在Spring中的详情介绍,请参见文章:3. 搞定出工,PropertyEditor就到这新一代类型转换为了解决PropertyEditor作为类型转换形式的设计缺点,Spring 3.0版本从新设计了一套类型转换接口,有3个外围接口: Converter<S, T>:Source -> Target类型转换接口,实用于1:1转换ConverterFactory<S, R>:Source -> R类型转换接口,实用于1:N转换GenericConverter:更为通用的类型转换接口,实用于N:N转换留神:就它没有泛型束缚,因为是通用另外,还有一个条件接口ConditionalConverter,可跟下面3个接口搭配组合应用,提供前置条件判断验证。这套接口,解决了PropertyEditor做类型转换存在的所有缺点,且具备十分高的灵活性和可扩展性。上面进入具体理解。 Converter将源类型S转换为指标类型T。 @FunctionalInterfacepublic interface Converter<S, T> { T convert(S source);}它是个函数式接口,接口定义非常简单。适宜1:1转换场景:能够将任意类型 转换为 任意类型。它的实现类十分多,局部截图如下:值得注意的是:简直所有实现类的拜访权限都是default/private,只有少数几个是public公开的,上面我用代码示例来“近距离”感受一下。 代码示例/** * Converter:1:1 */@Testpublic void test() { System.out.println("----------------StringToBooleanConverter---------------"); Converter<String, Boolean> converter = new StringToBooleanConverter(); // trueValues.add("true"); // trueValues.add("on"); // trueValues.add("yes"); // trueValues.add("1"); System.out.println(converter.convert("true")); System.out.println(converter.convert("1")); // falseValues.add("false"); // falseValues.add("off"); // falseValues.add("no"); // falseValues.add("0"); System.out.println(converter.convert("FalSe")); System.out.println(converter.convert("off")); // 留神:空串返回的是null System.out.println(converter.convert("")); System.out.println("----------------StringToCharsetConverter---------------"); Converter<String, Charset> converter2 = new StringToCharsetConverter(); // 两头横杠非必须,但强烈建议写上 不辨别大小写 System.out.println(converter2.convert("uTf-8")); System.out.println(converter2.convert("utF8"));}运行程序,失常输入: ...

December 21, 2020 · 3 min · jiezi

关于spring:记一次死锁分析过程

### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction### The error may involve com.cgd.order.dao.OrderSaleMapper.updateSaleOrderStatus-Inline### The error occurred while setting parameters### SQL: update t_order set ORDER_STATUS = ? where ORDER_ID = ?小盆友,如果你在日志里看到这个是不是像我一样会有很多问号?? 我一个只会写增删改查sql的低层次程序员有了满奶子问号。 然而我置信啊:只有功夫深,李白碰到的老婆婆就能把铁杵磨成针。 1.首先是要理解一些除了增删改查之外的数据库基础知识从极客上找了门MySQL实战,如果你也想买,请分割我,推荐人买有返现的。 这门课我是感觉很值,这两天为了解决这个死锁又读了一遍无关加锁的章节,发现了一条命令啊,这个命令会输入很多信息,有一节 LATESTDETECTED DEADLOCK,就是记录的最初一次死锁信息。 show engine innodb status;我就试着执行了下,好巧不巧跟那天死锁日志里的sql一样,不过也阐明这死锁问题挺频繁的 ------------------------LATEST DETECTED DEADLOCK------------------------2020-12-17 11:20:09 7fbe339f7700//第一个事务*** (1) TRANSACTION:TRANSACTION 116609954, ACTIVE 1.214 sec starting index readmysql tables in use 1, locked 1LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)LOCK BLOCKING MySQL thread id: 72830 block 64282MySQL thread id 64282, OS thread handle 0x7fbe01f7d700, query id 1042364621 172.16.21.10 prod_orderdb updating//以上乌七八糟的有事务的根底信息 大小 行数等等 //下边一行是死锁的其中一方的sql 解析一下ORDER_ID是表的主键/* 276aedd616081752079448345e2ac7/0.1.3// */update t_order set ORDER_STATUS = 4 where ORDER_ID = 234//示意这个事务在期待的锁信息*** (1) WAITING FOR THIS LOCK TO BE GRANTED://以后在期待表t_order上的 X锁, 主键为 8de0b6b3a773935bRECORD LOCKS space id 1252 page no 10646 n bits 112 index `PRIMARY` of table `t_order` trx id 116609954 lock_mode X locks rec but not gap waiting//n_fields 115 示意记录有115列 Record lock, heap no 10 PHYSICAL RECORD: n_fields 115; compact format; info bits 0//第一列 根本就是主键了 0: len 8; hex 8de0b6b3a773935b; asc s [;; 1: len 6; hex 000006ef0a51; asc Q;; 2: len 7; hex 76000006f723b0; asc v # ;; 3: len 16; hex 32303230313231323030333139363331; asc 2020121200319631;; 4: len 4; hex 80000000; asc ;; 5: SQL NULL; 6: len 4; hex 80000002; asc ;; 7: SQL NULL; 8: len 4; hex 8000000b; asc ;;...省略1xx行.//第二个事务信息*** (2) TRANSACTION:TRANSACTION 116609912, ACTIVE 7.886 sec fetching rowsmysql tables in use 1, locked 136461 lock struct(s), heap size 3241512, 306688 row lock(s), undo log entries 12MySQL thread id 72830, OS thread handle 0x7fbe339f7700, query id 1042364593 172.16.21.0 prod_orderdb Searching rows for update//同理第二个sqlupdate t_order set ORDER_STATUS = 4 where EXT_ID = '232SA'//以后事务持有的锁*** (2) HOLDS THE LOCK(S)://持有N个S锁RECORD LOCKS space id 1252 page no 10646 n bits 112 index `PRIMARY` of table `t_order` trx id 116609912 lock mode S locks rec but not gapRecord lock, heap no 2 PHYSICAL RECORD: n_fields 115; compact format; info bits 0 0: len 8; hex 8de0b6b3a7739342; asc s B;; 1: len 6; hex 000006f1aeff; asc ;; 2: len 7; hex 64000006ce20bb; asc d ;; 3: len 16; hex 32303230313231323030333139363036; asc 2020121200319606;; 4: len 4; hex 80000000; asc ;; 5: SQL NULL; 6: len 4; hex 80000002; asc ;; 7: SQL NULL; . . .//++++++++++Record lock, heap no 10 PHYSICAL RECORD: n_fields 115; compact format; info bits 0 0: len 8; hex 8de0b6b3a773935b; asc s [;; 1: len 6; hex 000006ef0a51; asc Q;; 2: len 7; hex 76000006f723b0; asc v # ;; 3: len 16; hex 32303230313231323030333139363331; asc 2020121200319631;; 4: len 4; hex 80000000; asc ;; 5: SQL NULL; . . . //++++++++++ 此处还省略N多 //++++++++++之间的行,同时持有很多行的锁//期待的锁*** (2) WAITING FOR THIS LOCK TO BE GRANTED://同样是期待X锁 主键为 8de0b6b3a773935bRECORD LOCKS space id 1252 page no 10646 n bits 112 index `PRIMARY` of table `t_order` trx id 116609912 lock_mode X locks rec but not gap waitingRecord lock, heap no 10 PHYSICAL RECORD: n_fields 115; compact format; info bits 0 0: len 8; hex 8de0b6b3a773935b; asc s [;; 1: len 6; hex 000006ef0a51; asc Q;; 2: len 7; hex 76000006f723b0; asc v # ;; 3: len 16; hex 32303230313231323030333139363331; asc 2020121200319631;; 4: len 4; hex 80000000; asc ;; 5: SQL NULL; . . .//数据库抉择回滚老本最小的一个事务进行回滚*** WE ROLL BACK TRANSACTION (1)2.思考两条sql,对应两条数据,八竿子打不着的两条数据在更新的时候产生了死锁 ...

December 21, 2020 · 4 min · jiezi

关于spring:万亿级数据的方法简单易懂

背景 在星爷的《大话西游》中有一句十分闻名的台词:“已经有一份真挚的感情摆在我的背后我没有珍惜,等我失去的时候才追悔莫及,世间最苦楚的事莫过于此,如果入地能给我一次再来一次的机会,我会对哪个女孩说三个字:我爱你,如果非要在这份爱上加一个期限,我心愿是一万年!”在咱们开发人员的眼中,这个感情就和咱们数据库中的数据一样,咱们多心愿他一万年都不扭转,然而往往大失所望,随着公司的一直倒退,业务的一直变更,咱们对数据的要求也在一直的变动,大略有上面的几种状况: 分库分表:业务倒退越来越快,导致单机数据库接受的压力越来越大,数据量也越来越多,这个时候通常会应用分库的办法去解决这个问题,将数据库的流量均分到不同的机器上。从单机数据库到分库这个过程,咱们就须要残缺的迁徙咱们的数据,咱们能力胜利的分库的形式上应用咱们的数据。更换存储介质:下面介绍的分库,一般来说咱们迁徙完之后,存储介质仍然是同样的,比如说之前应用的是单机Mysql,分库之后就变成了多台机器的Mysql,咱们的数据库表的字段都没有发生变化,迁徙来说绝对比较简单。有时候咱们分库分表并不能解决所有的问题,如果咱们须要很多简单的查问,这个时候应用Mysql可能就不是一个靠谱的计划,那么咱们就须要替换查问的存储介质,比方应用elasticsearch,这种的迁徙就会略微要简单一些,波及到不同存储介质的数据转换。切换新零碎:个别公司在高速倒退中,肯定会呈现很多为了速度快而后反复建设的我的项目,当公司再肯定时间段的时候,往往这部分我的项目会被合并,变成一个平台或者中台,比方咱们一些会员零碎,电商零碎等等。这个时候往往就会面临一个问题,将老的零碎中的数据须要迁徙到新的零碎中,这个时候就更加简单了,有可能不仅是存储介质有变动,有可能我的项目语言也不同,从更下层的角度来看,部门有可能也不同,所以这种数据迁徙的难度是比拟高,危险也更加的大。在理论业务开发中,咱们会依据不同的状况来做出不同的迁徙计划,接下来咱们来讨论一下到底应该怎么迁徙数据。 数据迁徙 数据迁徙其实不是欲速不达的,每一次数据迁徙都须要一段漫长的工夫,有可能是一周,有可能是几个月,通常来说咱们迁徙数据的过程根本都和下图差不多: 首先咱们须要将咱们数据库曾经存在的数据进行批量的迁徙,而后须要解决新增的这部分数据,须要实时的把这部分数据在写完本来的数据库之后而后写到咱们的新的存储,在这一过程中咱们须要一直的进行数据校验。当咱们校验根本问题不大的时候,而后进行切流操作,直到齐全切流之后,咱们就能够不必再进行数据校验和增量数据迁徙。 存量数据迁徙 首先咱们来说一下存量数据迁徙应该怎么做,存量数据迁徙在开源社区中搜寻了一圈发现没有太好用的工具,目前来说阿里云的DTS提供了存量数据迁徙,DTS反对同构和异构不同数据源之间的迁徙,根本反对业界常见的数据库比方Mysql,Orcale,SQL Server等等。DTS比拟适宜咱们之前说的前两个场景,一个是分库的场景,如果应用的是阿里云的DRDS那么就能够间接将数据通过DTS迁徙到DRDS,另外一个是数据异构的场景,无论是Redis还是ES,DTS都反对间接进行迁徙。 那么DTS的存量迁徙怎么做的呢?其实比较简单大略就是上面几个步骤: 当存量迁徙工作启动的时候,咱们获取以后须要迁徙的最大的id和最小id设置一个分段,比方1万,从最小id开始每次查问1万的数据给DTS服务器,交给DTS解决。sql如下: `select * from table_name where id > curId and id < curId + 10000;` * 1 3.当id大于maxId之后,存量数据迁徙工作完结 当然咱们在理论的迁徙过程中可能不会去应用阿里云,或者说在咱们的第三个场景下,咱们的数据库字段之间须要做很多转换,DTS不反对,那么咱们就能够模拟DTS的做法,通过分段批量读取数据的形式来迁徙数据,这里须要留神的是咱们批量迁徙数据的时候须要管制分段的大小,以及频率,避免影响咱们线上的失常运行。 增量数据迁徙 存量数据的迁徙计划比拟无限,然而增量的数据迁徙办法就是百花齐放了,一般来说咱们有上面的几种办法: DTS: 阿里云的DTS算是一条龙服务了,在提供存量数据迁徙的同时也提供了增量数据迁徙,只不过须要按量免费。服务双写:比拟适宜于零碎没有切换的迁徙,也就是只换了存储然而零碎还是同一个,比如说分库分表,redis数据同步等,这个的做法比较简单间接在代码外面同步的去写入须要迁徙的数据,然而因为不是同一个数据库就不能保障事务,有可能导致迁徙数据的时候会呈现数据失落,这个过程通过后续的数据校验会进行解决。MQ异步写入:这个能够实用于所有的场景,当有数据批改的时候发送一个MQ音讯,消费者收到这个音讯之后再进行数据更新。这个和下面的双写有点相似,然而他把数据库的操作变成了MQ异步了出问题的概率就会小很多监听binlog: 咱们能够应用之前说过的canal或者其余的一些开源的如databus去进行binlog监听,监听binlog的形式 就和下面的音讯MQ形式一样,只是发送音讯的这一步被咱们省略了。这个形式的一个开发量来说根本是最小的。这么多种形式咱们应该应用哪种呢?我集体来说是比拟举荐监听binlog的做法的,监听binlog缩小开发成本,咱们只须要实现consumer逻辑即可,数据能保障一致性,因为是监听的binlog这里不须要放心之前双写的时候不是一个事务的问题。 数据校验 后面所说的所有计划,尽管有很多是成熟的云服务(dts)或者中间件(canal),然而他们都有可能呈现一些数据失落,呈现数据失落的状况整体来说还是比拟少,然而十分难排查,有可能是dts或者canal不小心抖了一下,又或者是接收数据的时候不小心导致的失落。既然咱们没有方法防止咱们的数据在迁徙的过程中失落,那么咱们应该通过其余伎俩来进行校对。 通常来说咱们迁徙数据的时候都会有数据校验这一个步骤,然而在不同团队可能会选取不同的数据校验计划: 之前在美团的时候,咱们会做一个双读,也就是咱们所有的读取都会从新的外面读取一份,然而返回的还是老的,这个时候咱们须要做这部分数据的校验,如果有问题能够发出报警人工修复或者主动修复。通过这种形式,咱们罕用的数据就能很快的进行一个修复,当然也会不定时的去跑一个全量的数据check,只是这种check进去修复数据的工夫就比拟滞后。当初在猿辅导之后,咱们没有采纳之前的那种形式,因为双读check尽管能很快发现数据的不对,然而咱们并没有对这部分数据有那么高的一个实时性校验并且双读的一个代码开发量还是略微比拟大的,然而又不能依附不定时全量check去保障,这样就会导致咱们的数据校验工夫会十分的缩短。咱们采取了一个折中的办法,咱们借鉴了对账外面的T+1的一个思路,咱们每天凌晨获取老数据库中昨天更新的数据,而后和咱们新数据库中的数据做一一比对,如果有数据不一样或者数据缺失,咱们都能够立马进行一个修复。当然在理论开发过程中咱们也须要留神上面几点: 数据校验工作的一个正确性如何保障,校验工作原本就是去校对其余数据的,然而如果他本身呈现了问题,就失去了校验的意义,这里目前来说只能靠review代码这种形式去保障校验工作的正确性。校验工作的时候须要留神日志的打印,有时候呈现问题可能是间接所有数据呈现问题,那么校验工作就有可能会打出大量的谬误日志,而后进行报警,有可能会将零碎打挂,或者说影响其他人的服务。这里如果要简略一点搞,能够将一些非人工解决的报警搞成warn,简单一点搞得话,能够封装一个工具,某个error打印再某个时间段超过一定量而后就不必再打印了。校验工作留神不要影响线上运行的服务,通常校验工作会写很多批查问的语句,会呈现批量扫表的状况,如果代码没有写好很容易导致数据库挂掉。切流 当咱们数据校验根本没有报错了之后,阐明咱们的迁徙程序是比较稳定的了,那么咱们就能够间接应用咱们新的数据了吗?当然是不能够的,如果咱们一把切换了,顺利的话当然是很好的,如果呈现问题了,那么就会影响所有的用户。 所以咱们接下来就须要进行灰度,也就是切流。对于不同的业务切流的的维度会不一样,对于用户维度的切流,咱们通常会以userId的取模的形式去进行切流,对于租户或者商家维度的业务,就须要依照租户id取模的形式去切流。这个切流须要制订好一个切流打算,在什么时间段,放出多少的流量,并且切流的时候肯定要抉择流量比拟少的时候进行切流,每一次切流都须要对日志做具体的察看,呈现问题尽早修复,流量的一个放出过程是一个由慢到快的过程,比方最开始是以1%的量去一直叠加的,到前面的时候咱们间接以10%,20%的量去疾速放量。因为如果呈现问题的话往往在小流量的时候就会发现,如果小流量没有问题那么后续就能够疾速放量。 留神主键ID 在迁徙数据的过程中特地要留神的是主键ID,在下面双写的计划中也提到过主键ID须要双写的时候手动的去指定,避免ID生成程序谬误。 如果咱们是因为分库分表而进行迁徙,就须要思考咱们当前的主键Id就不能是自增id,须要应用分布式id,这里比拟举荐的是美团开源的leaf,他反对两种模式一种是雪花算法趋势递增,然而所有的id都是Long型,适宜于一些反对Long为id的利用。还有一种是号段模式,这种会依据你设置的一个根底id,从这个下面一直的减少。并且根本都走的是内存生成,性能也是十分的快。 当然咱们还有种状况是咱们须要迁徙零碎,之前零碎的主键id在新零碎中曾经有了,那么咱们的id就须要做一些映射。如果咱们在迁徙零碎的时候曾经晓得将来大略有哪些零碎会迁徙进来,咱们就能够采纳预留的形式,比方A零碎当初的数据是1到1亿,B零碎的数据也是1到1亿,咱们当初须要将A,B两个零碎合并成新零碎,那么咱们能够略微预估一些Buffer,比方给A零碎留1到1.5亿,这样A就不须要进行映射,B零碎是1.5亿到3亿,那么咱们转换成老零碎Id的时候就须要减去1.5亿,最初咱们新零碎的新的Id就从3亿开始递增。然而如果零碎中没有做布局的预留段怎么办呢?能够通过上面两种形式: 须要新增一个表,将老零碎的id和新零碎的id做一个映射记录,这个工作量还是比拟大的,因为咱们个别迁徙都会波及几十上百张表,记录的老本还是十分的高。如果id是Long型的话,咱们能够好好利用long是64位这个因素,咱们能够制订一个规定,咱们新零碎的id都是从一个比拟大的数开始,比方从大于Int的数开始,将小Int的那局部数都能够留给咱们的老零碎做Id迁徙,比方咱们下面的1.5亿的数据量,其实只用了28位,咱们的Int是32位,那么还有4位能够应用,这个4位能够代表16个零碎做迁徙,当然如果布局中有更多的零碎做迁徙,能够将新零碎的id起始点设置得更大一点。如下图所示: 总结 最初简略来总结下这个套路,其实就是四个步骤,一个留神:存量,增量,校验,切流,最初再留神一下id。不论是多大量级的数据,基本上依照这个套路来迁徙就不会呈现大的问题。心愿能在大家的后续迁徙数据工作中,这篇文章能帮忙到你。以下文章来源于咖啡拿铁 ,作者咖啡拿铁 总结了一些2020年的面试题,这份面试题的蕴含的模块分为19个模块,别离是: Java 根底、容器、多线程、反射、对象拷贝、Java Web 、异样、网络、设计模式、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、MyBatis、RabbitMQ、Kafka、Zookeeper、MySQL、Redis、JVM 。 获取材料以上材料:关注公众号:有故事的程序员,获取学习材料。记得点个关注+评论哦~

December 20, 2020 · 1 min · jiezi

关于spring:面试工作必备3种常用的缓存读写策略

举荐????:靠近100K star 的Java学习/面试指南:JavaGuide 看到很多小伙伴简历上写了“纯熟应用缓存”,然而被我问到“缓存罕用的3种读写策略”的时候却一脸懵逼。 在我看来,造成这个问题的起因是咱们在学习 Redis 的时候,可能只是简略了写一些 Demo,并没有去关注缓存的读写策略,或者说压根不晓得这回事。 然而,搞懂3种常见的缓存读写策略对于理论工作中应用缓存以及面试中被问到缓存都是十分有帮忙的! 上面我会简略介绍一下本人对于这 3 种缓存读写策略的了解。 另外,这3 种缓存读写策略各有优劣,不存在最佳,须要咱们依据具体的业务场景抉择更适宜的。 集体能力无限。如果文章有任何须要补充/欠缺/批改的中央,欢送在评论区指出,共同进步!——爱你们的 Guide 哥 Cache Aside Pattern(旁路缓存模式)Cache Aside Pattern 是咱们平时应用比拟多的一个缓存读写模式,比拟适宜读申请比拟多的场景。 Cache Aside Pattern 中服务端须要同时维系 DB 和 cache,并且是以 DB 的后果为准。 上面咱们来看一下这个策略模式下的缓存读写步骤。 写 : 先更新 DB而后间接删除 cache 。简略画了一张图帮忙大家了解写的步骤。 读 : 从 cache 中读取数据,读取到就间接返回cache中读取不到的话,就从 DB 中读取数据返回再把数据放到 cache 中。简略画了一张图帮忙大家了解读的步骤。 你仅仅理解了下面这些内容的话是远远不够的,咱们还要搞懂其中的原理。 比如说面试官很可能会诘问:“在写数据的过程中,能够先删除 cache ,后更新 DB 么?” 答案: 那必定是不行的!因为这样可能会造成数据库(DB)和缓存(Cache)数据不统一的问题。为什么呢?比如说申请1 先写数据A,申请2随后读数据A的话就很有可能产生数据不一致性的问题。这个过程能够简略形容为: 申请1先把cache中的A数据删除 -> 申请2从DB中读取数据->申请1再把DB中的A数据更新。当你这样答复之后,面试官可能会紧接着就诘问:“在写数据的过程中,先更新DB,后删除cache就没有问题了么?” 答案: 实践上来说还是可能会呈现数据不一致性的问题,不过概率十分小,因为缓存的写入速度是比数据库的写入速度快很多! 比方申请1先读数据 A,申请2随后写数据A,并且数据A不在缓存中的话也有可能产生数据不一致性的问题。这个过程能够简略形容为: 申请1从DB读数据A->申请2写更新数据 A 到数据库并把删除cache中的A数据->申请1将数据A写入cache。当初咱们再来剖析一下 Cache Aside Pattern 的缺点。 ...

December 18, 2020 · 1 min · jiezi

关于spring:谁再问Servlet的问题我就亲自上门来教学了

1. 概述在这篇简短的文章中,咱们将从概念上了解什么是servlet 和 servlet 容器以及它们是如何工作的**。同时,还能在申请、响应、会话对象、共享变量和多线程的上下文中看到它们的身影。** 2. Servlets 和 它的容器servlet 是 JEE 用于 web 开发罕用的组件。它们基本上是运行在容器边界内的Java程序。总的来说,它们负责承受申请,解决申请,并返回响应。 要应用它们,首先须要容器注册 servlet ,无论是基于 JEE 还是基于 Spring 的容器,都能够在启动时接管它们。在开始时,容器通过调用 init() 办法来实例化 servlet。初始化实现后,servlet 就能够承受传入的申请。随后,容器将这些申请定向到 servlet 的 service 办法中进行解决。之后,它依据HTTP申请类型将申请进一步委托给适当的办法,例如 doGet() 或 doPost() 。 应用 destroy(),容器会销毁 servlet,并且不再承受传入的申请。咱们将这个 init-service-destroy 的循环称为 servlet 的生命周期。 当初咱们从容器的角度来看,比方 Apache Tomcat 或 Jetty 在启动时,创立一个 ServletContext 的对象,ServletContext 的工作是充当服务器或容器的内存,并记住与web应用程序相关联的所有servlet、过滤器和侦听器,如其 web.xml文件或等效注解。在容器进行之前,ServletContext 会始终保留它。 不管怎么说,servlet的 load-on-startup 参数表演重要的角色 。如果此参数的值大于零,则只有在启动时服务器才会对其进行初始化。如果未指定此参数,则在申请第一次命中 servlet时调用它的 init()。 3. Request, Response 和 Session在上一节中,咱们探讨了发送申请和接管响应,这基本上是任何CS应用程序的根底。当初,咱们从servlet的角度来具体理解它们。 在这种状况下,申请将由 HttpServletRequest 示意,响应将用 HttpServletResponse 示意。 ...

December 18, 2020 · 1 min · jiezi

关于spring:3-搞定收工PropertyEditor就到这

分享、成长,回绝浅藏辄止。搜寻公众号【BAT的乌托邦】,回复关键字专栏有Spring技术栈、中间件等小而美的原创专栏供以收费学习。本文已被 https://www.yourbatman.cn 收录。 ✍前言你好,我是YourBatman。 上篇文章介绍了PropertyEditor在类型转换里的作用,以及举例说明了Spring内置实现的PropertyEditor们,它们各司其职实现 String <-> 各种类型 的互转。 在通晓了这些基础知识后,本文将更进一步,为你介绍Spring是如何注册、治理这些转换器,以及如何自定义转换器去实现公有转换协定。 版本约定Spring Framework:5.3.1Spring Boot:2.4.0✍注释略微相熟点Spring Framework的小伙伴就晓得,Spring特地善于API设计、模块化设计。后缀模式是它罕用的一种管理手段,比方xxxRegistry注册核心在Spring外部就有十分多:xxxRegistry用于治理(注册、批改、删除、查找)一类组件,当组件类型较多时应用注册核心对立治理是一种十分无效的伎俩。诚然,PropertyEditor就属于这种场景,治理它们的注册核心是PropertyEditorRegistry。 PropertyEditorRegistry它是治理PropertyEditor的核心接口,负责注册、查找对应的PropertyEditor。 // @since 1.2.6public interface PropertyEditorRegistry { // 注册一个转换器:该type类型【所有的属性】都将交给此转换器去转换(即便是个汇合类型) // 成果等同于调用下办法:registerCustomEditor(type,null,editor); void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor); // 注册一个转换器:该type类型的【propertyPath】属性将交给此转换器 // 此办法是重点,详解见下文 void registerCustomEditor(Class<?> requiredType, String propertyPath, PropertyEditor propertyEditor); // 查找到一个适合的转换器 PropertyEditor findCustomEditor(Class<?> requiredType, String propertyPath); }阐明:该API是1.2.6这个小版本新增的。Spring 个别 不会在小版本里新增外围API以确保稳定性,但这并非100%。Spring认为该API对使用者无感的话(你不可能会用到它),增/减也是有可能的此接口的继承树如下: 值得注意的是:尽管此接口看似实现者泛滥,但其实其它所有的实现对于PropertyEditor的治理局部都是委托给PropertyEditorRegistrySupport来治理,无一例外。因而,本文只需关注PropertyEditorRegistrySupport足矣,这为前面的高级利用(如数据绑定、BeanWrapper等)打好坚实基础。 用不太正确的了解可这么认为:PropertyEditorRegistry接口的惟一实现只有PropertyEditorRegistrySupportPropertyEditorRegistrySupport它是PropertyEditorRegistry接口的实现,提供对default editors和custom editors的治理,最终次要为BeanWrapperImpl和DataBinder服务。 一般来说,Registry注册核心外部会应用多个Map来保护,代表注册表。此处也不例外: // 装载【默认的】编辑器们,初始化的时候会注册好private Map<Class<?>, PropertyEditor> defaultEditors;// 如果想笼罩掉【默认行为】,可通过此Map笼罩(比方解决Charset类型你不想用默认的编辑器解决)// 通过API:overrideDefaultEditor(...)放进此Map里private Map<Class<?>, PropertyEditor> overriddenDefaultEditors;// ======================注册自定义的编辑器======================// 通过API:registerCustomEditor(...)放进此Map里(若没指定propertyPath)private Map<Class<?>, PropertyEditor> customEditors;// 通过API:registerCustomEditor(...)放进此Map里(若指定了propertyPath)private Map<String, CustomEditorHolder> customEditorsForPath;PropertyEditorRegistrySupport应用了4个 Map来保护不同起源的编辑器,作为查找的 “数据源”。这4个Map可分为两大组,并且有如下法则: ...

December 17, 2020 · 3 min · jiezi

关于spring:JVM的艺术JAVA内存模型

喜爱文章,动动手指导个赞 引言敬爱读者你们好,对于jvm篇章的连载,后面三章讲了类加载器,本篇文章将进入jvm畛域的另一个知识点,java内存模型。彻底的理解java内存模型,是有必要的。只有把握了java的内存模型,内存空间分为哪些区域,能力更好地了解,java是如何创建对象以及如何调配对象的空间。对后续的jvm调优打下松软的根底。而对于当初的互联网行业来说,高并发,高可用曾经必不可少,而学好jvm调优,不仅能在企业工作当中针对高并发场景下的零碎进行优化,在日常对系统的谬误排查、零碎的优化也起着至关重要的作用。心愿这篇文章能让各位读者学到真正的本事。同时也感激大家的继续关注和认可。 一:JDK体系结构 JDK、JRE、JVM之间的关系JDK:Java Development Kit(java开发工具包),蕴含JRE和开发工具包,例如javac、javah(生成实现本地办法所需的 C 头文件和源文件)。JRE:Java Runtime Environment(java运行环境),蕴含JVM和类库。JVM:Java Virtual Machine(Java虚拟机),负责执行符合规范的Class文件。 Java语言的跨平台个性 JVM所处的地位 (1)通常工作中所接触的根本是Java库和利用以及Java外围类库,晓得如何应用就能够了,然而归根结底代码都是要编译成class文件由Java虚拟机装载执行,所产生的后果或者景象都能够通过Java虚拟机的运行机制来解释。一些雷同的代码会因为虚拟机的实现不同而产生不同后果。 (2)在Java平台的构造中,能够看出,Java虚拟机(JVM)处在外围的地位,是程序与底层操作系统和硬件无关的要害。它的下方是移植接口,移植接口由两局部组成:适配器和Java操作系统,其中依赖于平台的局部称为适配器;JVM通过移植接口在具体的平台和操作系统上实现;在JVM的上方是Java的根本类库和扩大类库以及它们的API, 利用Java API编写的应用程序(application)和小程序(Java applet)能够在任何Java平台上运行而无需思考底层平台,就是因为有Java虚拟机(JVM)实现了程序与操作系统的拆散,从而实现了Java的平台无关性。 (3)对JVM标准的的形象阐明是一些概念的汇合,它们曾经在书《The Java Virtual Machine Specification》(《Java虚拟机标准》)中被具体地形容了;对JVM的具体实现要么是软件,要么是软件和硬件的组合,它曾经被许多生产厂商所实现,并存在于多种平台之上;运行Java程序的工作由JVM的运行期实例单个承当。 (4)JVM能够由不同的厂商来实现。因为厂商的不同必然导致JVM在实现上的一些不同,像国内就有驰名的TaobaoVM;然而JVM还是能够实现跨平台的个性,这就要归功于设计JVM时的体系结构了。 (5)JVM在它的生存周期中有一个明确的工作,那就是装载字节码文件,一旦字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有抉择的转换成机器码执行,即Java程序被执行。因而当Java程序启动的时候,就产生JVM的一个实例;当程序运行完结的时候,该实例也跟着隐没了。 Class字节码编译后被Java虚拟机所执行的代码应用了一种平台中立(不依赖于特定硬件及操作系统的)的二进制格局来示意,并且常常(但并非相对)以文件的模式存储,因而这种格局被称为Class文件格式。Class文件格式中准确地定义了类与接口的示意模式,包含在平台相干的指标文件格式中一些细节上的常规,正如概念所说,Java为了可能实现平台无关性,制订了一套本人的二进制格局,并常常以文件的形式存储,称为Class文件。这样在不同平台上,只有都装置了Java虚拟机,具备Java运行环境[JRE],那么都能够运行雷同的Class文件。 上图形容了Java程序运行的一个全过程,也能够看出Java平台由Java虚拟机和Java利用程序接口搭建,Java语言则是进入这个平台的通道,用Java语言编写并编译的程序能够运行在这个平台上。由Java源文件编译生成字节码文件,这个过程非常复杂,学过《编译原理》的敌人都晓得必须通过词法剖析、语法分析、语义剖析、两头代码生成、代码优化等;同样的,Java源文件到字节码的生成也想要经验这些步骤。Javac编译器的最初工作就是调用con.sun.tools.javac.jvm.Gen类将这课语法树编译为Java字节码文件。其实,所谓的编译字节码,无非就是将合乎Java语法标准的Java代码转化为合乎JVM标准的字节码文件。JVM的架构模型是基于栈的,大部分都须要通过栈来实现。字节码构造比拟非凡,其外部不蕴含任何的分隔符,无奈人工辨别段落(字节码文件自身就是给机器读的),所以无论是字节程序、数量都是有严格规定的,所有16位、32位、64位长度的数据都将结构成2个、4个、8个-----8位字节单位来示意,多字节数据项总是依照Big-endian程序(高位字节在地址的最低位,位置字节在地址的最高位)来进行存储。参考《Java虚拟机标准 Java SE7版》的形容,每一个字节码其实都对应着全局惟一的一个类或者接口的定义信息。字节码文件才用的是一种相似于C语言构造体的伪构造来形容字节码文件格式。字节码文件中对应的“根本类型”u1,u2,u4,u8别离示意无符号1、2、4、8个字节。 Class文件----总体格局 值得一提的是,一个无效的class字节码文件的前4个字节为0xCAFEBABE,都是固定的,被称为“魔术”,即magic。它就是JVM用于校验所读取的指标文件是否是一个无效且非法的字节码文件。由此可见,JVM并不是通过判断文件后缀名的形式来校验,以避免人为手动批改。 JVM底层架构图 下面这张图,是自己花了很多心理总结进去的,根本涵盖了java内存模型的构造。明天奉上。这篇文章会把下面这张图讲清楚。 运行时数据区:1,堆Java堆在虚拟机启动的时候被创立,Java堆次要用来为类实例对象和数组分配内存。Java虚拟机标准并没有规定对象在堆中的模式。在Java中,堆被划分成两个不同的区域:新生代( Young )、老年代( Old );这也就是JVM采纳的“分代收集算法”,简略说,就是针对不同特色的java对象采纳不同的 策略施行寄存和回收,天然所用分配机制和回收算法就不一样。新生代( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。 分代收集算法:采纳不同算法解决[寄存和回收]Java刹时对象和短暂对象。大部分Java对象都是刹时对象,朝生夕灭,存活很短暂,通常寄存在Young新生代,采纳复制算法对新生代进行垃圾回收。老年代对象的生命周期个别都比拟长,极其状况下会和JVM生命周期保持一致;通常采纳标记-压缩算法对老年代进行垃圾回收。这样划分的目标是为了使JVM可能更好的治理堆内存中的对象,包含内存的调配以及回收。 Java堆可能产生如下异常情况:如果理论所需的堆超过了主动内存管理系统能提供的最大容量,那Java虚拟机将会抛出一个OutOfMemoryError异样。简称(OOM)。 堆大小 = 新生代 + 老年代。堆的大小可通过参数–Xms(堆的初始容量)、-Xmx(堆的最大容量) 来指定。 其中,新生代 ( Young ) 被细分为 Eden 和 两个 Survivor 区域,这两个 Survivor 区域别离被命名为 from 和 to,以示辨别。默认的,Edem : from : to = 8 : 1 : 1 。(能够通过参数 –XX:SurvivorRatio 来设定 。 ...

December 17, 2020 · 2 min · jiezi

关于spring:Spring-源码学习-07ClassPathBeanDefinitionScanner

前言AnnotationConfigApplicationContext 构造函数除了初始化一个 reader ,还有一个 scanner,上面来一起看看 ClassPathBeanDefinitionScanner 都有什么逻辑。 源码剖析this.scanner = new ClassPathBeanDefinitionScanner(this); 代码如下所示: 其中 useDefaultFilters 默认设置的 true。所以最终会执行上面三局部代码: registerDefaultFilters();setEnvironment(environment);setResourceLoader(resourceLoader); 再来看下 UML : ClassPathBeanDefinitionScanner 继承了 ClassPathScanningCandidateComponentProvider,而下面说的这三个办法,其实都是父类 ClassPathScanningCandidateComponentProvider 的办法。 对应的这三个操作就是给它的参数赋值: registerDefaultFilters 本步骤次要是增加过滤器,对 includeFilters 赋值。 注册过滤器 @Component,@Controller @Service、 @Repository 也会被增加进去。 也会注册增加 JSR-250 的 @ManagedBean 和 JSR-330 的 @Named 注解。 setEnvironment setResourceLoader setEnvironment 和 setResourceLoader 赋值操作,基本上如代码所示。 总结 这一步次要是初始化类扫描器,在它初始化的时候,会初始化一些须要被扫描的注解,以及资源加载器。 到此,无参结构曾经执行结束。总结一下,这两局部别离是初始化默认的处理器,以及初始化类扫描器,资源加载器。 相干举荐Spring 源码学习 06:AnnotatedBeanDefinitionReaderSpring 源码学习 05:BeanDefinition 概念及其实现Spring 源码学习 04:初始化容器与 DefaultListableBeanFactory

December 15, 2020 · 1 min · jiezi

关于spring:SpEL表达式

1、SpEL表达式从spring3开始引入了spring表达式语言,它可能以一种弱小而间接的形式将值拆卸到Bean属性和结构器参数中,再这个过程中所应用的表达式会在运行时计算失去值。应用SpEL能够实现超乎设想的拆卸成果,这是其余拆卸技术很难做到的。SpEL个性如下应用bean的ID来援用bean;应用办法和拜访对象的属性;对值进行算数、关系和逻辑运算;正则表达式匹配;汇合操作。SpEL表达式要放到“#{...}”中 2、用法SpEL有三种用法,一种是在注解@Value中;一种是XML配置;最初一种是在代码块中应用Expression。 2.1 @Value  //@Value能润饰成员变量和办法形参 //#{}内就是表达式的内容 @Value("#{表达式}") public String arg;如果润饰成员变量,是从Spring容器中依照SpEL表达式筛选批改数据后,赋值给所润饰的变量;如果润饰办法形参,则是过滤传进来的参数值。 <bean>配置<bean id="xxx" class="com.java.XXXXX.xx"> <!-- 同@Value,#{}内是表达式的值,可放在property或constructor-arg内 --><property name="arg" value="#{表达式}"></bean> 用法跟注解@ Value润饰形参相似  Expression ; "复制代码") import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; public class SpELTest { public static void main(String[] args) { //创立ExpressionParser解析表达式 ExpressionParser parser = new SpelExpressionParser(); //表达式搁置 Expression exp = parser.parseExpression("表达式"); //执行表达式,默认容器是spring自身的容器:ApplicationContext Object value = exp.getValue(); /**如果应用其余的容器,则用上面的办法*/ //创立一个虚构的容器EvaluationContext StandardEvaluationContext ctx = new StandardEvaluationContext(); //向容器内增加bean BeanA beanA = new BeanA(); ctx.setVariable("bean_id", beanA); //setRootObject并非必须;一个EvaluationContext只能有一个RootObject,援用它的属性时,能够不加前缀ctx.setRootObject(XXX); //getValue有参数ctx,从新的容器中依据SpEL表达式获取所需的值 ...

December 15, 2020 · 2 min · jiezi

关于spring:Spring源码分析之AOP从解析到调用

注释: 在上一篇,咱们对IOC外围局部流程曾经剖析结束,置信小伙伴们有所播种,从这一篇开始,咱们将会踏上新的旅程,即Spring的另一外围:AOP! 首先,为了让大家能更无效的了解AOP,先带大家过一下AOP中的术语: 切面(Aspect):指关注点模块化,这个关注点可能会横切多个对象。事务管理是企业级Java利用中无关横切关注点的例子。在Spring AOP中,切面能够应用在一般类中以@Aspect注解来实现。连接点(Join point):在Spring AOP中,一个连接点总是代表一个办法的执行,其实就代表加强的办法。告诉(Advice):在切面的某个特定的连接点上执行的动作。告诉有多种类型,包含around, before和after等等。许多AOP框架,包含Spring在内,都是以拦截器做告诉模型的,并保护着一个以连接点为核心的拦截器链。指标对象(Target):指标对象指将要被加强的对象。即蕴含主业务逻辑的类的对象。切点(Pointcut):匹配连接点的断言。告诉和切点表达式相关联,并在满足这个切点的连接点上运行(例如,当执行某个特定名称的办法时)。切点表达式如何和连接点匹配是AOP的外围:Spring默认应用AspectJ切点语义。参谋(Advisor): 参谋是Advice的一种包装体现,Advisor是Pointcut以及Advice的一个联合,用来治理Advice和Pointcut。织入(Weaving):将告诉切入连接点的过程叫织入引入(Introductions):能够将其余接口和实现动静引入到targetClass中一个栗子术语看完了,咱们先上个Demo回顾一下吧~ 首先,应用EnableAspectJAutoProxy注解开启咱们的AOP @ComponentScan(basePackages = {"com.my.spring.test.aop"})@Configuration@EnableAspectJAutoProxypublic class Main { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class); IService service = context.getBean("service", IService.class); service.doService(); }}写一个接口 public interface IService { void doService();}写一个实现类 @Service("service")public class ServiceImpl implements IService{ @Override public void doService() { System.out.println("do service ..."); }}写一个切面 @Aspect@Componentpublic class ServiceAspect { @Pointcut(value = "execution(* com.my.spring.test.aop.*.*(..))") public void pointCut() { } @Before(value = "pointCut()") public void methodBefore(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("执行指标办法 【" + methodName + "】 的【前置告诉】,入参:" + Arrays.toString(joinPoint.getArgs())); } @After(value = "pointCut()") public void methodAfter(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("执行指标办法 【" + methodName + "】 的【后置告诉】,入参:" + Arrays.toString(joinPoint.getArgs())); } @AfterReturning(value = "pointCut()") public void methodReturn(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("执行指标办法 【" + methodName + "】 的【返回告诉】,入参:" + Arrays.toString(joinPoint.getArgs())); } @AfterThrowing(value = "pointCut()") public void methodThrow(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("执行指标办法 【" + methodName + "】 的【异样告诉】,入参:" + Arrays.toString(joinPoint.getArgs())); }}测试运行 ...

December 14, 2020 · 9 min · jiezi

关于spring:配置-Spring-Batch-批处理失败重试机制

1. 引言默认状况下,Spring批处理作业在执行过程中呈现任何谬误都会失败。然而有些时候,为了进步应用程序的弹性,咱们就须要解决这类间歇性的故障。在这篇短文中,咱们就来一起探讨 如何在Spring批处理框架中配置重试逻辑。 2. 简略举例假如有一个批处理作业,它读取一个CSV文件作为输出: username, userid, transaction_date, transaction_amountsammy, 1234, 31/10/2015, 10000john, 9999, 3/12/2015, 12321而后,它通过拜访REST端点来解决每条记录,获取用户的 age 和 postCode 属性: public class RetryItemProcessor implements ItemProcessor<Transaction, Transaction> { @Override public Transaction process(Transaction transaction) throws IOException { log.info("RetryItemProcessor, attempting to process: {}", transaction); HttpResponse response = fetchMoreUserDetails(transaction.getUserId()); //parse user's age and postCode from response and update transaction ... return transaction; } ...}最初,它生成并输入一个合并的XML: <transactionRecord> <transactionRecord> <amount>10000.0</amount> <transactionDate>2015-10-31 00:00:00</transactionDate> <userId>1234</userId> <username>sammy</username> <age>10</age> <postCode>430222</postCode> </transactionRecord> ...</transactionRecord> ...

December 11, 2020 · 2 min · jiezi

关于spring:05SpringBoot工程中的MyBatis框架的整合实现及原理分析

整合MyBatis的初步剖析概述Mybatis是一个优良的长久层框架,底层基于JDBC实现与数据库的交互。并在JDBC操作的根底上做了封装和优化,它借助灵便的SQL定制,参数及后果集的映射形式,更好的适应了以后互联网技术的倒退。Mybatis框架的简略利用架构如图所示:在当今的互联网利用中我的项目,mybatis框架通常会由spring框架进行资源整合,作为数据层技术实现数据交互操作。 筹备工作第一步:创立我的项目module,例如: 第二步:增加依赖 mysql 驱动依赖 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope></dependency>spring jdbc 依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId></dependency>mybatis starter依赖 <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version></dependency> 第二步:application.properties 配置文件中增加繁难配置 连接池配置 spring.datasource.url=jdbc:mysql:///dbgoods?serverTimezone=GMT%2B8&characterEncoding=utf8spring.datasource.username=rootspring.datasource.password=rootmybatis配置 mybatis.mapper-locations=classpath:/mapper/*/*.xml环境测试代码实现在src/test/java目录中增加测试类,对mybatis框架整合进行根本测试,代码如下: package com.cy.pj.goods.dao;import java.sql.Connection;import org.apache.ibatis.session.SqlSession;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;@SpringBootTestpublic class MyBatisTests { @Autowired private SqlSession sqlSession; @Test public void testGetConnection() { Connection conn=sqlSession.getConnection(); System.out.println("connection="+conn); }}在SpringBoot脚手架工程中,Spring框架会基于MyBatis框架底层配置,创立SqlSessionFactory对象,而后再通过此工厂对象创立SqlSession,最初基于Springku框架为测试类注入SqlSession对象,接下来,咱们能够通过SqlSession对象实现与数据库的会话了。 整合MyBatis业务代码实现及原理剖析业务形容基于SpringBoot脚手架工程对MyBatis框架的整合,实现对商品库中商品数据的查问业务。 API架构设计 业务时序图剖析 业务代码设计及实现第一步:定义商品模块POJO对象类型(基于此对象存储商品数据),代码如下: package com.cy.pj.goods.pojo;import java.util.Date;/**用于存储商品信息的pojo对象*/public class Goods { private Long id; private String name; private String remark; private Date createdTime; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public Date getCreatedTime() { return createdTime; } public void setCreatedTime(Date createdTime) { this.createdTime = createdTime; }}第二步:定义商品模块长久层对象GoodsDao接口及办法映射,代码如下 ...

December 9, 2020 · 2 min · jiezi

关于spring:2-Spring早期类型转换基于PropertyEditor实现

青年时种下什么,老年时就播种什么。关注公众号【BAT的乌托邦】,有Spring技术栈、MyBatis、JVM、中间件等小而美的原创专栏供以收费学习。分享、成长,回绝浅尝辄止。本文已被 https://www.yourbatman.cn 收录。 ✍前言你好,我是YourBatman。 Spring早在1.0(2004年公布,2003年孵化中)的时候,就有了类型转换功能模块。此模块存在的必要性不用多说,置信每个同学都可了解。最后,Spring做类型转换器是基于Java规范的java.beans.PropertyEditor这个API去扩大实现的,直到Spring 3.0后才得以呈现更好代替计划(Spring 3.0公布于2009 年12月)。 提醒:文章开端附有Spring次要版本的公布工夫和以及次要个性,感兴趣者可文末查看虽说Spring自3.0就提出了更为灵便、优良的类型转换接口/服务,然而晚期基于PropertyEditor实现的转换器并未废除且还在发挥余热中,因而本文就针对其晚期类型转换实现做出专文解说。 版本约定Spring Framework:5.3.1Spring Boot:2.4.0阐明:版本均于2020-11公布,且版本号均不带有.RELEASE后缀,这和之前是不一样的。具体起因请参考:Spring扭转版本号命名规定:此举对非英语国家很敌对✍注释若你用当下的眼光去看Spring基于PropertyEditor的类型转换实现,会发现这么搞是存在一些设计缺点的。当然并不能这么去看,毕竟当初都2020年了,那会才哪跟哪呢。既然Spring里的PropertyEditor现如今仍然健在,那咱就会会它呗。 PropertyEditor是什么?PropertyEditor位于java.beans包中,要晓得这个包外面的类都是设计为Java GUI程序(AWT)服务的,所以你看官网javadoc对PropertyEditor的介绍也无出其右: A PropertyEditor class provides support for GUIs that want to allow users to edit a property value of a given type.为GUI程序提供反对,容许你对给定的value进行编辑,作用相似于一个转换器:GUI上你能够输出、编辑某个属性而后通过它转换成适合的类型。 此接口提供的办法挺多的,和本文类型转换无关的最多只有4个: void setValue(Object value):设置属性值Object getValue():获取属性值String getAsText():输入。把属性值转换成String输入void setAsText(String text):输出。将String转换为属性值类型输出JDK对PropertyEditor接口提供了一个默认实现java.beans.PropertyEditorSupport,因而咱们若需扩大此接口,仅需继承此类,依据须要复写getAsText/setAsText这两个办法即可,Spring无一例外都是这么做的。 PropertyEditor作为一个JDK原生接口,内置了一些根本实现来服务于GUI程序,如: BooleanEditor:将true/false字符串转换为Boolean类型IntegerEditor:将字符串转换为Integer类型 同类别的还有LongEditor、FloatEditor...JDK内置的实现比拟少(如上),性能简陋,但对于服务GUI程序来说曾经够用,毕竟界面输出的只可能是字符串,并且还均是根底类型。但这对于简单的Spring环境、以及富文本的web环境来说就不够用了,所以Spring在此基础上有所扩大,因而才有了本文来探讨。 留神:PropertyEditorSupport线程不平安PropertyEditor实现的是双向类型转换:String和Object互转。调用setValue()办法后,须要先“缓存”起来后续才可能应用(输入)。PropertyEditorSupport为此提供了一个成员属性来做: PropertyEditorSupport: // 调用setValue()办法对此属性赋值 getValue()办法取值 private Object value;这么一来PropertyEditorSupport就是有状态的了,因而是线程不平安的。在应用过程中须要特地留神,避免出现并发危险。 阐明:Support类里还看到属性监听器PropertyChangeListener,因它属于GUI程序应用的组件,与咱们无关,所以后续丝毫不会提及哦Spring内置的所有扩大均是基于PropertyEditorSupport来实现的,因而也都是线程不平安的哦~ Spring为何基于它扩大?官网的javadoc都说得很分明:PropertyEditor设计是为GUI程序服务的,那么Spring为何看上它了呢? 试想一下:那会的Spring只能反对xml形式配置,而XML属于文本类型配置,因而在给某个属性设定值的时候,书写下来的100%是个字符串,然而此属性对应的类型却不肯定是字符串,可能是任意类型。你思考下,这种场景是不是跟GUI程序(AWT)一毛一样:输出字符串,对应任意类型。 为了实现这种需要,在PropertyEditorSupport的根底上只须要复写setAsText和getAsText这两个办法就行,而后Spring就这么干了。我集体yy一下,当初Spring抉择这么干而没本人重整旗鼓的起因可能有这么几个: 本着不反复创造轮子的准则,有得用就间接用呗,况且是100%满足要求的示好Java EE技术。毕竟那会Spring位置还并不稳,有大腿就先榜上2003年左右,Java GUI程序还并未退出历史舞台,Spring为了通用性就抉择基于它扩大喽 阐明:那会的通用性可能和当初通用性含意上是不一样的,须要稍作区别Spring内建扩大实现有哪些?Spring为了扩大本身性能,进步配置灵活性,扩大出了十分十分多的PropertyEditor实现,共计40余个,局部截图如下: PropertyEditor性能举例ZoneIdEditor转为java.time.ZoneIdAsia/ShanghaiURLEditor转为URL,反对传统形式file:,http:,也反对Spring格调:classpath:,context上下文相对路径等等http://www.baidu.comStringTrimmerEditortrim()字符串,也可删除指定字符char任意字符串StringArrayPropertyEditor转为字符串数组A,B,CPropertiesEditor转为Propertiesname = YourBatmanPatternEditor转为Pattern(\D)(\d+)(.)PathEditor转为java.nio.file.Path。反对传统URL和Spring格调的urlclasspath:xxxClassEditor转为Class全类名CustomBooleanEditor转为Boolean见示例CharsetEditor转为Charset见示例CustomDateEditor转为java.util.Date见示例Spring把实现根本(大多数)都放在org.springframework.beans.propertyeditors包下,接下来我筛选几个代表性API举例说明。 规范实现示例CustomBooleanEditor:@Testpublic void test1() { PropertyEditor editor = new CustomBooleanEditor(true); // 这些都是true,不辨别大小写 editor.setAsText("trUe"); System.out.println(editor.getAsText()); editor.setAsText("on"); System.out.println(editor.getAsText()); editor.setAsText("yes"); System.out.println(editor.getAsText()); editor.setAsText("1"); System.out.println(editor.getAsText()); // 这些都是false(留神:null并不会输入为false,而是输入空串) editor.setAsText(null); System.out.println(editor.getAsText()); editor.setAsText("fAlse"); System.out.println(editor.getAsText()); editor.setAsText("off"); System.out.println(editor.getAsText()); editor.setAsText("no"); System.out.println(editor.getAsText()); editor.setAsText("0"); System.out.println(editor.getAsText()); // 报错 editor.setAsText("2"); System.out.println(editor.getAsText());}关注点:对于Spring来说,传入的true、on、yes、1等都会被“翻译”成true(字母不辨别大小写),大大提高兼容性。 ...

December 8, 2020 · 1 min · jiezi

关于spring:04SpringBoot工程下如何实现对HikariCP连接池的整合

池化思维剖析池化思维是咱们我的项目开发过程中的一种十分重要的思维,如整数池,字符串池,对象池、连接池、线程池等都是池化思维的一种利用,都是通过复用对象,以缩小因创立和开释对象所带来的资源耗费,进而来晋升零碎性能。例如Integer对象的外部池利用,代码如下: package com.cy.java.pool;public class TestInteger01 { public static void main(String[] args) { Integer n1=100;//Integer.valueOf(100) 编译时优化 Integer n2=100; Integer n3=200; Integer n4=200;//池中没有则new Integer(200) System.out.println(n1==n2);//true System.out.println(n3==n4);//false } }数据库连接池简介背景剖析目开发过程中应用程序与数据库交互时,“取得连贯”或“开释连贯”是十分耗费系统资源的两个过程,频繁地进行数据库连贯的建设和敞开会极大影响零碎的性能,若多线程并发量很大,这样耗时的数据库连贯就可能让零碎变得卡顿。因为TCP连贯的创立开销非常低廉,并且数据库所能承载的TCP并发连接数也有限度,针对这种场景,数据库连接池应运而生。如下图所示: 思考:如果当初是让你去设计一个连接池,你会从什么角度进行设计?第一:物理存储构造(基于什么构造去存储数据)第二:基于什么算法从池中取连贯?第三:基于什么算法从池中移除连贯?第四:当池中没有连贯时,基于什么形式解决连贯申请?第五:池是能够共享,咱们须要思考池在拜访的时并发平安? 连接池原理剖析在零碎初始化的时候,在内存中开拓一片空间,将肯定数量的数据库连贯作为对象存储在对象池里,并对外提供数据库连贯的获取和偿还办法。用户拜访数据库时,并不是建设一个新的连贯,而是从数据库连接池中取出一个已有的闲暇连贯对象;应用结束偿还后的连贯也不会马上敞开,而是由数据库连接池对立治理回收,为下一次借用做好筹备。如果因为高并发申请导致数据库连接池中的连贯被借用结束,其余线程就会期待,直到有连贯被偿还。整个过程中,连贯并不会敞开,而是源源不断地循环应用,有借有还。数据库连接池还能够通过设置其参数来管制连接池中的初始连接数、连贯的上上限数,以及每个连贯的最大应用次数、最大闲暇工夫等,也能够通过其本身的管理机制来监督数据库连贯的数量、应用状况等。 Java中的连接池Java官网,为了在应用程序中更好的利用连接池技术,定义了一套数据源标准,例如javax.sql.DataSource接口,基于这个接口,很多团队或集体创立了不同的连接池对象。而后咱们的应用程序中通过耦合与DataSource接口,便能够不便的切换不同厂商的连接池。Java我的项目中通过连接池获取连贯的一个根本过程,如下图所示: 在上图中,用户通过DataSource对象的getConnection()办法,获取一个连贯。如果池中有连贯,则间接将连贯返回给用户。如果池中没有连贯,则会调用Dirver(驱动,由数据库厂商进行实现)对象的connect办法从数据库获取,拿到连贯当前,能够将连贯在池中放一份,而后将连贯返回给调用方。连贯需求方再次须要连贯时,能够从池中获取,用完当前再还给池对象。 数据库连接池在Java数据库相干中间件产品群中,应该算是底层最根底的一类产品,作为企业应用开发必不可少的组件,有数蠢才们为咱们奉献了一个又一个的优良产品,它们有的随时代倒退,功成身退,有的则还在一直迭代,老而弥坚,更有新生代产品,或性能无敌,或性能全面。目前市场上常见的连接池有DBCP、C3P0,DRUID,HikariCP等。SpringBoot工程下HikariCP整合测试数据初始化关上mysql控制台,而后按如下步骤执行goods.sql文件。第一步:登录mysql。 mysql –uroot –proot第二步:设置控制台编码方式。 set names utf8;第三步:执行goods.sql文件(切记不要关上文件复制到mysql客户端运行)。 source d:/goods.sql其中goods.sql文件内容如下: drop database if exists dbgoods;create database dbgoods default character set utf8;use dbgoods;create table tb_goods( id bigint primary key auto_increment, name varchar(100) not null, remark text, createdTime datetime not null)engine=InnoDB;insert into tb_goods values (null,'java','very good',now());insert into tb_goods values (null,'mysql','RDBMS',now());insert into tb_goods values (null,'Oracle','RDBMS',now());insert into tb_goods values (null,'java','very good',now());insert into tb_goods values (null,'mysql','RDBMS',now());insert into tb_goods values (null,'Oracle','RDBMS',now());insert into tb_goods values (null,'java','very good',now());创立我的项目Module并增加相干依赖第一步:基于IDEA创立我的项目Module,如图所示: ...

December 8, 2020 · 2 min · jiezi

关于spring:Java-8-中的方法引用轻松减少代码量提升可读性

1. 引言Java8中最受宽广开发中喜爱的变动之一是因为引入了 lambda 表达式,因为这些表达式容许咱们放弃匿名类,从而大大减少了样板代码,并进步了可读性。办法援用是lambda表达式的一种非凡类型。它们通常通过援用现有办法来创立简略的lambda表达式。 办法援用包含以下四种类型: 静态方法特定对象的实例办法特定类型的任意对象的实例办法构造方法在本篇文章中,咱们将探讨Java中的办法援用。 2. 援用静态方法We'll begin with a very simple example, capitalizing and printing a list of Strings: 咱们从一个非常简单的示例开始,字符串转成大写并打印: List<String> messages = Arrays.asList("hello", "baeldung", "readers!");咱们能够通过简略的lambda表达式间接调用 StringUtils.capitalize() 办法: messages.forEach(word -> StringUtils.capitalize(word));或者,咱们能够应用办法援用来简略地援用 capitalize 静态方法: messages.forEach(StringUtils::capitalize);留神,办法援用应应用::运算符。 3. 援用特定对象的实例办法为了演示这种类型的办法援用,咱们新建以下这两个类: public class Bicycle { private String brand; private Integer frameSize; // standard constructor, getters and setters} public class BicycleComparator implements Comparator { @Override public int compare(Bicycle a, Bicycle b) { return a.getFrameSize().compareTo(b.getFrameSize()); } }创立一个 BicycleComparator 对象来比拟自行车尺寸: ...

December 8, 2020 · 1 min · jiezi

关于spring:云计算交付模型知多少-IaaSPaaSSaaS

对于互联网公司而言,迁徙到云是一个理智的决定。它缩小了总的老本收入,同时最大限度地进步了工作效率和生产率,本文将指出迁徙到云或者建设公有云优缺点以及边界在哪里?1、什么是云计算云计算(cloud computing)是分布式计算的一种,指的是通过网络“云”将微小的数据计算处理程序分解成无数个小程序,而后,通过多部服务器组成的零碎进行解决和剖析这些小程序失去后果并返回给用户。 本地通常是提前把软件基础架构部署在用户计算机上,所有资源使用者本人拜访和治理; 绝对于本地服务,云有以下特色: 按需服务-须要时应用;网络拜访-通过网络作为传输媒介,云提供商负责保护其基础架构;资源共享-多个资源集中在一起,供多个客户端应用;可伸缩性-资源具备弹性能力,最大水平节俭和进步资源利用率,具备平台无关性、存储有限扩大等劣势。2、私有云的毛病在哪里?云是公共资源,每秒都无数以百万的用户拜访,云服务提供商可能蒙受攻打,从而窃取用户信息,从而云在肯定水平上存在平安问题。数据存储在第三方机器,可能会呈现第三方查看和批改用户隐衷数据问题。更多的控制权不在于本人,而在于云提供商,云呈现问题,只能期待第三方回应。云自身又分为私有云、公有云、混合云等,以上说的几点都是私有云的特点,很多企业不信赖私有云平台,特地是国内很多企业要求对技术做到自主可控,联合自身的业务增长速度,须要搭建本人的公有云平台。那么要实现公有云平台搭建,须要实现什么工作呢?如图(a) (a) 3、搭建企业级云平台须要实现哪些工作?3.1、IaaS 基础架构即服务IaaS 基础架构即服务,该服务提供了计算机体系架构和根底服务,提供了所有云计算资源供咱们间接拜访应用,比方数据存储、虚拟化服务、服务器和网络等。 应用对象:企业管理员。长处:云提供了基础架构和服务、加强了可扩展性、动静按需扩大。 毛病:集群规模增大后会呈现平安问题和网络服务提早。 3.2、PaaS 平台即服务PaaS 次要是提供开发环境/平台,编程语言、操作系统、web 服务器和数据库形成,用户可在其中构建、编译、运行程序无需放心其基础架构。当今面对互联网业务量和用户量剧增,PaaS 是企业须要着重建设的局部。很多企业都以 Kubernetes 为根底建设容器云平台。常见的私有云有有阿里云,腾讯云、亚马逊云等。 应用对象:开发人员。长处:疾速开发部署、弹性扩容、继续交付。 毛病:开发人员仅限于应用PaaS提供的语言和工具,如果后期应用裸金属服务器部署,前期迁徙到云,可能会有肯定难度和适应期。 3.3、SaaS 软件即服务按需应用软件、按需付费。跟购买程序无关,该服务运行在云端,是平台无关的,无需在 PC 上装置软件。云端运行该服务一个或多个实例供多个最终用户应用,云计算大大降低企业软件运行老本。比方网盘、网上冲浪服务等。 应用对象:用户。长处:能够通过任何平台拜访、无需关怀在什么网络环境。非常适合协同办公。 毛病:云服务是面对所有用户,比方:浏览器兼容性可能导致不能应用某些服务。 3.4、PaaS VS IaaS在云平台建设过程中 PaaS 和 IaaS 边界在哪里呢?很多企业在建设过程中,可能会把这两个一概而论,其实有肯定的界线。 IaaS 次要是对裸金属机器进行资源分配、操作系统装置、服务器启动、网络配置等。PaaS 次要是对计算资源进行逻辑治理,与利用无关资源分配和调度,次要是最大水平上服务于下层利用,如图(b)。 (b) 4、云平台真的适宜你吗?建设之前,须要大量的工夫去整顿、评估组件的各种可行性剖析。说到这里,很多人可能会急流勇退;是的,坦白的说,云平台其实不适宜大多数的团队,如果你在一个 15 - 20 人的小团队里,它会带给你大量苦楚,而益处却微不足道。 4.1、以建设容器云平台举个例子目前 A 公司的零碎全副运行在裸金属 3 台服务器或者 5 个虚拟机上,思考到硬件资源无奈灵便调度,目前思考迁徙到Kubernetes上。 首先须要申请更多的机器,迁徙总要有一个过渡阶段,后期裸金属服务器上要运行一份服务,Kubernetes容器化平台还要有一份服务,此外还须要思考依赖的底层服务;其次须要开发人员的学习适应和肯定的人力投入,开发人员须要在理解大量概念之后能力应用,Node、Pod、Container、Service、Deployment......各种资源对象,如图(c)能够看出 Kubernetes 是一个宏大的零碎,操作和应用都是十分的简单,它蕴含 58w 行 go 代码,如果咱们想要服务更好的工作,钻研其运行机制,肯定是必不可少的。  ( c ) 最初落地,须要思考数据的迁徙、遗留零碎的迁徙,因为 Kubernetes 自身是一个集群,不得不思考分布式存储管理、配置管理...... 如果本人零碎自身不适应集群部署,那么不能施展云的作用,不得不思考把服务拆分成散布式微服务程序,这种程序很难编写,编写过程须要思考分布式事务等很多问题,其次调试和日志排查问题也会减少复杂度,于是你在云平台的漩涡里不能自拔.......... 下面说了这么多 Kubernetes 应用问题,是不是说它就一无是处了,当然不是。比如说以后服务客户是金融业务,7*24 小时不能宕机,且有上万用户应用,这就须要思考到服务的扩展性和降级可靠性了,这正是Kubernetes 最善于的事件了。 ...

December 7, 2020 · 1 min · jiezi

关于spring:揭露-mybatis日志不为人知的秘密

引言咱们在应用mybatis时,如果呈现sql问题,个别会把mybatis配置文件中的logging.level参数改成debug,这样就能在日志中看到某个mapper最终执行sql、入参和影响数据行数。咱们拿到sql和入参,手动拼接成残缺的sql,而后将该sql在数据库中执行一下,就根本能定位到问题起因。 mybatis的日志性能应用起来还是十分不便的,大家有没有想过它是如何设计的呢? 从logging目录开始咱们先看一下mybatis的logging目录,该目录的性能决定了mybatis应用什么日志工具打印日志。 logging目录构造如下: 它外面除了jdbc目录,还蕴含了7个子目录,每一个子目录代表一种日志打印工具,目前反对6种日志打印工具和1种非日志打印工具。咱们用一张图来总结一下 除了下面的7种日志工具之外,它还形象出一个Log接口,所有的日志打印工具必须实现该接口,前面能够面向接口编程。 定义了LogException异样,该异样是日志性能的专属异样,如果你有看过mybatis其余源码的话,不难发现,其余性能也定义专属异样,比方:DataSourceException等,这是mybatis的惯用手法,次要是为了将异样细粒度的划分,以便更快定位问题。 此外,它还定义了LogFactory日志工厂,以便于屏蔽日志工具实例的创立细节,让用户应用起来更简略。 如果是你该如何设计这个性能?咱们依照下面目录构造的介绍其实曾经有一些思路: 定义一个Log接口,以便于对立形象日志性能,这7种日志性能都实现Log接口,并且重写日志打印办法。定义一个LogFactory日志工厂,它会依据咱们我的项目中引入的某个日志打印工具jar包,创立一个具体的日志打印工具实例。看起来,不错。然而,再认真想想,LogFactory中如何判断我的项目中引入了某个日志打印工具jar包才创立相应的实例呢?咱们第一个想到的可能是用if...else判断不就行了,再想想感觉用if...else不好,7种条件判断太多了,并非优雅的编程。这时候,你会想一些防止太长if...else判断的办法,当然如果你看过我之前写的文章《实战|如何打消又臭又长的if...else判断更优雅的编程?》,可能曾经学到了几招,然而mybatis却用了一个新的方法。 mybatis是如何设计这个性能的?从Log接口开始它外面形象了日志打印的5种办法和2种判断办法。 再剖析LogFactory的代码它外面定义了一个动态的结构器logConstructor,没有用if...else判断,在static代码块中调用了6个tryImplementation办法,该办法会启动一个执行工作去调用了useXXXLogging办法,创立日志打印工具实例。 当然tryImplementation办法在执行前会判断结构器logConstructor为空才容许执行工作中的run办法。下一步看看useXXXLogging办法:看到这里,聪慧的你可能会有这样的疑难,从上图能够看出mybatis定义了8种useXXXLogging办法,然而在后面的static动态代码块中却只调用了6种,这是为什么? 比照后发现:useCustomLogging 和 useStdOutLogging 后面是没调用的。useStdOutLogging它外面应用了StdOutImpl类该类其实就是通过JDK自带的System类的办法打印日志的,无需引入额定的jar包,所以不参加static代码块中的判断。 而useCustomLogging办法须要传入一个实现了Log接口的类,如果mybatis默认提供的6种日志打印工具不满足要求,以便于用户本人扩大。 而这个办法是在Configuration类中调用的,如果用户有自定义logImpl参数的话。 具体是在XMLConfigBuilder类的settingsElement办法中调用再回到后面LogFactory的setImplementation办法 它会先找到实现了Log接口的类的结构器,返回将该结构器赋值给全局的logConstructor。 这样一来,就能够通过getLog办法获取到Log实例。 而后在业务代码中通过上面这种形式获取Log对象,调用它的办法打印日志了。 梳理一下LogFactory的流程: 在static代码块中依据一一引入日志打印工具jar包中的日志类,先判断如果全局变量logConstructor为空,则加载并获取相应的结构器,如果能够获取到则赋值给全局变量logConstructor。如果全局变量logConstructor不为空,则不持续获取结构器。依据getLog办法获取Log实例通过Log实例的具体日志办法打印日志在这里还分享一个知识点,如果某个工具类外面都是静态方法,那么要把该工具类的构造方法定义成private的,避免被疑难调用,LogFactory就是这么做的。 适配器模式日志模块除了应用工厂模式之外,还是有了适配器模式。 适配器模式会将所须要适配的类转换成调用者可能应用的指标接口 波及以下几个角色: 指标接口( Target )须要适配的类( Adaptee )适配器( Adapter)mybatis是怎么用适配器模式的?上图中标红的类对应的是Adapter角色,Log是Target角色。而LogFactory就是Adaptee,它外面的getLog办法外面蕴含是须要适配的对象。 sql执行日志打印原理从下面曾经可能确定应用哪种日志打印工具,但在sql执行的过程中是如何打印日志的呢?这就须要进一步剖析logging目录下的jdbc目录了。 看看这几个类的关系图:ConnectionLogger、PreparedStatementLogger、ResultSetLogger和StatementLogger都继承了BaseJdbcLogger类,并且实现了InvocationHandler接口。从类名十分直观的看出,这4品种对应的数据库jdbc性能。 它们实现了InvocationHandler接口意味着它用到了动静代理,真正起作用的是invoke办法,咱们以ConnectionLogger为例: 如果调用了prepareStatement办法,则会打印debug日志。 上图中传入的original参数外面蕴含了\n\t等分隔符,须要将分隔符替换成空格,拼接成一行sql。 最终会在日志中打印sql、入参和影响行数:上图中的sql语句是在ConnectionLogger类中打印的 那么入参和影响行数呢? 入参在PreparedStatementLogger类中打印的影响行数在ResultSetLogger类中打印的 大家须要留神的一个中央是:sql、入参和影响行数只打印了debug级别的日志,其余级别并没打印。所以须要在mybatis配置文件中的logging.level参数配置成debug,能力打印日志。 彩蛋不晓得大家有没有发现这样一个问题: 在LogFactory的代码中定义了很多匿名的工作执行器 然而在理论调用时,却没有在线程中执行,而是间接调用的,这是为什么? 答案是为了保障程序执行,如果所有的日志工具jar包都有,加载优先级是:slf4j 》commonsLog 》log4j2 》log4j 》jdkLog 》NoLog 还有个问题,程序执行就能够了,为什么要把匿名外部类定义成Runnable的呢? 这里十分有迷惑性,因为它没创立Thread类,并不会多线程执行。我集体认为,这里是mybatis的开发者的一种偷懒,不然须要定义一个新类代替这种执行工作的含意,还不如就用已有的。 最初说一句(求关注,别白嫖我)求关注,如果这篇文章对您有所帮忙,或者有所启发的话,帮忙扫描下发二维码关注一下,保持原创不易,您的反对是我保持下来最大的能源。 求一键三连:点赞、转发、在看。在公众号中回复:面试、代码神器、开发手册、工夫治理有超赞的粉丝福利,另外回复:加群,能够跟很多BAT大厂的前辈交换和学习。 本文由博客群发一文多发等经营工具平台 OpenWrite 公布

December 6, 2020 · 1 min · jiezi

关于spring:SpringMVC常用注解整理

controllerr层* @controller:用于标注管制层服务,将以后类交给spring治理;* @RestController:该注解相当@controller+@RestController注解* @ResponseBody:将controller的办法的返回对象通过指定的转换器转换为指定的格局后写入到response对象的body区,通常用来返回josn或字符串等数据(在应用此注解之后不会再走视图解析器,而是间接将数据写入到输出流中,成果等同于通过response对象输入指定格局的数据);* @RequestMapping:标注申请门路,什么申请都能够接管;* @GetMapping:标注申请门路,只接管get申请(查)* @PostMapping:标注申请门路,只接管post申请(增)* @putMapping:标注申请门路,用于批改更新申请* @DeleteMapping:标注申请门路,用于删除申请;* @PathVariable:承受申请门路中的占位符的值* @RequestParam :将申请参数绑定到被此注解润饰的办法的参数上,是springMVC中接管一般参数的注解;service层:* @Service:用于标注业务逻辑层,将以后类交给spring治理, 其getBean的默认名称是类名(头字母小写),能够@Service(“xxxx”)这样来指定dao层:* @Mapper:将以后mapper接口交给spring治理,为接口创立实现类,并未实现类发明实例,最初交给spring中的ioc容器治理(mapper接口上也能够不加@Mapper注解,通过在启动类上增加@mapperscan注解,通过该注解来扫描com.tedu.dao包下的所有接口);* @MapperScan(basePackages = "com.tedu.dao")* @Repository //形容数据层实现类,用于交给spring治理*

December 5, 2020 · 1 min · jiezi

关于spring:注解方式自定义实现Spring-Ioc容器-事务-动态代理

@TOC 前言上一篇点击查看应用xml来实现自定义IOC以及依赖注入关系保护,动静代理,以及事务操作; 这次应用注解来实现IOC以及依赖关系保护 步骤以及思路剖析基于xml实现形式时,仅仅只须要在xml外面配置好bean的id以及bean的权限定命名,而后反射实例化对象,最初退出到ioc容器中依赖注入时候仅仅须要获取property标签以及父级标签,依据property名从ioc容器中获取到须要注入的bean示例即可; 如果是基于注解实现呢! 1 首先须要自定义注解2 如何获取自定义到的注解3 实例化打了注解的实例4 在指定bean成员变量上是否蕴含须要注入的注解,而后依赖注入5 生成代理对象,基于接口判断是否抉择JDK动静代理或者CGLIB代理代码实现首先自定义注解实例bean的注解 @Repository 和@Service @Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Service { String value() default "";}@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Repository { String value() default "";}主动拆卸的注解 @Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Autowired { String name() default "";}事务注解 Transactional @Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Transactional {}而后 在类上标注注解,以及依赖注入事务注解以及DI 以及Bean主动拆卸 我的项目构造 配置信息版本 JDK8 , tomcat 7 , IDEA 2019 03 所需依赖 <!-- servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!--引入cglib依赖包--> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.1_2</version> </dependency>tomcat插件 ...

December 5, 2020 · 6 min · jiezi

关于spring:拜托别再让我优化大事务了我的头都要裂开了

前言最近有个网友问了我一个问题:零碎中大事务问题要如何解决? 正好前段时间我在公司解决过这个问题,咱们过后因为我的项目初期工夫比拟缓和,为了疾速实现业务性能,疏忽了零碎局部性能问题。我的项目顺利上线后,专门抽了一个迭代的工夫去解决大事务问题,目前曾经优化实现,并且顺利上线。现给大家总结了一下,咱们过后应用的一些解决办法,以便大家被雷同问题困扰时,能够参考一下。 大事务引发的问题在分享解决办法之前,先看看零碎中如果呈现大事务可能会引发哪些问题 从上图能够看出如果零碎中呈现大事务时,问题还不小,所以咱们在理论我的项目开发中应该尽量避免大事务的状况。如果咱们已有零碎中存在大事务问题,该如何解决呢? 解决办法少用@Transactional注解大家在理论我的项目开发中,咱们在业务办法加上@Transactional注解开启事务性能,这是十分广泛的做法,它被称为申明式事务。局部代码如下: @Transactional(rollbackFor=Exception.class) public void save(User user) { doSameThing... }然而,我要说的第一条是:少用@Transactional注解。为什么? 咱们晓得@Transactional注解是通过spring的aop起作用的,然而如果使用不当,事务性能可能会生效。如果凑巧你经验不足,这种问题不太好排查。至于事务哪些状况下会生效,能够参考我之前写的《spring事务的这10种坑,你稍不留神可能就会踩中!!!》这篇文章。@Transactional注解个别加在某个业务办法上,会导致整个业务办法都在同一个事务中,粒度太粗,不好管制事务范畴,是呈现大事务问题的最常见的起因。 那咱们该怎么办呢? 能够应用编程式事务,在spring我的项目中应用TransactionTemplate类的对象,手动执行事务。局部代码如下: @Autowired private TransactionTemplate transactionTemplate; ... public void save(final User user) { transactionTemplate.execute((status) => { doSameThing... return Boolean.TRUE; }) }从下面的代码中能够看出,应用TransactionTemplate的编程式事务性能本人灵便管制事务的范畴,是防止大事务问题的首选方法。 当然,我说少应用@Transactional注解开启事务,并不是说肯定不能用它,如果我的项目中有些业务逻辑比较简单,而且不常常变动,应用@Transactional注解开启事务开启事务也不妨,因为它更简略,开发效率更高,然而千万要小心事务生效的问题。 将查问(select)办法放到事务外如果呈现大事务,能够将查问(select)办法放到事务外,也是比拟罕用的做法,因为个别状况下这类办法是不须要事务的。 比方呈现如下代码: @Transactional(rollbackFor=Exception.class) public void save(User user) { queryData1(); queryData2(); addData1(); updateData2(); }能够将queryData1和queryData2两个查询方法放在事务外执行,将真正须要事务执行的代码才放到事务中,比方:addData1和updateData2办法,这样就能无效的缩小事务的粒度。如果应用TransactionTemplate的编程式事务这里就十分好批改。 @Autowired private TransactionTemplate transactionTemplate; ... public void save(final User user) { queryData1(); queryData2(); transactionTemplate.execute((status) => { addData1(); updateData2(); return Boolean.TRUE; }) }然而如果你切实还是想用@Transactional注解,该怎么拆分呢? ...

December 5, 2020 · 2 min · jiezi

关于spring:求你别再用swagger了给你推荐几个在线文档生成神器

前言最近公司打算做一个openapi开放平台,让我找一款好用的在线文档生成工具,具体要求如下: 必须是开源的可能实时生成在线文档反对全文搜寻反对在线调试性能界面柔美说实话,这个需要看起来简略,然而实际上一点的都不简略。 我花了几天工夫到处百度,谷歌,技术博客 和 论坛查资料,先后调研了如下文档生成工具: gitbookgithub地址:https://github.com/GitbookIO/gitbook 开源协定:Apache-2.0 License Star: 22.9k 开发语言:javascript 用户:50万+ 举荐指数:★★★ 示例地址:https://www.servicemesher.com/envoy/intro/arch_overview/dynamic_configuration.html gitBook是一款文档编辑工具。它的性能相似金山WPS中的word或者微软office中的word的文档编辑工具。它能够用来写文档、建表格、插图片、生成pdf。当然,以上的性能WPS、office可能做得更好,然而,gitBook还有更最弱小的性能:它能够用文档建设一个网站,让更多人理解你写的书,另外,最最外围的是,他反对Git,也就意味着,它是一个分布式的文档编辑工具。你能够随时随地来编写你的文档,也能够多人独特编写文档,哪怕多人编写同一页文档,它也能记录每个人的内容,而后通知你他们之间的区别,也能记录你的每一次改变,你能够查看每一次的书写记录和变动,哪怕你将文档都删除了,它也能找回来!这就是它继承git后的厉害之处! 长处:应用起来非常简单,反对全文搜寻,能够跟git完满集成,对代码无任何嵌入性,反对markdown格局的文档编写。 毛病:须要独自保护一个文档我的项目,如果接口批改了,须要手动去批改这个文档我的项目,不然可能会呈现接口和文档不统一的状况。并且,不反对在线调试性能。 集体倡议:如果对外的接口比拟少,或者编写之后不会常常变动能够用这个。 smartdocgitee地址: https://gitee.com/smart-doc-team/smart-doc 开源协定:Apache-2.0 License Star: 758 开发语言:html、javascript 用户:小米、科大讯飞、1加 举荐指数:★★★★ 示例地址:https://gitee.com/smart-doc-team/smart-doc/wikis/文档效果图?sort_id=1652819 smart-doc是一个java restful api文档生成工具,smart-doc颠覆了传统相似swagger这种大量采纳注解侵入来生成文档的实现办法。smart-doc齐全基于接口源码剖析来生成接口文档,齐全做到零注解侵入,只须要依照java规范正文的写就能失去一个规范的markdown接口文档。 长处:基于接口源码剖析生成接口文档,零注解侵入,反对html、pdf、markdown格局的文件导出。 毛病:须要引入额定的jar包,不反对在线调试 集体倡议:如果实时生成文档,然而又不想打一些额定的注解,比方:应用swagger时须要打上@Api、@ApiModel等注解,就能够应用这个。 redocgithub地址:https://github.com/Redocly/redoc 开源协定:MIT License Star: 10.7K 开发语言:typescript、javascript 用户:docker、redocly 举荐指数:★★★☆ 示例地址:https://docs.docker.com/engine/api/v1.40/ redoc本人号称是一个最好的在线文档工具。它反对swagger接口数据,提供了多种生成文档的形式,非常容易部署。应用redoc-cli可能将您的文档捆绑到零依赖的 HTML文件中,响应式三面板设计,具备菜单/滚动同步。 长处:十分不便生成文档,三面板设计 毛病:不反对中文搜索,分为:一般版本 和 付费版本,一般版本不反对在线调试。另外UI交互个人感觉不适宜国内大多数程序员的操作习惯。 集体倡议:如果想疾速搭建一个基于swagger的文档,并且不要求在线调试性能,能够应用这个。 knife4jgitee地址:https://gitee.com/xiaoym/knife4j 开源协定:Apache-2.0 License Star: 3k 开发语言:java、javascript 用户:未知 举荐指数:★★★★ 示例地址:http://swagger-bootstrap-ui.xiaominfo.com/doc.html knife4j是为Java MVC框架集成Swagger生成Api文档的加强解决方案,前身是swagger-bootstrap-ui,取名kni4j是心愿她能像一把匕首一样玲珑,轻量,并且性能强悍。 长处:基于swagger生成实时在线文档,反对在线调试,全局参数、国际化、拜访权限管制等,性能十分弱小。 ...

December 4, 2020 · 1 min · jiezi

关于spring:整合spring-cloud云架构-SSO单点登录之OAuth20-根据token获取用户信息

我依据框架中OAuth2.0的应用总结,画了SSO单点登录之OAuth2.0 登出流程,明天咱们看一下依据用户token获取yoghurt信息的流程(企业架构源码能够加求球:三五三六二四七二五九): 1. /** 2. * 依据token获取用户信息 3. * @param accessToken 4. * @return 5. * @throws Exception 6. */ 7. @RequestMapping(value = "/user/token/{accesstoken}", method = RequestMethod.GET) 8. public ResponseVO getUserByToken(@PathVariable(value = "accessToken", required = true) String accessToken,@RequestHeader(value = "userId", required = true) Long userId) throws Exception { 9. if(StringUtils.isEmpty(accessToken)){ 10. return UserResponseCode.buildEnumResponseVO(UserResponseCode.RESPONSE_CODE_REQ_CANNOT_EMPTY, null); 11. } 13. OauthAccessToken oauthAccessToken = userMgrService.getOauthAccessToken(accessToken); 14. if(null == oauthAccessToken){ 15. return UserResponseCode.buildEnumResponseVO(UserResponseCode.RESPONSE_CODE_OAUTH_ACCESSTOKEN_EMPTY, null); 16. } 18. String userName = oauthAccessToken.getUserName(); 19. if (StringUtils.isEmpty(userName)) { 20. return UserResponseCode.buildEnumResponseVO(UserResponseCode.RESPONSE_CODE_OAUTH_ACCESSTOKEN_EMPTY, null); 21. } 23. return this.getUser(userName); 24. } 26. @RequestMapping(path = "/user/get/{userName}", method = RequestMethod.GET) 27. public ResponseVO getUser(@PathVariable(value = "userName") String userName) { 28. Map<String, Object> returnData = null; 29. try { 30. User user = userMgrService.getUserByName(userName); 31. if (null != user) { 32. returnData = new HashMap<String, Object>(); 33. returnData.put("user", user); 34. return UserResponseCode.buildEnumResponseVO(UserResponseCode.RESPONSE_CODE_SUCCESS, returnData); 35. } 36. return UserResponseCode.buildEnumResponseVO(UserResponseCode.RESPONSE_CODE_SYSTEM_ERROR, null); 37. } catch (Exception e) { 38. return UserResponseCode.buildEnumResponseVO(UserResponseCode.RESPONSE_CODE_SYSTEM_ERROR, null); 39. } 41. } 我这里只是简略写了一些登出的代码,咱们会在前面的文章中具体贴出所有代码供大家参考,而且会从创立数据库,到执行操作的每一个流程记录下来。 ...

December 4, 2020 · 1 min · jiezi

关于spring:Spring-AOP核心类解析这是最全的一篇了

写在后面最近,不少小伙伴在催更【Spring注解驱动开发】专题,好吧,【Spring注解驱动开发】专题的确有很长时间没更新了。那咱们从明天开始更新【Spring注解驱动开发】专题,同样的,咱们还是以源码解析为主。文章已同步收录到:https://github.com/sunshinelyz/technology-binghe 和 https://gitee.com/binghe001/technology-binghe 。如果文件对你有点帮忙,别忘记给个Star哦! 关注【冰河技术】微信公众号,回复“Spring注解”支付工程源码。 类结构图咱们先来看下AnnotationAwareAspectJAutoProxyCreator类的结构图。 上图中一些 类/接口 的介绍: AspectJAwareAdvisorAutoProxyCreator : 公开了AspectJ的调用上下文,并弄清楚来自同所有面的多个Advisor在AspectJ中的优先级规定。 AbstractAdvisorAutoProxyCreator : 通用主动代理创立器,它基于检测到的每个参谋程序为特定bean构建AOP代理。 AbstractAutoProxyCreator : 扩大了 ProxyProcessorSupport,实现了SmartInstantiationAwareBeanPostProcessor、BeanFactoryAware 接口,是BeanPostProcessor 实现,该实现应用AOP代理包装每个合格的bean,并在调用bean自身之前委派给指定的拦截器。 BeanFactoryAware : 实现了该接口的Bean能够晓得它属于那个 BeanFactory,Bean能够通过Spring容器查找它的协同者(依赖查找),但大多数的Bean是通过结构器参数和Bean办法(依赖注入)来获取它的协同者。 BeanPostProcessor :工厂钩子,容许自定义批改新的bean实例。例如,查看标记接口或应用代理包装bean。如果咱们须要在Spring容器中实现Bean的实例化,配置和其初始化前后增加一些本人的逻辑解决,咱们就能够定义一个或多个BeanPostProcessor接口的实现,而后注册到容器中。 InstantiationAwareBeanPostProcessor : BeanPostProcessor 的子接口,它增加了实例化之前的回调,以及实例化之后但设置了显式属性或主动拆卸之前的回调。它外部提供了3个办法,再加上BeanPostProcessor接口外部的2个办法,实现这个接口须要实现5个办法。InstantiationAwareBeanPostProcessor 接口的次要作用在于指标对象的实例化过程中须要解决的事件,包含实例化对象的前后过程以及实例的属性设置。 SmartInstantiationAwareBeanPostProcessor : InstantiationAwareBeanPostProcessor 接口的扩大,多出了3个办法,增加了用于预测已解决bean的最终类型的回调,再加上父接口的5个办法,所以实现这个接口须要实现8个办法,次要作用也是在于指标对象的实例化过程中须要解决的事件。 总之:AspectJAwareAdvisorAutoProxyCreator为 AspectJ 切面类创立主动代理。 外围类解析BeanPostProcessor 接口中的两个办法 postProcessBeforeInitialization 和 postProcessAfterInitialization,作用是对Bean初始化前后增加一些本人的逻辑。 @Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean;}@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean;}InstantiationAwareBeanPostProcessor 是 BeanPostProcessor 的子接口,它额定减少了3个新的办法:postProcessBeforeInstantiation( 指标对象被实例化之前调用的办法,能够返回指标实例的一个代理用来代替指标实例 )、postProcessAfterInstantiation(该办法在Bean实例化之后执行,返回false,会疏忽属性值的设置;如果返回true,会依照失常流程设置属性值) 和 postProcessPropertyValues(对属性值进行批改,将来版本将会删除) ...

December 3, 2020 · 4 min · jiezi

关于spring:硬核从零实现一个操作系统内核毕设项目经验不愁了

文章内容可能比拟少,只是简略分享一下一位学弟写的操作系统内核,心愿对本人想写操作系统内核的小伙伴能有所帮忙!Github掘金打算历史文章汇总:https://www.yuque.com/docs/share/61b99973-ecb3-4317-ba19-fc1a15dd842c操作系统是一门十分重要的计算机基础课。 对于面试来说,操作系统是技术面试必不可少的一环,并且口试题中更是大量呈现操作系统的问题。 对于编程学习来说, 学习操作系统有助于咱们理解计算机的工作原理。 操作系统中的很多思维、很多经典的算法,你都能够在咱们日常开发应用的各种工具或者框架中找到它们的影子。 很多学校在学习操作系统的时候,都会有要求学生写一个简略的操作系统内核来加深对操作系统的了解。 实际上,写一个 Demo 级别的操作系统内核并不难,要害还是看你有没有趣味和急躁。 单纯从找工作角度来说,如果你可能本人独立写一个操作系统内核的话,即便是玩具级别的那种。 相对也可能为本人的简历加分不少。 从集体能力来说,讲句心里话,写一个操作系统内核对于你的编程能力进步是十分十分大的! Github 上就有一个老哥开源了一个本人手写的操作系统内核。想要手写一个操作系统内核的敌人肯定要不要错过啊! 目前的话,这个我的项目曾经播种了 1k+ 的 star! 这个我的项目的作者提供了各个阶段完成度不同的内核,你齐全能够依照本人喜爱的中央开始进行。 如果你想要运行这个操作系统内核的话,非常简单。 首先将这个我的项目克隆到本地 :git clone https://github.com/SimpleXX/SimpleKernel.git进入我的项目目录:cd SimpleKernel/ 后运行 bash ./run.sh 即可。效果图如下: 整个我的项目的目录构造如下。因为作者是依照功能模块来划分目录,所以整体构造看着十分清晰。 我的项目地址:https://github.com/Simple-XX 。 Github掘金打算历史文章汇总:https://www.yuque.com/docs/share/61b99973-ecb3-4317-ba19-fc1a15dd842c

December 3, 2020 · 1 min · jiezi

关于spring:java版spring-cloud分布式微服务云架构B2B2C电子商务平台20升级已完成

近期公司用了一个月的工夫,将鸿鹄云商2.0微服务版本全面降级,提供电子商务服务治理,服务配置,服务监控,链路追踪,容灾等(企业架构源码能够加求球:三五三六二四七二五九)

December 3, 2020 · 1 min · jiezi

关于spring:乐字节Spring-邮件发送

Spring 邮件发送次要内容JavaMail 概述 JavaMail,顾名思义,提供给开发者解决电子邮件相干的编程接口。JavaMail 是由 Sun 定义的一套收发电子邮件的 API,它能够不便地执行一些罕用的邮件传输,不同的厂商能够提供本人的实现类。但它并没有蕴含在 JDK 中,而是作为 JavaEE 的一部分。 厂商所提供的 JavaMail 服务程序能够有选择地实现某些邮件协定,常见的邮件协定包含: SMTP:简略邮件传输协定,用于发送电子邮件的传输协定;POP3:用于接管电子邮件的标准协议;IMAP:互联网音讯协定,是 POP3 的代替协定。 这三种协定都有对应 SSL 加密传输的协定,别离是 SMTPS,POP3S 和 IMAPS。除 JavaMail 服务提供程序之外, JavaMail 还须要 JAF(JavaBeans Activation Framework)来解决不是纯文本的邮件内容,这包含 MIME(多用途互联网邮件扩大)、URL 页面和文件附件等内容。另外,JavaMail 依赖 JAF(JavaBeans Activation Framework),JAF 在 Java6 之后曾经合并到 JDK 中,而 JDK5 之前须要另外下载 JAF 的类库。 协定介绍 在钻研 JavaMail API 的细则之前,首先须要对于 API 用到的协定有个意识。对于 java mail 来说用到的协定有常见的几种: SMTP、POP、IMAP、MIME SMTP 简略邮件传输协定(Simple Mail Transfer Protocol,SMTP)由 RFC 821 定义。它定义了发送电子邮件的机制。在 JavaMail API 环境中,您基于 JavaMail 的程序将和您的公司或因特网服务供应商的(Internet ServiceProvider’s,ISP’s)SMTP 服务器通信。SMTP 服务器会直达音讯给接管方 SMTP 服务器以便最终让用户经由 POP 或 IMAP 取得。 ...

December 3, 2020 · 9 min · jiezi

关于spring:乐字节Spring-JDBC-和-事务控制

Spring JDBC 和 事务管制次要内容Spring 整合 JDBC 环境 Spring 框架除了提供 IOC 与 AOP 外围性能外,同样提供了基于JDBC 的数据拜访性能,使得拜访长久层数据更加不便。应用 Spring JDBC 环境,首先须要一套 Spring 整合 JDBC 的环境。 增加依赖坐标<!-- 增加相干的依赖坐标 --><!-- spring 框架坐标依赖增加 --><dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.4.RELEASE</version></dependency><!-- spring 测试环境 --><dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.4.RELEASE</version> <scope>test</scope></dependency><!-- aop --><dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version></dependency><!-- spring jdbc --><dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.4.RELEASE</version></dependency><!-- spring事物 --><dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.4.RELEASE</version></dependency><!-- mysql 驱动包 --><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.19</version></dependency><!-- c3p0 连接池 --><dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.5</version></dependency> 增加 jdbc 配置文件在src/main/resources目录下新建jdbc.properties配置文件,并设置对应的配置信息 ...

December 3, 2020 · 13 min · jiezi

关于spring:RequestParam注解加与不加的区别

@RequestParam注解,加与不加的区别@RequestParam 将 申请参数 绑定到 控制器办法参数 上SpringMVC提供的接管一般参数的注解源码: @Target({ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface RequestParam { @AliasFor("name") String value() default ""; @AliasFor("value") String name() default ""; boolean required() default true; String defaultValue() default "nttnttnue000ue001ue002nttttn";} 是name属性 还是value属性,看前辈的博客说两者皆可,开发中二者都能取得参数,我还没有测试过。@RequestParam(value="参数名",required="true/false",defaultValue="")/* value:参数名required:设置是否蕴含该参数,默认是true,示意该申请门路中必须蕴含该参数,如果不蕴含就会报400谬误defaultValue:设置默认参数值,如果设置了该值,required=true就会生效,主动为false,如果没有传该参数,就应用默认值/ 加与不加应用不应用该注解,都能够获取参数,但二者还是有区别的。 不应用@RequestParam注解时, 申请门路中不跟 参数,获取的参数为null;应用@RequestParam 注解时, 申请门路中不跟 参数,页面会报错,返回400如果设置了required="false",就和不应用@RequestParam注解一样了注解@RequestParam如何应用加与不加的区别

December 2, 2020 · 1 min · jiezi

关于spring:工作快两年了斗胆谈谈校招社招技术面试那些事

举荐????:靠近100K star 的Java学习/面试指南:JavaGuide !!!Note : 01,02 局部非干货,只是集体就一篇文章被 diss 的经验做的一个简略复盘。不想看Guide哥瞎BB的能够跳过。这篇文章次要是为了聊一些对于校招/社招的心里话,被 diss 与否其实是无所谓的。我不能让所有人都称心我的文章,然而大部分人感觉我的文章有价值我就开心了。 01前几天,我分享了一篇 《读者,双非本科、0实习、0较量/我的项目经验。3个月上岸百度(上)》 的文章引发了一小部分读者喷我是成心贩卖焦虑。 刚开始的时候,我的一脸懵逼啊!这心想哪里有贩卖焦虑了呢?为此,我还去询问了很多敌人。敌人们也都并没有感觉不妥。 可能敌人也是站在我这边的,我本人思前想后,感觉必定是哪里出了问题(当天本人状态原本也不咋滴,的确有被影响到。)。 认真想了一下,换位思考了一下。我感觉呈现这种状况的起因可能有上面几个: 当事人状态不好 :被我 diss 的人过后状态不太好,而后看到这篇文章受到了刺激 。我是十分了解的,我在状态不好的时候会敏感很多。所以,我个别会压抑心田的怒火,不会去怒怼他人。了解呈现偏差 :在以后这个曾经比拟卷的状况下,这个题目的确会让很多一些认真看文章内容的人人产生误解。让很多人误以为通过 3 个月的突击温习就能取得大厂 Offer。在以后的技术面试环境下,的确戳到了很多人的痛点。 或者我在文首简略阐明一下读者自身就有计算机专业根底 ,并不是单纯靠 3 个月的温习就上岸大厂会更好。单纯凑个冷落 :很多人单纯就点开文章,然而基本不会认真看文章内容。而后,这些人看到评论区的评论,就跟着一起瞎起哄。动动手就能喷人多简略哦!多厉害哦!这种人就很恶心啊!不过,我做几年公众号必定有一些这样的读者,也挺失常的!没关系!工夫会把你变成我的忠诚读者。然而,那些酸作者上岸大厂的人,我是真搞不懂!大厂每年招这么多人,总有很多人上岸。看到他人上岸的经验,咱们难道不应该学习一下,而不是搁那恰柠檬吗? 我说的这种学习不是说你照搬他人的教训,而是借鉴排汇他人的教训。 说实话,小贾的分享十分十分用心!所以,我给的稿费还挺多的。我感觉这是对好内容的一种认可!不过,我说了很久,小贾最初也只有了 400 。 《读者,双非本科、0实习、0较量/我的项目经验。3个月上岸百度(上)》 的下篇我应该会在下周整理出来。 02题目始终是我的一个痛点,很多十分用心的原创因为题目没起好就间接翻车了。 上面是我近期的一些原创,应该没有题目对不上内容的吧? 说实话,我是真想当一个“题目党”啊! 谁不想让本人辛辛苦苦写的原创被更多人看到!试问一下:“你本人辛苦写的原创,你难道不心愿更多人看到么?”。 很多时候平淡的题目,雅致的封面真的没啥人看。我感觉不是大家雅致了、塌实了,而是当初的大环境的确是这样,与咱们每一个人都有关系。 我感觉公众号题目和封面就像咱们每个人的简历一样,咱们都想用无限的内容突出一些亮点来吸引他人的留神。 咱们大部分人在写简历的时候,根本都会简略包装一下。我说的这个包装不是平心而论,而是突出放大了某些亮点。 有时候我常常感叹:“连文章题目都特么开始卷了”。 03就像当初的面试一样,大家都说内卷了,埋怨当初的面试真特么难。 然而,单纯埋怨有用么?你对其余求职者说:“大家都不要刷 Leetcode 了啊!都不要再筹备高并发、高可用的面试题了啊!当初都这么卷了!” 会有人听你的么?你不筹备面试,然而其他人会筹备面试啊!那你是不是傻啊?还是真的厉害到不须要筹备面试呢? 大家身边肯定有很多编程比你厉害然而找的工作并没有你好的敌人吧! 技术面试不同于编程,编程厉害不代表技术面试就肯定能过。 当初你去面个试,不简略筹备一下子,那几乎就是往枪口上撞。 真的不是贩卖焦虑! 你不信能够本人去面试一波看看。 我就不信这年头还有不筹备面试也不刷上面试题就能间接取得大厂 offer。可能会有一些发过顶级周刊或者取得过顶级大赛奖项的巨佬不须要。 试问一下:“咱们作为普通人,在这样一个技术面试气氛下,不花点心理筹备面试能翻身么?” “面试造火箭,工作拧螺丝钉” 就是目前的一个常态,预计将来很久也还是会这样。 然而,肯定不要对面试抱有侥幸心理。打铁还需本身硬! 千万不要感觉本人看几篇面经,看几篇面试题解析就能通过面试了。肯定要静下心来深刻学习! 04我本人是双非本科,我在大二就意识到本人的学校不是劣势。所以,我就早早确定了本人当前要走的技术方向是走 Java 后端。 ...

December 2, 2020 · 1 min · jiezi

关于spring:微服务框架基于开源技术的分布式服务化框架

采纳微服务架构,升高了零碎之间的耦合性,升高了单个利用故障对业务零碎的影响,同时采纳该架构,为未来的继续集成(Devops)打下技术根底。同时也升高了团队之间的相互依赖,进步了工作效率 基于spring boot, spring cloud和netflix等开源技术搭建微服务架构Netflix Eureka作为服务注册和发现的实现计划。(Eureka是一套弹性服务注册实现计划)基于客户端的负载平衡,Ribbon实现额定负载平衡算法,包含可用性过滤、加权响应工夫以及可用域亲和等Oauth Client&Server 是基于spring security oauth,实现微服务的平安认证(企业架构源码能够加求球:三五三六二四七二五九)JWT&Token&Redis实现微服务对立SSO单点登录认证计划(可选)

December 2, 2020 · 1 min · jiezi

关于spring:Spring-Task-定时任务

Spring Task 定时工作次要内容定时工作概述 在我的项目中开发定时工作应该一种比拟常见的需要,在 Java 中开发定时工作次要有三种解决方案:一是应用JDK 自带的 Timer,二是应用第三方组件 Quartz,三是应用 Spring Task。 Timer 是 JDK 自带的定时工作工具,其简略易用,然而对于简单的定时规定无奈满足,在理论我的项目开发中也很少应用到。Quartz 功能强大,然而应用起来绝对轻便。而 Spring Task 则具备前两者的长处(功能强大且简略易用),应用起来很简略,除 Spring 相干的包外不须要额定的包,而且反对注解和配置文件两种模式。 应用Spring Task实现定时工作 Spring Task 开发定时工作有两种工作配置形式: 1. XML 配置 2. 注解配置 应用 XML 配置实现定时工作创立我的项目,增加依赖创立Maven我的项目,在pom.xml配置文件中,批改我的项目环境,增加spring依赖坐标 <!-- 引入spring依赖坐标 --><dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.4.RELEASE</version></dependency> 增加配置文件 spring.xml在src/main/resources目录下新建配置文件spring.xml,并设置Spring扫描器 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- Spring扫描注解的配置 --> <context:component-scan base-package="com.xxxx" /></beans> 定义定时工作办法新建类,增加主动注入的注解,定义定义工作的办法 package com.xxxx.task;import org.springframework.stereotype.Component;import java.text.SimpleDateFormat;import java.util.Date;@Componentpublic class TaskJob { public void job1(){ System.out.println("工作 1:" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date())); } public void job2(){ System.out.println("工作 2:" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date())); }} 定时工作命名空间的增加在spring.xml配置文件中,增加定时工作的命名空间 ...

December 2, 2020 · 4 min · jiezi

关于spring:Apache-Beam批处理和流式处理的融合

1. 概述在本教程中,咱们将介绍 Apache Beam 并探讨其基本概念。咱们将首先演示应用 Apache Beam 的用例和益处,而后介绍基本概念和术语。之后,咱们将通过一个简略的例子来阐明 Apache Beam 的所有重要方面。 2. Apache Beam是个啥?Apache Beam(Batch+strEAM)是一个用于批处理和流式数据处理作业的对立编程模型。它提供了一个软件开发工具包,用于定义和构建数据处理管道以及执行这些管道的运行程序。 Apache Beam旨在提供一个可移植的编程层。事实上,Beam管道运行程序将数据处理管道转换为与用户抉择的后端兼容的API。目前,反对这些分布式解决后端有: Apache ApexApache FlinkApache Gearpump (incubating)Apache SamzaApache SparkGoogle Cloud DataflowHazelcast Jet3. 为啥抉择 Apache BeamApache Beam 将批处理和流式数据处理交融在一起,而其余组件通常通过独自的 API 来实现这一点。因而,很容易将流式解决更改为批处理,反之亦然,例如,随着需要的变动。 Apache Beam 进步了可移植性和灵活性。咱们关注的是逻辑,而不是底层的细节。此外,咱们能够随时更改数据处理后端。 Apache Beam 能够应用 Java、Python、Go和 Scala等SDK。事实上,团队中的每个人都能够应用他们抉择的语言。 4. 基本概念应用 Apache Beam,咱们能够构建工作流图(管道)并执行它们。编程模型中的要害概念是: PCollection–示意能够是固定批处理或数据流的数据集PTransform–一种数据处理操作,它承受一个或多个 PCollections 并输入零个或多个 PCollections。Pipeline–示意 PCollection 和 PTransform 的有向无环图,因而封装了整个数据处理作业。PipelineRunner–在指定的分布式解决后端上执行管道。简略地说,PipelineRunner 执行一个管道,管道由 PCollection 和 PTransform 组成。 5. 字数统计示例当初咱们曾经学习了 Apache Beam 的基本概念,让咱们设计并测试一个单词计数工作。 5.1 建造梁式管道设计工作流图是每个 Apache Beam 作业的第一步,单词计数工作的步骤定义如下:1.从原文中读课文。2.把课文分成单词表。3.所有单词都小写。4.删去标点符号。5.过滤进行语。6.统计惟一单词数量。为了实现这一点,咱们须要应用 PCollection 和 PTransform 形象将上述步骤转换为 管道 。 ...

December 2, 2020 · 2 min · jiezi

关于spring:读者上岸百度经验分享上

读者筹备面试的工夫是 3 个月左右。然而,不是仅仅用 3 个月就能上岸大厂,之前也有计算机根底(网络、数据结构、操作系统、数据库、计组、微机原理等)。前段时间,贾哥在星球向我询问 offer 抉择的问题,我才晓得贾哥曾经斩获两个还不错的 offer。 贾哥和我一样都是双非本科,学历下面咱们和大部分一样都没有任何劣势。他的校招经验挺挫折的,十分有参考价值。 于是,我就找到贾哥让他写一篇文章分享一下本人秋招的一些筹备面试的经验以及教训。 贾哥写的太用心了,整篇文章大略有 1w+字。我将分为两次来发。感觉内容不错的话,大家记得点赞催更。 心愿贾哥的分享对小伙伴们有帮忙! 01秋招这一路趔趔趄趄的走来,经验了很多心酸,也成长了很多。 从信念满满的开始,到一直地自我狐疑。从一个无所不知的菜鸡,到当初还是一个菜鸟。 我或者没有很多胜利的逆袭教训来分享给大家。然而!我从一个秋招的裸奔男孩到现实上岸,播种的更多是失败的教训、成长的经历和人生的考验吧! 我对计算机并没有激情满满的酷爱,更多的是随着投入的工夫和学习而产生的趣味吧! 我是一个一般的不能在一般的大学生:双非本科,没有任何实习经验、较量经验。 作为一个计算机学子,我大一大二简直不晓得本人未来会抉择编程开发…… 听过很多秋招大佬的传奇逆袭经验,向往他们将酷爱都投身到刷力扣的成就感中,艳羡他们在秋招时斩获大把 Offer。 社会遵循着 2-8 准则,我或者应该被归到 8 这一类当中。我有时在一直问本人,你真的适宜开发这一行吗?你会在这条路上走多远呀?评估本人的实力与大佬们的差距,可能就是我学习的能源吧! 作为一个被秋招毒打的打工人,我想和大家分享我的经验! 02带着高考的些许遗憾,我来到了我的母校,西安某不出名双非一本,业余为数字媒体技术。 这个业余尽管归类在计算机学院下,然而咱们的课程方向是游戏动画,影视建模方向。 导致每次面试官问我业余,我都要解释一遍,我是计算机专业的,计算机的公共基础课(数据结构、计算机网络等)咱们都会学。 咱们的待业方向貌似更加偏差新媒体方向,尽管编程常识也会学,甚至还学了那本西瓜书的《机器学习》。 大学前两年,本人就是一种糊里糊涂的状态。我没有很明确的指标和方向,每天都是在宿舍-食堂-教室,上好该上的课。 已经想拿个综测的业余第一,然而如同光靠问题还是不够的,起初规范降到了考试尽力考个高分就行。 对于学习数据结构、操作系统等等计算机专业课程,我有一个深深的感触:考试分数高不代表你真的“学会了” 。 这些根底课程,我根本都是上课认真听听,考前温习半个月,拿个不错的分数过了,感觉工作就实现了。 当初熬夜补这些常识的时候,眼里都是懊悔的泪水呀 ????。 大三,才意识到本人马上要毕业了,思考了一个月,放弃考研的打算。我想了很久很久,感觉还是做一个打工人吧! C/C++中的指针让我头晕眼花,于是我抉择了 Java。 2019 年 10 月,开始了本人在大学里,真正有指标,有能源的去学习! 在一个失眠焦虑的夜晚,我写下这段话来激励本人: 往年在综测时,拿到了业余第一,能够申请保研(我校保研个别只能保本校)。也波动过,秋招真的太难了,要不就放弃吧。然而想到本人大三时立下的雄心壮志,既然抉择了这条路,就一抹黑的走上来吧,秋招不上岸,春招还能搏一把;这条路切实走不通,那我就考研!而后,我就开始在 B 站、慕课网、油管、MOOC 上找 Java 的视频学习。 从 JavaSE、JavaWeb、框架的学习。2020 年 2 月份,仿佛感觉,把这些内容都过了一遍。 期间一边看网课、博客文章、Guide 哥的专栏总结,一边写博客加深了解。暑假租了房,每天循序渐进的输出,过年前几天才回家。过年那天早晨,都是一边看春晚,一边在温习。 03到 3 月份,意识的几个同学开始投滴滴、百度的实习,我才开始写简历,到牛客看面经,也筹备投实习。然而,看到面经的各种发问,我感觉本人像没学一样,全都是常识盲区。 ...

December 1, 2020 · 1 min · jiezi

关于spring:spring-cloud构建全球多租户分布式微服务部署的方案

最近在用spring cloud散布式微服务云架构做一个寰球多租户分布式部署的计划,我在这里只是简略的记录,以后的架构图只能是一个大略的计划,具体实施的计划和细节,IT老铁们能够本人去琢磨,因为业务链不同,细节也就不一样,不说那么多了,(企业架构源码能够加求球:三五三六二四七二五九)间接上图:

December 1, 2020 · 1 min · jiezi

关于spring:你知道什么是-Restful-风格吗SpringMVC-带我们实现它

Restful 格调的 API 是一种软件架构格调,设计格调而不是规范,只是提供了一组设计准则和约束条件。它次要用于客户端和服务器交互类的软件。基于这个格调设计的软件能够更简洁,更有档次,更易于实现缓存等机制。 在 Restful 格调中,用户申请的 url 应用同一个 url 而用申请形式:get,post,delete,put...等形式对申请的解决办法进行辨别,这样能够在前后台分离式的开发中使得前端开发人员不会对申请的资源地址产生混同和大量的查看办法名的麻烦,造成一个对立的接口。 SpringMVC Restful 格调 url 配置实现的形式SpringMVC 的 resturl 是通过 @RequestMapping 及 @PathVariable annotation 提供的,通过如 @RequestMapping(value="/blog /{id}",method=RequestMethod.DELETE) 即可解决 /blog/1 的 delete 申请。 GET(SELECT):从服务器查问,能够在服务器通过申请的参数辨别查问的 形式。POST(CREATE):在服务器端新建一个资源,调用 insert 操作。PUT(UPDATE):在服务器端更新资源,调用 update 操作。PATCH(UPDATE):在服务器端更新资源(客户端提供扭转的属性)。(目前 jdk7 未实现,tomcat7 不反对)。DELETE(DELETE):从服务器端删除资源,调用 delete 语句。案例实操Get 申请配置/***restful-->get 申请 执行查问操作 @param id@return*/@RequestMapping(value="queryAccountById02/{id}",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_UTF8_VALUE)@ResponseBodypublic MessageModel queryAccountById(@PathVariable Integer id){ MessageModel messageModel=new MessageModel(); if(null==id){ messageModel.setCode(300); messageModel.setMsg("参数非法!"); return messageModel; } messageModel.setResult(accountService.queryById(id)); return messageModel; } Post 申请配置/** ...

December 1, 2020 · 1 min · jiezi

关于spring:1-揭秘Spring类型转换-框架设计的基石

仰不愧天,俯不愧人,内不愧心。关注公众号【BAT的乌托邦】,有Spring技术栈、MyBatis、JVM、中间件等小而美的原创专栏供以收费学习。分享、成长,回绝浅尝辄止。本文已被 https://www.yourbatman.cn 收录。✍前言你好,我是YourBatman。Spring Framework是一个现代化的框架,俨然已倒退成为Java开发的基石。随着高度封装、高度智能化的Spring Boot的遍及,发现团队内越来越少的人晓得其深层次机制,哪怕只有一点点。这是让Spirng团队开心,但却是让应用的团队比拟担心的景象。若运行一个齐全黑箱程序无疑像抱着一个定时炸弹,总是如履薄冰、战战兢兢。团队内须要这样的同学来为它保驾护航,惊爆之时方可泰然自诺。所以,你违心pick吗?本系列将探讨Spring Framework里贯通其上下文,具备无足轻重位置的一个模块:类型转换(也可叫数据转换)。 ✍注释Java是个多类型且强类型语言,类型转换这个概念对它来说并不生疏。比方: 主动类型转换(隐式):小类型 -> 大类型。eg:int a = 10; double b = a;强制类型转换(显式):大类型 -> 小类型。eg:double a = 10.123; int b = (int)a; 阐明:强转有可能产生精度失落调用API类型转换:常见的是字符串和其它类型的互转。eg:parseInt(String); parseBoolean(String); JSON.toJSONString(Obj); LocalDate.parse(String) 阐明:API可能来自于JDK提供、一方库、二方库、三方库提供在企业级开发环境中,会遇到更为简单的数据转换场景,譬如说: 输出/传入一个规格字符串(如1,2,3,4),转换为一个数组输出/传入一个JSON串(如{"name":"YourBatman","age":18}),转换为一个Person对象输出/传入一个URL串(如:C:/myfile.txt、classpath:myfile.txt),转换为一个org.springframework.core.io.Resource对象虽说数据输出/传入绝大部分都会是字符串(如Http申请信息、XML配置信息),但构造能够千差万别,那么这就必然会波及到大量的数据类型、构造转换的逻辑。假使这都须要程序员本人手动编码做转换解决,那会让人望而却步甚至怯步。还好咱们有Spring。从本文起,A哥就帮你解密Spring Framework它是如何帮你接管类型转换,实现“自动化”的。有了此局部常识的储备,后续再探讨自动化数据绑定、自动化数据校验、Spring Boot涣散绑定等,所有都变得容易接受得多。 阐明:类型转换其实每个框架都会存在,其中Java畛域以Spring的实现最为经典,学会后便可触类旁通Spring类型转换Spring的类型转换也并非一步到位。齐全把握Spring的类型转换并非易事,须要有肯定的脉络按步骤进行。本文作为类型转换系列第一篇文章,将绘制目录纲要,将从以下几个方面逐渐展开讨论。 晚期类型转换之PropertyEditor晚期的Spirng(3.0之前)类型转换是基于Java Beans接口java.beans.PropertyEditor来实现的(全副继承自PropertyEditorSupport): public interface PropertyEditor { ... // String -> Object void setAsText(String text) throws java.lang.IllegalArgumentException; // Object -> String String getAsText(); ...}这类实现举例有: StringArrayPropertyEditor:,分隔的字符串和String[]类型互转PropertiesEditor:键值对字符串和Properties类型互转IntegerEditor:字符串和Integer类型互转...基于PropertyEditor的类型转换作为一种古老的、遗留下来的形式,是具备一些设计缺点的,如:职责不繁多,类型不平安,只能实现String类型的转换等。尽管自Spring 3.0起提供了现代化的类型转换接口,然而此局部机制始终得以保留,保障了向下兼容性。 阐明:Spring 3.0之前在Java畛域还未齐全站稳脚跟,因而良好的向下兼容显得尤为重要这块内容将在本系列前面具体篇章中失去专题详解,敬请关注。新一代类型转换接口Converter、GenericConverter为了解决PropertyEditor作为类型转换形式的设计缺点,Spring 3.0版本从新设计了一套类型转换接口,其中次要包含: Converter<S, T>:Source -> Target类型转换接口,实用于1:1转换 ...

December 1, 2020 · 1 min · jiezi

关于spring:Spring-源码学习-02关于-Spring-IoC-和-Bean-的概念

前言在前一篇文章中介绍了如何构建源码浏览环境,既然构建好了源码环境,本地也能够失常运行,那就开始浏览源码吧! 在浏览源码时,会参考官网文档,很多概念在官网都能够失去答案,有趣味的小伙伴们能够持续浏览,当做温习,写的不足之处,心愿多多领导。 IoC 和 DI IoCIoC(Inversion of Control),即管制反转。 之前是在对象外部 new 创立其余对象,而后应用。 而当初 Spring 中有一个容器能够在创立治理这些对象,并且将对象依赖的其余对象注入到这个对象中,这些对象的创立、销毁都由 Spring 进行治理。 相比以前来说,不再由本人管制其余对象的生命周期,这个过程就叫做管制反转。而负责对立治理这些类的容器就叫做 IoC 容器。 DIIoC is also known as dependency injection (DI). 是不是感觉奇奇怪怪的,为什么说:IoC 也称为 DI。 其实 IoC 和 DI 是同一个概念的不同角度形容。 依赖注入是指组件之间的依赖关系由容器在运行期决定,形象的说,即由容器动静的将某个依赖关系注入到组件之中。 通过依赖注入机制,咱们只须要通过简略的配置,而无需任何代码就可指定指标须要的资源,实现本身的业务逻辑,而不须要关怀具体的资源来自何处,由谁实现。 Spring 是通过 DI 实现 IoC 的。 Container 和 Bean Bean 是一个由 Spring IoC 容器实例化,组装和治理的对象。 置信大家都写过或者见过上面的代码: /** * 从容器中获取对象 * @author liuzhihang * @date 2020/4/6 19:02 */@Componentpublic class CustomBeanFactory implements ApplicationContextAware { private static ApplicationContext ctx; @Override public void setApplicationContext(ApplicationContext ac) throws BeansException { ctx = ac; } public static Object getBean(String beanName) { return ctx.getBean(beanName); }}代码逻辑很简略,就是从容器中获取到指定名称的 Bean,而其中 ApplicationContext 接口其实就是 Spring IoC 容器。 ...

December 1, 2020 · 1 min · jiezi

关于spring:Spring-IOC

Spring IOC次要内容Spring 框架Spring 框架概念 Spring 是泛滥开源java我的项目中的一员,基于分层的javaEE利用一站式轻量级开源框架,次要外围是 IOC(管制反转/依赖注入)与 AOP(面向切面)两大技术,实现我的项目在开发过程中的轻松解耦,进步我的项目的开发效率。 在我的项目中引入 Spring 立刻能够带来上面的益处 升高组件之间的耦合度,实现软件各层之间的解耦。能够应用容器提供的泛滥服务,如:事务管理服务、音讯服务等等。当咱们应用容器治理事务时,开发人员就不再须要手工管制事务.也不需解决简单的事务流传。 容器提供单例模式反对,开发人员不再须要本人编写实现代码。 容器提供了AOP技术,利用它很容易实现如权限拦挡、运行期监控等性能。 Spring 源码架构 Spring 总共大概有20个模块,由1300多个不同的文件形成。而这些组件被别离整合在外围容器(Core Container)、Aop(Aspect Oriented Programming)和设施反对(Instrmentation)、数据拜访及集成(Data Access/Integeration)、Web、报文发送(Messaging)、测试6个模块汇合中。 外围容器:Spring-beans 和 Spring-core 模块是 Spring 框架的外围模块,蕴含管制反转(Inversion of Control, IoC)和依赖注入(Dependency Injection, DI),外围容器提供 Spring 框架的基本功能。外围容器的次要组件是 BeanFactory,工厂模式的实现。BeanFactory 应用管制反转(IOC) 思维将应用程序的配置和依赖性标准与理论的利用程序代码离开。Spring 上下文Spring Context:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包含企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度性能。 Spring-Expression 模块是对立表达式语言(unified EL)的扩大模块,能够查问、治理运行中的对象,同时也不便的能够调用对象办法、操作数组、汇合等。它的语法相似于传统EL,但提供了额定的性能,最出色的要数函数调用和简略字符串的模板函数。 Spring-AOP:Spring-aop是Spring的另一个外围模块, 在Spring中,他是以JVM的动静代理技术为根底,而后设计出了一系列的Aop横切实现,比方前置告诉、返回告诉、异样告诉等。通过其配置管理个性,Spring AOP 模块间接将面向切面的编程性能集成到了 Spring 框架中。所以,能够很容易地使 Spring 框架治理的任何对象反对 AOP。Spring Data Access(数据拜访):由Spring-jdbc、Spring-tx、Spring-orm、Spring-jms和Spring-oxm 5个模块组成 Spring-jdbc 模块是 Spring 提供的JDBC形象框架的次要实现模块,用于简化 Spring JDBC。Spring-tx 模块是SpringJDBC事务管制实现模块。应用Spring框架,它对事务做了很好的封装,通过它的Aop配置,能够灵便的配置在任何一层。 ...

December 1, 2020 · 15 min · jiezi

关于spring:根据RequestMapping原理实现自定义注解

依据@RequestMapping原理实现自定义注解基于最近的一个需要:客户端与服务端通过socket连贯,在socket通道里传输信息,在信息里定义一个type辨别客户端的申请类型,依据这个类型找到对应的业务解决逻辑。这不就是依据url解析对应门路找到Controller吗!于是间接开始撸@RequestMapping源码。 @RequestMapping源码剖析间接看到 AbstractHandlerMethodMapping中afterPropertiesSet() /** * 在初始化时检测处理程序办法 * @see #initHandlerMethods */@Overridepublic void afterPropertiesSet() { initHandlerMethods();}/** * 在ApplicationContext中扫描bean,检测并注册处理程序办法 * SCOPED_TARGET_NAME_PREFIX示意域代理bean的前缀 * @see #getCandidateBeanNames() * @see #processCandidateBean * @see #handlerMethodsInitialized */protected void initHandlerMethods() { for (String beanName : getCandidateBeanNames()) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { processCandidateBean(beanName); } } handlerMethodsInitialized(getHandlerMethods());}在properties属性加载好之后就会初始化程序处理办法initHandlerMethods(),getCandidateBeanNames() 获取上下文中beanName,processCandidateBean(beanName)只解决不是域代理bean的bean,而后咱们看看processCandidateBean() protected void processCandidateBean(String beanName) { Class<?> beanType = null; try { beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isTraceEnabled()) { logger.trace("Could not resolve type for bean '" + beanName + "'", ex); } } // beanType != null 示意确定具备给定名称bean的类型 // isHandler(beanType)示意是否被@Controller和@RequestMapping标注 if (beanType != null && isHandler(beanType)) { detectHandlerMethods(beanName); }}/** * org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#isHandler * 提供实现 */ @Override protected boolean isHandler(Class<?> beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); }而后再看看detectHandlerMethods() 就是在指定的bean外面查找以后对应的method ...

November 30, 2020 · 6 min · jiezi

关于spring:SpringMVC全局异常处理的方式有哪些呢

在 JavaEE 我的项目的开发中,不论是对底层的数据库操作过程,还是业务层的处理过程,还是管制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异样须要解决。每个过程都独自解决异样,零碎的代码耦合度高,工作量大且不好对立,保护的工作量也很大。 SpringMvc 对于异样解决这块提供了反对,通过 SpringMvc 提供的全局异样解决机制,可能将所有类型的异样解决从各个处理过程解耦进去,这样既保证了相干处理过程的性能较繁多,也实现了异样信息的对立解决和保护。 SpringMVC全局异样解决的三种形式应用 Spring MVC 提供的简略异样处理器 SimpleMappingExceptionResolver;实现 Spring 的异样解决接口 HandlerExceptionResolver 自定义本人的异样处理器;应用 @ExceptionHandler 注解实现异样解决;案例实操全局异样解决形式一配置 SimpleMappingExceptionResolver 对象 <bean class="org.springframework.web.servlet.handler.SimpleMappingException Resolver"> <property name="defaultErrorView" value="error"></property> <property name="exceptionAttribute" value="ex"></property> <property name="exceptionMappings"> <props> <prop  key="com.xxx.exception.BusinessException">error1</prop> <prop  key="com.xxx.exception.ParamsException">error2</prop> </props> </property></bean> 应用 SimpleMappingExceptionResolver 进行异样解决,具备集成简略、有良好的扩展性、对已有代码没有入侵性等长处,但该办法仅能获取到异样信息,若在出现异常时,对须要获取除异样以外的数据的状况不实用。 全局异样解决形式二实现 HandlerExceptionResolver 接口 @Componentpublic class GlobalException implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { Map<String,Object> map=new HashMap<String, Object>(); map.put("ex", ex); ModelAndView mv=null; if(ex instanceof ParamsException){ return new ModelAndView("error_param", map); } if(ex instanceof BusinessException){ return new ModelAndView("error_business", map); } return new ModelAndView("error", map); } } ...

November 30, 2020 · 1 min · jiezi

关于spring:spring-cloud构建java版-多租户-b2b2c-o2o电子商务云商平台

外围架构:Spring Cloud、Spring Boot、Mybatis、Redis、Bootstrap html5+css3、小程序、原生APP 核心思想:产品微服务、模块化、原子化、继续集成、分布式、集群部署 开发模式:代码生成工具、驱动式开发模式、进步开发效率 JDK:JDK 1.8+(企业架构源码能够加求球:三五三六二四七二五九) 数据库:MYSQL 5.6+

November 30, 2020 · 1 min · jiezi

关于spring:转SpringBoot启动源码解读2

https://www.jianshu.com/p/1fd071f56b3a

November 28, 2020 · 1 min · jiezi

关于spring:SSMSpring

1 spring概述spring是分层的JavaSE及JavaEE利用于全栈的轻量级开源框架,以 IoC (Inverse Of Control:管制反转/反转管制)和 AOP (Aspact Oriented Programming:面向切面编程)为外围,提供了体现层SpringMVC和长久层Spring JDBC以及业务层事务管理等泛滥模块的企业级利用技术,还能整合开源世界中泛滥 驰名的第三方框架和类库,逐步成为应用多的JavaEE企业应用开源框架。 spring框架次要用来解决业务间的逻辑,如账号注册时的用户名判断等等。 spring框架其中最外围的是:IoC管制反转、DI依赖注入、SpringAOP面向切面编程、事务管制。 1.1 spring的架构:Spring 初的指标就是要整合所有优良资源,而后对外提供一个对立的服务。 Spring 模块构建在外围容器之上,外围容器定义了创立、配置和治理 bean 的形式, 如下图所示:组成 Spring 框架的每个模块(或组件)都能够独自存在,或者与其余一个或多 个模块联结实现。每个模块的性能如下: 2 IoC+DIIoC是设计思维,IoC有三个外围:BeanFactory、反射、DI。BeanFactory利用反射实现对象的创立,DI实现对象关系治理。 2.1 IoC管制反转IOC(Inverse Of Control)管制反转,即,把创建对象的权力交给框架。也就是指将对象的创立、对象的存储、对象的治理交给了spring容器。 2.1.1 spring中的IoC的实现第一步:创立maven我的项目spring第二步:在pom文件中增加junit、spring依赖 <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.3.RELEASE</version> </dependency>第三步:在工程的src/main/resources目录下,创立applicationContext.xml文件 <?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.xsd"> <!-- 将EmpService接口的实现类作为bean注册到spring容器中 即 让spring容器创立该类的实例(对象) 如果注册的类有父接口,id值通常是接口名(首字母小写) 如果注册的类没有父接口,id值通常为类名(首字母小写) --> <bean id="empService" class="com.tedu.service.EmpServiceImpl02"></bean> <!-- 将User类作为bean注册到spring容器中, 也就是由spring容器 负责创立该类的实例 scope="singleton|prototype",默认值是singleton,示意单实例 如果将scope值改为prototype,则每次都会创立新的User实例,也就 是多实例 --> <!-- (2)构造方法注入 --> <bean id="user" class="com.tedu.pojo.User"> <constructor-arg name="name" value="马云"/> <constructor-arg name="age" value="30"/> <constructor-arg name="info" ref="userInfo"/> </bean> <!-- 将UserInfo类作为bean注册到spring容器中 --> <bean id="userInfo" class="com.tedu.pojo.UserInfo"></bean> </beans>第四步:创立测试类TestSpring,进行测试 ...

November 28, 2020 · 4 min · jiezi

关于spring:转springdatajpa自定义Repository

https://www.jianshu.com/p/21d5edb28262

November 28, 2020 · 1 min · jiezi

关于spring:一张图彻底理解Spring如何解决循环依赖

写在后面最近,在看Spring源码,看到Spring解决循环依赖问题的源码时,不得不说,源码写的太烂了。像Spring这种顶级的我的项目源码,居然存在着这种xxx的代码。看了几次都有拍板大,置信很多小伙伴都会跟我有一样的感触。怎么办呢?还是踏下心来,缓缓啃源码。最终,我将Spring如何解决循环依赖的源码总结成上面的流程图,这样,依据流程图读源码就清晰多了!!图解Spring循环依赖Spring解决循环依赖问题的源码写的的确挺烂的,就是一顿 if + else 的嵌套操作。临时还是不给小伙伴们上源码了。我将Spring解决循环依赖问题的源码总结成上面的流程图,看起来就清晰多了,联合流程图看Spring源码,事倍功半。 不多说了,上图: 说句实在话,看Spring源码,总结,画图。输入下面这张图就花了我将近3个小时。小伙们联合这张图看Spring源码吧,置信肯定不会让你悲观。如果对你有帮忙的话,请点个赞、给个在看和转发。 好了,明天就到这儿吧,我是冰河,咱们下期见~~

November 27, 2020 · 1 min · jiezi

关于spring:spring-cloud20构建分布式企业微服务云架构搭建commonservice跟项目

咱们先从搭建通用服务开始,首先沟通maven创立commonservice的根我的项目,外面有一些根底的配置信息,如:版本控制、打包、编译、依赖、通用包配置、模块等,我间接将代码帖进来,心愿大家可能了解的更到位:(企业架构源码能够加求球:三五三六二四七二五九) 1. <span style="font-size: 16px;"><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 3. <modelVersion>4.0.0</modelVersion> 4. <groupId>com.honghu.cloud</groupId> 5. <artifactId>commonservice</artifactId> 6. <version>2.0</version> 7. <packaging>pom</packaging> 9. <modules> 10. <module>commonservice-eureka</module> 11. <module>commonservice-config</module> 12. <module>commonservice-gateway</module> 13. <module>commonservice-oauth</module> 14. <module>commonservice-monitor</module> 15. <module>commonservice-turbine</module> 16. <module>commonservice-admin</module> 17. <module>commonservice-log</module> 18. <module>commonservice-file</module> 19. <module>commonservice-notification</module> 20. <module>commonservice-sequence</module> 21. </modules> 23. <parent> 24. <groupId>org.springframework.boot</groupId> 25. <artifactId>spring-boot-starter-parent</artifactId> 26. <version>2.0.4.RELEASE</version> 27. </parent> 29. <properties> 30. <spring-cloud.version>Finchley.RELEASE</spring-cloud.version> 31. <mybatis.version>1.3.2</mybatis.version> 32. <jwt.version>0.9.0</jwt.version> 33. <fastjson.version>1.2.47</fastjson.version> 34. <commons-collections>4.1</commons-collections> 35. <monitor.version>2.0.2</monitor.version> 36. <swagger.version>2.8.0</swagger.version> 37. <aliyun-sdk-oss.version>2.8.2</aliyun-sdk-oss.version> 38. <aliyun-sdk-core.version>3.2.8</aliyun-sdk-core.version> 39. <aliyun-sdk-dysmsapi.version>1.1.0</aliyun-sdk-dysmsapi.version> 40. <elasticsearch.version>6.2.3</elasticsearch.version> 41. <security-oauth2.version>2.3.3.RELEASE</security-oauth2.version> 42. <docker.image.prefix>springboot</docker.image.prefix> 43. </properties> 45. <dependencies> 46. <dependency> 47. <groupId>org.springframework.boot</groupId> 48. <artifactId>spring-boot-starter-actuator</artifactId> 49. </dependency> 50. <dependency> 51. <groupId>org.springframework.boot</groupId> 52. <artifactId>spring-boot-starter-test</artifactId> 53. <scope>test</scope> 54. </dependency> 55. <dependency> 56. <groupId>org.projectlombok</groupId> 57. <artifactId>lombok</artifactId> 58. </dependency> 59. <dependency> 60. <groupId>com.alibaba</groupId> 61. <artifactId>fastjson</artifactId> 62. <version>${fastjson.version}</version> 63. </dependency> 64. <dependency> 65. <groupId>org.apache.commons</groupId> 66. <artifactId>commons-lang3</artifactId> 67. </dependency> 68. <dependency> 69. <groupId>org.apache.commons</groupId> 70. <artifactId>commons-collections4</artifactId> 71. <version>${commons-collections}</version> 72. </dependency> 73. </dependencies> 75. <dependencyManagement> 76. <dependencies> 77. <dependency> 78. <groupId>org.springframework.cloud</groupId> 79. <artifactId>spring-cloud-dependencies</artifactId> 80. <version>${spring-cloud.version}</version> 81. <type>pom</type> 82. <scope>import</scope> 83. </dependency> 84. <dependency> 85. <groupId>org.mybatis.spring.boot</groupId> 86. <artifactId>mybatis-spring-boot-starter</artifactId> 87. <version>${mybatis.version}</version> 88. </dependency> 89. <dependency> 90. <groupId>io.jsonwebtoken</groupId> 91. <artifactId>jjwt</artifactId> 92. <version>${jwt.version}</version> 93. </dependency> 94. </dependencies> 95. </dependencyManagement> 97. </project></span> 根底配置:groupId、artifactId、version(2.0版本) ...

November 27, 2020 · 2 min · jiezi

关于spring:Spring-源码阅读环境的搭建

前言本文记录了 Spring 源码环境的搭建形式,以及踩过的那些坑!以后版本:5.3.2-SNAPSHOT。 环境筹备GitJDK master 分支须要 JDK 115.2.x 分支, JDK8 即可Gradle 6.5.1IDEA 最新 (2020.2.3)Spring 源码仓库地址:https://github.com/spring-projects/spring-framework 下载源码clone 源码git clone https://github.com/spring-projects/spring-framework.git应用 IDEA 关上 期待 IDEA 加载实现即可。注: 也能够指定 clone 的分支 git clone -b 5.2.x https://github.com/spring-projects/spring-framework.git或者先 fork 到本人的仓库,而后再 clone。 这里我是 fork 到我的仓库,而后再 clone 的。 以后 master 分支代表的版本为 5.3.2-SNAPSHOT。 执行测试在我的项目右键创立 module 抉择 Gradle Java 创立 module 在 build.gradle 中增加配置compile(project(":spring-context")) 创立测试类并测试 其中 UserComponent 增加了 @Component 注解, 程序失常执行则所有 OK。能够开始欢快的调试代码了。 问题总结编译失败有小伙伴间接下载 zip 包,可能遇到以下问题:(十分不倡议间接下载 zip 包构建,想晓得起因能够持续看,最初我也没有构建胜利,而是间接通过 clone 构建的。) ...

November 27, 2020 · 1 min · jiezi

关于spring:八Java版Spring-Cloud-B2B2C-o2o鸿鹄云商平台平台管理功能清单设计

明天咱们次要来解说平台治理的功能设计,业界的b2b2c产品是比拟成熟的,置信很多的敌人也理解一些,咱们做的是java版本多租户b2b2c电子商务平台,整个平台的治理包含会员、商户入驻、商品(包含自营)、经营流动(包含自营)、订单(包含自营)、结算等外围性能。思考到自营和商家入驻的数据隔离,也思考到用户对b2b2c产品的拆分(如:b2c,只须要自营店铺公布商品即可),目前自营店铺和商家店铺是齐全离开的。 我这边不做过多介绍了,产品经理参考了同行业的b2b2c电子商务平台,Spring Cloud B2B2C o2o鸿鹄云商平台也是站在伟人的肩膀下来施行产品布局和研发,另外产品经理通过市场调研,也收集了不少用户提出的业务场景和问题,咱们也联合市场的变动,紧跟市场须要,做了平台性能的布局,如下: 鸿鹄B2B2C后盾治理平台: 快捷菜单 零碎设置:根本设置、FTP设置、上传设置、SEO、Email、短信、告诉模板、管理员、领取形式、罕用地区、运费区域、快递设置、快递公司、推送、二级域名设置等。 商品治理:分类、品牌、商品、规格、展现类目等。 装修治理:首页治理、橱窗治理、专题、频道治理。 自营相干:自营治理、自营流动、自营订单。 店铺治理:入驻治理、店铺治理、店铺类型、调整治理、商家服务。 会员:会员治理、会员级别、告诉、积分治理、积分明细、预贷款(明细)、图片治理、增票资质、分享列表、动静列表。 交易治理:订单治理、订单设置、征询治理、投诉治理、退货治理、订单退款、充值接口(列表)、用户统计、订单统计、商品统计、地区统计。 网站:文章分类,文章治理、零碎文章、合作伙伴、页面导航。 经营治理:根底设置、金币治理、竞价直通车、平台充值卡、短信音讯治理、自提点治理、广告治理、积分规定、积分商城、流动治理、团购治理、团购设置、组合销售、满就减治理、满就送治理、0元试用治理、版本治理、经营版本治理。 新闻征询:征询分类、征询治理、征询回复、征询楼层。 微商城:根底设置、微信素材治理、微信首页楼层治理、微商城商品、微商城生存购列表、二级频道治理。 系统管理:结算设置、结算治理、缓存治理、数据库治理、搜索引擎、数据库监控. iteye的图片出不来,可能服务器在降级,大家如果要看导图,能够间接拜访: https://www.jianshu.com/p/1d2230743b49 以上是我参加的Spring Cloud B2B2C O2O鸿鹄云商平台-平台治理性能清单设计,从当初开始,我会将每一个细节点落实到文章上,心愿可能帮忙更多的敌人。(企业架构源码能够加求球:三五三六二四七二五九)

November 26, 2020 · 1 min · jiezi

关于spring:Spring-对Apache-Kafka的支持与集成

1. 引言Apache Kafka 是一个分布式的、容错的流解决零碎。在本文中,咱们将介绍Spring对Apache Kafka的反对,以及原生Kafka Java客户端Api 所提供的形象级别。 Spring Kafka 通过 @KafkaListener 注解,带来了一个简略而典型的 Spring 模板编程模型,它还带有一个 KafkaTemplate 和音讯驱动的 POJO 。 2. 装置和设置要下载和装置Kafka,请参考官网指南。而后还须要在 pom.xml 文件中增加 spring-kafka: <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>2.3.7.RELEASE</version></dependency>新建一个 Spring Boot 示例应用程序,以默认配置启动。 3. 配置 Topics以前咱们应用命令行工具在 Kafka 中创立 topic,例如: $ bin/kafka-topics.sh --create \ --zookeeper localhost:2181 \ --replication-factor 1 --partitions 1 \ --topic mytopic然而随着 AdminClient 在Kafka中的引入,咱们当初能够通过编程来创立 Topic 。 如下代码,增加 KafkAdmin bean 到 Spring中,它将主动为 NewTopic 类的所有 bean 增加 topic : @Configurationpublic class KafkaTopicConfig { @Value(value = "${kafka.bootstrapAddress}") private String bootstrapAddress; @Bean public KafkaAdmin kafkaAdmin() { Map<String, Object> configs = new HashMap<>(); configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); return new KafkaAdmin(configs); } @Bean public NewTopic topic1() { return new NewTopic("developlee", 1, (short) 1); }}4. 音讯生成要创立音讯,首先须要配置 ProducerFactory ,并设置创立 Kafka Producer 实例的策略,而后应用 KafkaTemplate。 KafkaTemplate 包装了 Producer 实例,并提供向 Kafka Topic 发送音讯的简便办法。 ...

November 26, 2020 · 3 min · jiezi

关于spring:七Java版Spring-Cloud-B2B2C-o2o鸿鹄云商平台微服务层设计

上一篇文章咱们介绍了鸿鹄云商b2b2c o2o微服务部署计划,其实很多读者都在关注微服务层是如何设计的,其中包含微服务架构、规定流程、定义规范,其实本篇文章不想过多的反复介绍,之前有给大家解说过微服务架构图和部署解决方案,上面间接通过一张设计图给大家整体介绍鸿鹄云商b2b2c微服务层设计,前面咱们会通过分析所有性能点,将具体的业务和设计过程具体解说,也心愿更多的人理解鸿鹄云商b2b2c平台的设计方案。(企业架构源码能够加求球:三五三六二四七二五九) 以上是我参加的Spring Cloud B2B2C O2O鸿鹄云商平台-微服务层设计方案,从当初开始,我会将每一个细节点落实到文章上,心愿可能帮忙更多的敌人。

November 25, 2020 · 1 min · jiezi

关于spring:68篇干货手把手教你通关-Spring-Security

Spring Security 系列前前后后整了 68 篇文章了,是时候告一个段落了。 这两天松哥抽空把该系列的文章整顿了一下,做成了一个索引,不便小伙伴们查找。 教程地址如下: http://www.javaboy.org/springsecurityhttp://www.itboyhub.com/springsecurity对应的 Demo 地址如下: https://github.com/lenve/spring-security-sampleshttps://github.com/lenve/oauth2-samples后面 javaboy.org 是国外服务器,如果响应慢小伙伴只须要 xxx 即可,不须要我多说了吧。 前面的 itboyhub.com 是国内服务器,尽管松哥曾经买了 CDN 减速服务了,然而响应速度如同还是一般般,所以文末松哥也给出了微信公众号的文章索引。 小伙伴们依照松哥曾经排列好的程序,一篇一篇练级通关吧! 文章索引: 挖一个大坑,Spring Security 开搞!松哥手把手带你入门 Spring Security,别再问明码怎么解密了手把手教你定制 Spring Security 中的表单登录Spring Security 做前后端拆散,咱就别做页面跳转了!通通 JSON 交互Spring Security 中的受权操作原来这么简略Spring Security 如何将用户数据存入数据库?Spring Security+Spring Data Jpa 强强联手,平安治理只有更简略!Spring Boot + Spring Security 实现主动登录性能Spring Boot 主动登录,平安危险要怎么管制?在微服务项目中,Spring Security 比 Shiro 强在哪?SpringSecurity 自定义认证逻辑的两种形式(高级玩法)Spring Security 中如何疾速查看登录用户 IP 地址等信息?Spring Security 主动踢掉前一个登录用户,一个配置搞定!Spring Boot + Vue 前后端拆散我的项目,如何踢掉已登录用户?Spring Security 自带防火墙!你都不晓得本人的零碎有多平安!什么是会话固定攻打?Spring Boot 中要如何进攻会话固定攻打?集群化部署,Spring Security 要如何解决 session 共享?松哥手把手教你在 SpringBoot 中进攻 CSRF 攻打!so easy!要学就学透彻!Spring Security 中 CSRF 进攻源码解析Spring Boot 中明码加密的两种姿态!Spring Security 要怎么学?为什么肯定要成体系的学习?Spring Security 两种资源放行策略,千万别用错了!松哥手把手教你入门 Spring Boot + CAS 单点登录Spring Boot 实现单点登录的第三种计划!Spring Boot+CAS 单点登录,如何对接数据库?Spring Boot+CAS 默认登录页面太丑了,怎么办?用 Swagger 测试接口,怎么在申请头中携带 Token?Spring Boot 中三种跨域场景总结Spring Boot 中如何实现 HTTP 认证?Spring Security 中的四种权限管制形式Spring Security 多种加密计划共存,老破旧零碎整合利器!神奇!本人 new 进去的对象一样也能够被 Spring 容器治理!Spring Security 配置中的 and 到底该怎么了解?一文搞定 Spring Security 异样解决机制!写了这么多年代码,这样的登录形式还是头一回见!Spring Security 居然能够同时存在多个过滤器链?Spring Security 能够同时对接多个用户表?在 Spring Security 中,我就想从子线程获取用户登录信息,怎么办?深刻了解 FilterChainProxy【源码篇】深刻了解 SecurityConfigurer 【源码篇】深刻了解 HttpSecurity【源码篇】深刻了解 AuthenticationManagerBuilder 【源码篇】花式玩 Spring Security ,这样的用户定义形式你可能没见过!深刻了解 WebSecurityConfigurerAdapter【源码篇】盘点 Spring Security 框架中的八大经典设计模式Spring Security 初始化流程梳理为什么你应用的 Spring Security OAuth 过期了?松哥来和大家捋一捋!一个诡异的登录问题什么是计时攻打?Spring Boot 中该如何进攻?Spring Security 中如何让下级领有上级的所有权限?Spring Security 权限治理的投票器与表决机制Spring Security 中的 hasRole 和 hasAuthority 有区别吗?Spring Security 中如何细化权限粒度?一个案例演示 Spring Security 中粒度超细的权限管制!Spring Security 中最风行的权限治理模型!我又发现 Spring Security 中一个小机密!聊一个 GitHub 上开源的 RBAC 权限管理系统,很6!RBAC 案例解读【2】上面是 OAuth2 相干的技能点: ...

November 25, 2020 · 1 min · jiezi

关于spring:五Java版Spring-Cloud-B2B2C-o2o鸿鹄云商平台技术框架3

上一篇文章咱们介绍了spring cloud框架几个外围组件,本篇文章思考到我的项目的部署计划及服务与服务之间的组合及合作能力,咱们从这两方面动手着手讲一下鸿鹄云商b2b2c平台技术框架解决方案。 Docker资源的对立部署、调配和动静负载平衡治理 由Master对立治理Docker中各Pod利用的部署、调配和动静负载平衡当某利用长期高负载或业务量增长须要,须要调配资源时,由Master对立治理疾速部署和动静调配;应用实现后再疾速开释资源计划: 采纳Kubernetes + Docker解决方案搭建了一个灵便的企业级集群治理平台。通过在Kubernetes + Docker集群中减少内部硬件负载均衡器,代替service软负载平衡性能,晋升零碎负载平衡能力和稳定性。实现集群节点状态的变动实时与负载均衡器同步,保障集群的扩张和节点的状态变动可能实时的反馈到负载均衡器的策略上。客户收益: 采纳Kubernetes + Docker集群治理平台,实现了开发/测试/生产环境的无效隔离和利用的一次构建、随处运行,很好地撑持了华创疾速的业务倒退。基于Kubernetes+Docker的星散群治理平台计划,极大进步了大规模利用疾速部署的灵活性,和零碎快捷的程度扩大能力。 微服务框架组件组合与合作 0: 载入/更新配置(企业架构源码能够加求球:三五三六二四七二五九) 1: API网关与服务端注册服务 2: 显示层/介接零碎调用服务前的发现服务 3: 显示层/介接零碎透过API网关调用服务 4: API网关调用服务端前的发现服务 5: API网关通过调用端负载平衡机制调用服务端 6: 服务端调用另一服务端前的发现服务 7: 服务端通过调用端负载平衡机制调用另一服务端 以上是我参加的Spring Cloud B2B2C O2O鸿鹄云商平台-技术框架解决方案,从当初开始,我会将每一个细节点落实到文章上,心愿可能帮忙更多的敌人。

November 24, 2020 · 1 min · jiezi

关于spring:springbootwebmvc

springboot默认反对反对一个模板引擎,这个引擎能够以html作为模板,咱们能够在模板增加thymeleaf自定义标签属性,而后基于属性操作数据,这种技术次要取代jsp!templates下的网页不能间接通过浏览器url进行拜访,须要基于后端控制器,在办法中定义页面响应![QZSZ0A`2O~S\)PH2WGDW\(\]EY.png](/img/bVcKHEr)常见谬误 如果default.html要在放在templates子目录中,则还须要在配置文件中配置thymeleaf的前缀![~4ZS1G2GD9\]SVQE~R8PHX$J.png](/img/bVcKHHg)spring.thymeleaf.prefix=classpath:/templates/module/

November 23, 2020 · 1 min · jiezi

关于spring:差点跪了阿里3面真题CAP和BASE理论了解么可以结合实际案例说下不

本文节选自我开源的 JavaGuide :https://github.com/Snailclimb/JavaGuide (Github标星92k+!一份涵盖大部分 Java 程序员所须要把握的外围常识。筹备 Java 面试,首选 JavaGuide!)经验过技术面试的小伙伴想必对这个两个概念曾经再相熟不过了! Guide哥当年加入面试的时候,不夸大地说,只有问到分布式相干的内容,面试官简直是必定会问这两个分布式相干的实践。 并且,这两个实践也能够说是小伙伴们学习分布式相干内容的根底了! 因而,小伙伴们十分十分有必要将这实践搞懂,并且可能用本人的了解给他人讲进去。 这篇文章我会站在本人的角度对这两个概念进行解读! 集体能力无限。如果文章有任何须要改善和欠缺的中央,欢送在评论区指出,共同进步!——爱你们的Guide哥 CAP实践CAP 实践/定理起源于 2000年,由加州大学伯克利分校的Eric Brewer传授在分布式计算原理研讨会(PODC)上提出,因而 CAP定理又被称作 布鲁尔定理(Brewer’s theorem) 2年后,麻省理工学院的Seth Gilbert和Nancy Lynch 发表了布鲁尔猜测的证实,CAP实践正式成为分布式畛域的定理。 简介CAP 也就是 Consistency(一致性)、Availability(可用性)、Partition Tolerance(分区容错性) 这三个单词首字母组合。 CAP 实践的提出者布鲁尔在提出 CAP 猜测的时候,并没有具体定义 Consistency、Availability、Partition Tolerance 三个单词的明确定义。 因而,对于 CAP 的民间解读有很多,个别比拟被大家举荐的是上面 ???? 这种版本的解。 在实践计算机科学中,CAP 定理(CAP theorem)指出对于一个分布式系统来说,当设计读写操作时,只能能同时满足以下三点中的两个: 一致性(Consistence) : 所有节点拜访同一份最新的数据正本可用性(Availability): 非故障的节点在正当的工夫内返回正当的响应(不是谬误或者超时的响应)。分区容错性(Partition tolerance) : 分布式系统呈现网络分区的时候,依然可能对外提供服务。什么是网络分区? 分布式系统中,多个节点之前的网络原本是连通的,然而因为某些故障(比方局部节点网络出了问题)某些节点之间不连通了,整个网络就分成了几块区域,这就叫网络分区。 不是所谓的“3 选 2”大部分人解释这一定律时,经常简略的表述为:“一致性、可用性、分区容忍性三者你只能同时达到其中两个,不可能同时达到”。实际上这是一个十分具备误导性质的说法,而且在 CAP 实践诞生 12 年之后,CAP 之父也在 2012 年重写了之前的论文。 当产生网络分区的时候,如果咱们要持续服务,那么强一致性和可用性只能 2 选 1。也就是说当网络分区之后 P 是前提,决定了 P 之后才有 C 和 A 的抉择。也就是说分区容错性(Partition tolerance)咱们是必须要实现的。简而言之就是:CAP 实践中分区容错性 P 是肯定要满足的,在此基础上,只能满足可用性 A 或者一致性 C。 ...

November 23, 2020 · 2 min · jiezi

关于spring:小游戏2048最佳算法怎么实现思路全解析

1.简介很多人都玩过2048,我就比拟老套,因为我一贯看不上这类单机游戏。然而就在某一天泡脚的无聊时光,拿了媳妇儿的手机,左看看右点点,莫名关上了2048。嗯... 这真是一款打发无聊时光的 "good game"。通过滑动来使得每行或每列相邻并且雷同的数字相加而失去一个最大的数字,最初的数字越大,得分越高!于是,我在想,是否能像魔方一样,有肯定的套路来帮忙咱们决定每一步该往哪个方向滑动最佳,以便取得最好的问题呢? 2.如何玩20482048是在4×4方格中玩的游戏。方格的每个地位都可能是空的,也可能是一个带有数字的方块。 开始游戏时,方格上会在随机地位产生两个方块,数字为“ 2”或“ 4”。每个方块都有10%的几率是“ 4”,否则为“2”。 通过将所有方块向某个方向(上,下,左或右)挪动来进行游戏。这样做时,彼此相邻且一起挪动的具备雷同值的所有方块将合并成一个新的方块,该方块的值等于前两个方块的和: 进行滑动后,将在随机地位产生一个新的方块。新方块有 90% 的几率为 ”2“, 10% 的几率是 ”4“。 而后,持续进行游戏,直到方格中不再有能挪动的方块为止。 按理来说,这游戏的指标是达到一个值为“ 2048”的方块就完结了。然而,we never stop,咱们能够持续进行游戏,来争取更大的胜利。实践上,方块最大值为 “ 131072” 。 3.问题阐明想要解决这个游戏,是个灰常因缺斯汀的问题。因为咱们不仅要正确预测每个新方块产生的地位,而且还要正确地预测它是“ 2”还是“ 4”。这是随机事件,实践上每一次都预测正确是不可能的。 因而,不可能有一种算法每次都能轻松而正确解决难题。咱们能尽可能做到的玩好这个概率游戏,确定每个步骤的最佳操作。 不论什么时候,咱们只能采取四种行为,而后面临的挑战是确定这四项动作中哪一项将获得最佳的长期成果。 咱们的算法基于 [Expectimax] 算法,它自身是 [Minimax] 算法的一种变体,然而树的路由会依据它们产生的可能性进行加权。 从实质上讲,咱们将游戏视为两人游戏: 玩家一(人类玩家)能够向四个方向的某个方向挪动方块。玩家二(计算机玩家)能够将方块搁置在方格的任一空白地位。基于此,咱们能够依据每个动作产生的概率对每个动作生成后果树。而后,这能够为咱们提供确定哪种人员行动可能给出最佳后果所需的详细信息。 3.1. 游戏流程图游戏玩法的个别流程: 咱们能够在“增加随机方块”过程中看到游戏的随机性——既要找到随机的正方形来增加方块,又要为方块抉择一个随机值。 而后,咱们面临的挑战是在“确定下一步口头”步骤中确定要做什么。这是咱们玩游戏的算法。 总体上看似看似简略: 咱们须要做的是模仿每一种可能,确定哪个滑动给出最佳后果,而后应用它。 因而,咱们当初将算法简化为模仿任何给定的挪动并为后果生成分数。 这是一个分为两局部的过程。第一步是看是否能够挪动,如果不能挪动,则以“ 0”的分数提前停止。如果能够挪动,那么咱们将持续进行真正的算法,在该算法中确定挪动的成果如何: 3.2 确定下一步口头到目前为止,算法的次要局部是模仿滑动,然而要害的问题是:如何为每个可能的挪动进行评分。这下就是 Expectimax 算法发挥作用的时候了! 我将模仿两个玩家的所有可能动作,并进行几个步骤,而后看看其中哪个能带来最佳后果。 对于人类玩家而言,只有“上”,“下”,“左”和“右”的这四个动作。对于计算机则是,将“ 2”或“ 4” 方块随机搁置在空白的地位: 该算法是递归的,每个递归步骤只有在间隔实在游戏中的理论挪动有肯定深度时才会进行。这样导致流程图会循环返回本身,但实际上咱们将这么做: 1.如果处于极限深度则进行,为以后模仿的方格计算分数。2.计算机模仿所有可能的挪动:模仿任何可能的人类玩家挪动,返回人的挪动,并计算出的分数。3.对模仿挪动计算出的分数相加,而后对该挪动产生的可能性进行加权。实现此操作后,咱们将所有计算出的分数相加,这就是咱们要从以后游戏板上进行的挪动的最终分数。因为咱们执行了四次操作(从以后游戏界面开始,每个可能的动作都取得一个),所以咱们最终失去了四个分数,其中得分最高的就是应该做出的动作。 3.3. 计分此时,剩下要做的就是计算方格的分数。但还须要思考,如何从这个地位持续得分。 通过增加几个因素以及适当的权重,能够实现很多办法。例如: 空方块数可能合并的次数——即,两个相邻地位中雷同数字的次数每个方块上的最大值所有方块的总和方格的单一性——确定方格的构造好坏,使得方块的值在一个方向上减少。4.伪代码当初咱们晓得了算法的工作原理,接下来摸索一些详细描述算法的伪代码。 我对游戏的理论玩法并不感冒,只对确定挪动的算法有点趣味,所以从这里开始: ...

November 23, 2020 · 1 min · jiezi