欢迎您访问EasyBlog 本站旨在为大家提供IT技术相关的教程和资讯,以及常用开发工具免费下载!
  • 联系我:15709160159联系我
  • 微信公众号微信公众号
您现在的位置是: 首页  >  架构/框架  >  Spring
  • SpringBoot+MyBatis+AOP 实现多数据源动态自主切换

    SpringBoot+MyBatis+AOP 实现多数据源动态自主切换

    在实际开发中,我们一个项目可能会用到多个数据库,通常一个数据库对应一种数据,而且在大数据量的业务下通常都会有多个数据源的。最近恰好工作上遇到一个SpringBoot+Mybatis框架的多数据源配置切换的业务,所以就研究了一下关于Springboot+Mybatis多数据源切换。1.多数据源常见解决方案正常情况下,我们操作数据是通过配置一个DataSource数据源来连接数据库,然后绑定给SqlSessionFactory,然后通过Dao或Mapper指定SqlSessionFactory来操作数据库的。而操作多数据源则更要复杂一点,可以通过如下两种方式来实现:普通的多数据源多个DataSource数据源绑定多个SqlSessionFactory,每个数据源绑定一个SqlSessionFactory,然后通过Dao或Mapper指定SqlSessionFactory来操作数据库。操作不同的数据源是通过在业务层调用对应的实现了不同数据源的方法来同时操作不同的数据源的。动态切换的数据源方式一中,必须要使多个数据源之间完全的物理分离,如果存在一个用户表,几个数据库都有的情况,并且业务也类似,那写多套代码是冗余的,并且代码维护起来也更加困难,有没有更便捷的方式呢?其实可以通过配置多个DataSource数据源到一个DynamicDataSource动态数据源上,动态数据源绑定一个SqlSessionFactory,除了中间多出一个动态数据源外,其他部分都是相同的。Q:那么这种方式是怎么实现数据源的切换的呢?A:通过在业务类或方法上添加一个数据源标识(注解),使用切面来监听这个标志,进而切换数据源,通过一个注解就可以更加灵活切换数据源。2.实现动态数据源切换2.1禁用SpringBoot的自动配置数据源类在SpringBoot中,程序会自动读取src/main/resources/application.yml或application.properties配置文件中的spring.datasource.xxx的数据源配置信息,如果我们需要配置多数据源的话,要先把这个自动读取数据源配置信息的类禁掉。禁掉该类的方法是:在SpringBoot的启动类中,使用@SpringBootApplication注解时把类DataSourceAutoConfiguration.class排除。2.2重写数据源配置读取类禁掉自动读取数据源配置类之后,需要自己写读取不同数据源的配置信息代码了,要配置多少个数据源,就有多少个配置方法,并将数据源实例交给Spring容器管理,如下(这里以MySQL和TiDB为例,数据库连接池使用Hikari):2.3自定义DynamicDataSource实现数据源可切换有了多个数据源之后我们需要一个地方来管理系统的数据源,可以使用枚举,也可以使用常量类,如下定义了MYSQL和TiDB两种数据源枚举:SpringBoot中提供了一个类AbstractRoutingDataSource可以让用户实现数据源的动态切换,我们需要重写该类的determineCurrentLookupKey()方法,从数据源类型容器中获取当前线程的数据源类型。如下:其中DataSourceSwith是自定义的数据源切换类,它保存了当前线程下的应该使用的数据源名称,构建一个数据源类型容器,并提供了向其中设置、获取和清空数据源类型的方法,具体代码如下:2.4使用自定义DynamicDataSource重写SpringBoot的数据源配置在DataSourceConfig类中增加方法,从DynamicDataSource中获取当前线程的Datasoure,实现数据源的切换:根据动态数据源配置,创建sqlSessionFactory,具体代码如下:根据动态数据源配置,创建transactionManager,具体代码如下:根据动态数据源配置,创建mybatissessionConfiguration,具体代码如下:3.AOP+自定义注解实现数据源动态切换通过上面第2步我们配置了MySQL和TiDB两种可动态切换的数据源,我们只需要在业务代码中使用自定义的DataSourceSwitch.setDataSourceType()方法设置业务员方法应该使用的数据源即可实现数据源的动态切换,可是这种方式略显麻烦且不够优雅,在AOP加持下,我们可以实现通过自定义注解实现数据源动态切换。实现的基本原理也很简单:通过在业务类上标注自定义注解并指定数据源,然后AOP切面监听注解,如果被注解标注的类或方法被执行那么就按照注解中指定的数据源调用DataSourceSwitch的setDataSourceType方法实现数据源切换。3.1自定义数据@DataSource3.2在业务类上标注自定义数据源注解在使用MySQL数据源的业务类上标注注解@DataSource(value=DataSourceDialect.MYSQL_MASTER),由于注解默认值使用的就是MySQL数据源,所以可以缺省写为@DataSource在使用TiDB数据源的业务类上标注注解@DataSource(value=DataSourceDialect.TIDB_MASTER)3.3通过切面实现动态切换数据源4.验证结果访问依赖MySQL数据源的接口/v1/user接口正常返回&日志打印了切换过程:访问依赖TiDB数据源的接口/v1/order/list接口正常返回&日志打印了切换过程:

    LoveIT 2023-01-30
    Spring
  • Spring教程:事物详解(三)声明式事务源码详解

    Spring教程:事物详解(三)声明式事务源码详解

    引言上篇我们着重对Spring编程式事物进行了源码阅读以及原理分析,了解了Spring事物的运行原理,但这种管理事务的方式的代码侵入行非常高,现在开发基本不会使用这个,而且现在Java开发基本都会使用SpringBoot,配合SpringBoot的自动配置,声明式事物简直不要太好用!本篇就深入SpringBoot源码,看看@EnableTransactionManagement配合@Transactional两个简单的注解(写法简单,但内在其实不简单)是如何帮助我们管理事务的。一、AOP有关概念回顾声明式事务是依赖SpringAOP实现的,即面向切面编程。所谓AOP...一句话概括就是:把业务代码中重复代码做成一个切面,提取出来,并定义哪些方法需要执行这个切面。其它的自行百度吧...AOP核心概念如下:通知(Advice):定义了切面(各处业务代码中都需要的逻辑提炼成的一个切面)做什么what+when何时使用。例如:前置通知Before、后置通知After、返回通知After-returning、异常通知After-throwing、环绕通知Around.连接点(Jointpoint):程序执行过程中能够插入切面的点,一般有多个。比如调用方式时、抛出异常时。切点(Pointcut):切点定义了连接点,切点包含多个连接点,即where哪里使用通知.通常指定类+方法或者正则表达式来匹配类和方法名称。切面(Aspect):切面=通知+切点,即when+where+what何时何地做什么。引入(Introduction):允许我们向现有的类添加新方法或属性。织入(Weaving):织入是把切面应用到目标对象并创建新的代理对象的过程。二、声明式事物源码解读由于采用声明式@Transactional这种注解的方式,那么我们从SpringBoot启动时的自动配置载入开始看。在SpringBootautoconfigure包下的/META-INF/spring.factories中配置文件中查找到有关声明式事物的自动配置,如下图:发现,SpringBoot载入2个关于事务的自动配置类:org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,重点看一下TransactionAutoConfiguration这个自动配置类。2.1TransactionAutoConfigurationTransactionAutoConfiguration这个类主要看:两个类注解和两个内部类2.1.1两个类注解@ConditionalOnClass(PlatformTransactionManager.class)会在类路径下包含PlatformTransactionManager这个类时这个自动配置生效,这个类是Spring事务的核心包,肯定引入了。@AutoConfigureAfter({JtaAutoConfiguration.class,HibernateJpaAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class,Neo4jDataAutoConfiguration.class}),这个配置在括号中的4个配置类后才生效。2.1.2两个类内部类TransactionTemplateConfiguration事务模板配置类有两个注解,含义分别如下:@ConditionalOnSingleCandidate(PlatformTransactionManager.class)当能够唯一确定一个PlatformTransactionManagerBean实例时才生效。@ConditionalOnMissingBean如果没有定义TransactionTemplateBean生成一个。EnableTransactionManagementConfiguration开启事务管理器配置类在源码中我们还可以看到,EnableTransactionManagementConfiguration支持2种代理方式:JdkDynamicAutoProxyConfiguration和CglibAutoProxyConfigurationJdkDynamicAutoProxyConfiguration@EnableTransactionManagement(proxyTargetClass=false),表示是JDK动态代理,支持面向接口的代理。@ConditionalOnProperty(prefix="spring.aop",name="proxy-target-class",havingValue="false",matchIfMissing=false),即spring.aop.proxy-target-class=false时生效,且没有这个配置不生效。CglibAutoProxyConfiguration@EnableTransactionManagement(proxyTargetClass=true),表示使用Cglib代理,支持的是子类继承代理。@ConditionalOnProperty(prefix="spring.aop",name="proxy-target-class",havingValue="true",matchIfMissing=true),即spring.aop.proxy-target-class=true时生效,且没有这个配置默认生效。也就是说,如果开始事物后,没有做任何配置,那么SpringBoot会默认使用Cglib代理,那么也就是说,@Transactional注解默认情况下支持直接加在类上。看到这里,我们需要对@EnableTransactionManagement注解做一个更深的认识,下图所示是其源码。proxyTargetClass:值为false表示是JDK动态代理支持接口代理。true表示是Cglib代理支持子类继承代理。mode:事务通知模式(切面织入方式),默认代理模式(同一个类中方法互相调用拦截器不会生效),可以选择增强型AspectJorder:连接点上有多个通知时用于优先级排序,默认最低。值越大优先级越低。属性先说这么多,这个注解重点还是看它头上的@Import(TransactionManagementConfigurationSelector.class)这个注解。@Import注解的功能不用多说,它就是用来导入配置的,重点关注配置类TransactionManagementConfigurationSelector,类图如下:如上图所示,TransactionManagementConfigurationSelector继承自AdviceModeImportSelector实现了ImportSelector接口。如上图,最终会执行selectImports方法导入需要加载的类,我们只看PROXY模式下,载入了AutoProxyRegistrar、ProxyTransactionManagementConfiguration2个类。AutoProxyRegistrar:给容器中注册一个InfrastructureAdvisorAutoProxyCreator组件;利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;ProxyTransactionManagementConfiguration:一个配置类,定义了事务增强器。三、声明式事物工作时序图最后,整理了一下声明式事物工作时序图,建议收藏!

    LoveIT 2021-10-26
    Spring
  • Spring教程:事物详解(二)编程式事务源码详解

    Spring教程:事物详解(二)编程式事务源码详解

    引言Spring提供了两种事物管理实现方式:编程式事务管理:编程式事务管理使用TransactionTemplate可实现更细粒度的事务控制。声明式事务管理:基于SpringAOP实现。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务管理没有入侵代码,通过**@Transactional**就可以进行事务操作,更快捷而且简单(尤其是配合SpringBoot自动配置,可以说是精简至极!)且大部分业务都可以满足,推荐使用。其实不管是编程式事务还是声明式事务,最终调用的底层核心代码是一致的。本章分上下两篇,分别从编程式、声明式入手,再进入核心源码贯穿式讲解。本片重点分析编程式事物的实现方式。Let'sgo~~一、编程式事务TransactionTemplate全路径名是:org.springframework.transaction.support.TransactionTemplate。看包名也知道了,这是Spring对事务的模板类。在Spring中模版模式使用非常广泛的~点进TransactionTemplate源码它是实现了TransactionOperations、InitializingBean这2个接口(熟悉Spring源码的小伙伴知道这个InitializingBean又是老套路),我们来看下接口源码如下:TransactionOperations接口InitializingBeanTransactionOperations这个接口用来执行事务的回调方法,InitializingBean这个是典型的SpringBean初始化流程中的预留接口,专用用来在bean属性加载完毕时执行的方法(不熟悉的小伙伴去看看SpringBean生命周期的流程)。看到这里,有的小伙伴自然而然就有疑问了:TransactionTemplate的2个接口的方法做了什么?接着往下说!如上图所示,实际上afterPropertiesSet方法只是校验了事务管理器不为空,execute()才是核心方法,execute主要步骤:总结一下,核心步骤如下:getTransaction()获取事务,源码见见下篇3.3.1节doInTransaction()执行业务逻辑,这里就是用户自定义的业务代码。如果是没有返回值的,就是doInTransactionWithoutResult()。commit()事务提交,根据事物执行状态,调用AbstractPlatformTransactionManager类的commit()提交事物、rollbackOnException()异常回滚或者rollback()事务提交回滚,源码见下篇3.3.3节

    LoveIT 2021-10-26
    Spring
  • Spring教程:事物详解(一)初探事物

    Spring教程:事物详解(一)初探事物

    引言很多coder在不理解事务的原理甚至连基本概念都不清楚的情况下,就去使用数据库事务,是极容易出错,写出一些自己不能掌控的代码。网上很多文章要不就是概念,或者一点源码,或者一点测试验证,都不足以全面了解事务,所以本文出现了,本系列Spring事务详解包含四部分:第一章讲概念,对事务的整体有一个了解。第二章从源码来看底层实现机制。第三章实例测试验证。第四章总结提高。一、背景1.1拜神Spring事务领头人叫JuergenHoeller,先混个脸熟哈,他写了几乎全部的Spring事务代码。读源码先拜神,掌握他的源码的风格,读起来会通畅很多。最后一节咱们总结下这个大神的代码风格。1.2事务的定义事务(Transaction)是数据库区别于文件系统的重要特性之一。目前国际认可的数据库设计原则是ACID特性,用以保证数据库事务的正确执行。Mysql的innodb引擎中的事务就完全符合ACID特性。Spring对于事务的支持,分层概览图如下:二、事务的ACID特性原子性(Atomicity):一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。主要涉及InnoDB事务。相关特性:事务的提交,回滚,信息表。一致性(consistency):数据库总是从一个一致性的状态转换到另一个一致性的状态。在事务开始前后,数据库的完整性约束没有被破坏。例如违反了唯一性,必须撤销事务,返回初始状态。隔离性(isolation):每个读写事务的对象对其他事务的操作对象能相互分离,即:事务提交前对其他事务是不可见的,通常内部加锁实现。主要涉及事务,尤其是事务隔离级别,相关特性:隔离级别、innodb锁的底层实现细节。持久性(durability):一旦事务提交,则其所做的修改会永久保存到数据库。涉及到MySQL软件特性与特定硬件配置的相互影响,相关特性:4个配置项:双写缓冲开关、事务提交刷新log的级别、binlog同步频率、表文件;写缓存、操作系统对于fsync()的支持、备份策略等。三、事务的属性定义要保证事务的ACID特性,Spring给事务定义了6个属性,对应于声明式事务注解@Transational(org.springframework.transaction.annotation.Transactional)中6个成员属性。事务名称:用户可手动指定事务的名称,当多个事务的时候,可区分使用哪个事务。对应注解中的属性value、transactionManager隔离级别:为了解决数据库并发事物带来的问题,采用分级加锁处理策略。对应注解中的属性isolation超时时间:定义一个事务执行过程多久算超时,以便超时后回滚。可以防止长期运行的事务占用资源.对应注解中的属性timeout是否只读:表示这个事务只读取数据但不更新数据,这样可以帮助数据库引擎优化事务.对应注解中的属性readOnly传播机制:对事务的传播特性进行定义,共有7种类型。对应注解中的属性propagation回滚机制:定义遇到异常时回滚策略。对应注解中的属性rollbackFor、noRollbackFor、rollbackForClassName、noRollbackForClassName其中==隔离级别==和==传播机制==比较复杂,我们来细细的品一品。3.1隔离级别3.1.1现象事物的隔离级别(isolationlevel)定义了一个事务可能受其他并发事务影响的程度。在并发事务中,经常会引起以下问题:脏读(Dirtyreads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。不可重复读(Nonrepeatableread)——不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。幻读(Phantomread)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。3.1.2MySQL底层支持(InnoDB事物模型)当多个事务同时执行sql操作时,隔离级别用于平衡InnoDB的性能、可靠性、并发性、结果的可再现性。可以通过set_transaction进行单个用户连接的隔离级别设置。通过showvariableslike‘tx_isolation’查看当前使用的隔离级别。加上server启动参数--transaction-isolation或者在配置文件中设定serverlevel的隔离级别。InnoDB使用不同的锁策略来实现对不同事务隔离级别的支持。具体如下:隔离级别含义ISOLATION_DEFAULT使用后端数据库默认的隔离级别(Spring独有的)ISOLATION_READ_UNCOMMITTED最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读ISOLATION_READ_COMMITTED允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生ISOLATION_REPEATABLE_READ对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生ISOLATION_SERIALIZABLE最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的3.2传播行为**事务的传播行为(propagationbehavior)**是指一个事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。Spring在org.springframework.transaction包下的TransactionDefinition接口定义了七种传播行为:传播行为含义PROPAGATION_REQUIRED表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务PROPAGATION_SUPPORTS表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行PROPAGATION_MANDATORY表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常PROPAGATION_REQUIRED_NEW表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManagerPROPAGATION_NOT_SUPPORTED表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManagerPROPAGATION_NEVER表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常PROPAGATION_NESTED表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务参考资料spring事务详解(一)初探事务.https://www.likecs.com/default/index/url?u=aHR0cHM6Ly9pLmNuYmxvZ3MuY29tL0VkaXRQb3N0cy5hc3B4P3Bvc3RpZD05NTQ5NTM1Mysql技术内幕-InnoDB存储引擎InnoDBLockingandTransactionModel.MySQL官网

    LoveIT 2021-10-26
    Spring
  • SpringBoot项目更换启动时控制台打印的banner

    SpringBoot项目更换启动时控制台打印的banner

    更换Banner1、在resources目录下新建banner.txt文件2、制作Banner之后制作Banner,这里我推荐几个网站:-http://patorjk.com/software/taag-http://www.network-science.de/ascii/-http://www.degraeve.com/img2txt.php把banner字符输入之后提交就可以得到想要的Banner了,下面是我的网站的启动效果:感兴趣的小伙伴赶快去尝试一下吧!

    LoveIT 2020-06-11
    Spring Boot
  • SpringBoot网站基于OAuth2添加第三方登录之GitHub登录

    SpringBoot网站基于OAuth2添加第三方登录之GitHub登录

    一、OAuth2简介OAuth是目前最流行的授权机制,用来授权第三方应用,获取用户数据。OAuth在全世界已经得到广泛应用,目前的版本是2.0版。简单说,OAuth就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。因此令牌(token)与密码(password)的作用是一样的,都可以进入系统,但是有三点差异:令牌是短期的,到期会自动失效,用户自己无法修改。密码一般长期有效,用户不修改,就不会发生变化。令牌可以被数据所有者撤销,会立即失效。令牌有权限范围(scope)因为令牌有着和密码一样的功能,所以对于令牌也必须严格保密,泄漏令牌和泄漏密码的后果是一样的。这也就是为啥令牌的有效期很短的原因了。二、GitHub第三方登录的原理第三方登录实际就是OAuth授权认证。用户想要登录A网站,A网站让用户提供第三方网站的数据,证明自己的身份。获取第三方网站的身份数据,就需要OAuth授权。以使用GitHub为第三方登录为例:用户在网站点击使用GitHub登录,A网站跳转到GitHub(会带上回调URI和ClientID)GitHub要求用户登录,然后询问"A网站要求获得xx权限,你是否同意?"(对于同一个网站,同意一次之后,下次再登录就不在需要用户授权)用户同意,GitHub就会重定向回A网站,同时发回一个授权码。A网站使用授权码,向GitHub请求令牌。GitHub返回令牌.A网站使用令牌,向GitHub请求用户数据。使用GitHub做第三方登录认证的具体的流程可如下图所示:好了,原理大致了解到这里,接下来动手搭建一下GitHub第三方登录。三、GitHub第三方登录搭建示例1、创建应用①登录github后台(地址:https://github.com/settings/developers),创建应用你需要添加GitHub登录的应用。或者在GitHub的settings中点击Deveplopersettings②之后直接点击NewGitHubApp③之后填写你的App有关的信息即可在注册成功之后,GitHub会返回客户端ID(clientID)和客户端密钥(clientsecret),这就是应用的身份识别码,在授权的时候会用到。一个填写示例:2、几个重要的URL登录页面授权URL:https://github.com/login/oauth/authorize?client_id=%s&redirect_uri=%s&state=%s获得Token的URL:https://github.com/login/oauth/access_token?client_id=%s&client_secret=%s&code=%s&redirect_uri=%s&state=%s获得用户信息的URL:https://api.github.com/user?access_token=%s3、设计数据库设计一个数据表用于存放用户的认证记录,用于认证之后就将他的认证信息存放到这个表中,并和主用户表(User)绑定。之后Mapper(DAO)、Service层自己按照自己业务逻辑自行实现,准备好有关接口等待Controller的调用。4、放置GitHub登录按钮点击GitHub登录之后的授权页面:5、后台代码具体实现①首先在SpringBoot配置文件配置如下信息:②之后写一个配置类用于获取这些文件中的这些信息③为了提高系统的扩展性,比如以后还可以做个QQ登录、微信登录.....,因此这里提供一个接口用于认证服务GitHub认证授权实现类:④GitHub认证控制器(Controller)GitHub返回的用户信息中的id在GitHub上是一个唯一的Id,这个可以作为用户是否在使用GitHub在系统登录过的依据。好了,这里我们的Github授权登录功能就算完成了。哪里有不清楚的地方可以在评论区留言。

    LoveIT 2020-05-31
    Spring Boot
  • Spring从入门到精通—SSM整合实例

    Spring从入门到精通—SSM整合实例

    0、什么是SSM?在软件开发领域里SSM是对Spring、SpringMVC、MyBatis这三大框架的简称。0.1、SpringSpring是一个开源框架,Spring是于2003年兴起的一个轻量级的Java开发框架,由RodJohnson在其著作ExpertOne-On-OneJ2EEDevelopmentandDesign中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。0.2、SpringMVCSpringMVC属于SpringFrameWork的后续产品,已经融合在SpringWebFlow里面。SpringMVC分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。0.3、MyBatisMyBatis本是Apache的一个开源项目iBatis,2010年这个项目由Apachesoftwarefoundation迁移到了googlecode,并且改名为MyBatis。MyBatis是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQLMaps和DataAccessObjects(DAO)MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(PlainOldJavaObjects,普通的Java对象)映射成数据库中的记录。接下来我们来一步步把他们整合在一起。1、创建基本的MavenWeb项目        在IDEA中创建一个基本的Maven项目。具体过程不是这里的重点,如有有不清楚,请自行百度或Google~。创建好项目后,在pom.xml文件中配置依赖(导包),在pom.xml文件中添加依赖配置如下:注意!配置的时候要特别注意mybatis-spring这个包的版本和你使用的MyBatis以及Spring版本是否兼容,特别适当发生java.lang.AbstractMethodError:org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout()错误的时候,还就更要怀疑是这个问题了:适配的环境:mybatis-spring对JDK、mybatis、spring都有要求2、配置环境        配置文件的编写是SSM整合的关键,需要配置的东西主要有web.xml、Sprng配置文件applicationContext.xml、SpringMVC配置文件applicationContext-mvc.xml、MyBatis全局配置文件MyBatis-config.xml以及后面的Mapper映射文件的编写。2.1配置web.xml文件web.xml文件的基本配置如下:2.2配置MyBatis-config.xml全局配置文件        在MyBatis的全局配置文件中配置一些基本对settings,环境就不要在这里配置了,交给Spring管理就好了(本身MyBatis这个配置文件都是可有可无的,但是用它来写一个settings配置可以使结构清晰,方便修改)。2.3配置applicationContext-mvc.xml文件2.4配置applicationContext.xml文件2.5jdbc.properties数据库资源文件对于SSM的配置基本上完成了,下面将使用这个搭建好的框架对对book表进行简单的CRUD操作。3、一个简单CRUD3.1基本准备创建数据库和表:新建tx数据库,并在tx数据库中新建book表。具体的数据库脚本如下:3.2编写SQL映射文件以及对应的Mapper接口在src/main/resources目录下新建mapper目录,在mapper目录下新建BookMapper.xmlSQL映射文件。并在源码包的mappr包下新建对应的BookMapper.java接口。(1)SQL映射文件BookMapper.xml(2)Mapper接口3.3开发业务层(Service层)为了遵循SOA的开发理念和规范,我们这里还是写一个接口,并实现接口在com.xust.iot.service包下新建impl包,然后新建BookService接口的实现类BookServiceImpl。3.4开发控制层(Controller层)在com.xust.iot.controller包下新建BookController类3.5开发视图层(View层)(1)index.html(2)添加图书的页面:add.jsp(3)展示所有图书信息的页面:bookInfo.jsp(4)修改图书信息的页面:edit.jsp最终的测试结果总结       经过几个小时的斗争,SSM三大框架的简单整合算是完成了,期间也遇到了这样那样的问题,但都一一解决了,从测试结果来看还是比较成功的。然而代码没有写几行,配置文件写了一大堆,我只想说SpringBoot真香!!!

    LoveIT 2020-03-17
    Spring
  • SpringBoot—WebMvcConfigurer详解

    SpringBoot—WebMvcConfigurer详解

    1.简介WebMvcConfigurer配置类其实是Spring内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制,可以自定义一些Handler,Interceptor,ViewResolver,MessageConverter。基于java-based方式的springmvc配置,需要创建一个配置类并实现WebMvcConfigurer接口;在SpringBoot1.5版本都是靠重写WebMvcConfigurerAdapter的方法来添加自定义拦截器,消息转换器等。SpringBoot2.0后,该类被标记为@Deprecated(弃用),官方推荐直接实现WebMvcConfigurer或者直接继承WebMvcConfigurationSupport,方式一实现WebMvcConfigurer接口(推荐),方式二继承WebMvcConfigurationSupport类2.WebMvcConfigurer接口常用方法:2.1addInterceptors:拦截器addInterceptor:需要一个实现HandlerInterceptor接口的拦截器实例addPathPatterns:用于设置拦截器的过滤路径规则;addPathPatterns("/**")对所有请求都拦截excludePathPatterns:用于设置不需要拦截的过滤规则拦截器主要用途:进行用户登录状态的拦截,日志的拦截等。下面是一个配置示例:2.2addViewControllers:页面跳转以前使用Servlet的时候,如果需要访问一个页面,必须要写Servlet类,然后再写一个方法跳转到页面,感觉好麻烦,后来有了SpringMVC我们就可以在xml配置文件中配置视图的直接映射view-controller命名空间:来避免这些方法。再后来有了SpringBoot,我们可以可以重写WebMvcConfigurer中的addViewControllers方法即可达到效果了:值的指出的是,在这里重写addViewControllers方法,并不会覆盖WebMvcAutoConfiguration(Springboot自动配置)中的addViewControllers(在此方法中,SpringBoot将“/”映射至index.html),这也就意味着自己的配置和SpringBoot的自动配置同时有效,这也是我们推荐添加自己的MVC配置的方式。2.3addResourceHandlers:静态资源比如,我们想自定义静态资源映射目录的话,只需重写addResourceHandlers方法即可。注:如果继承WebMvcConfigurationSupport类实现配置时必须要重写该方法,具体见其它文章addResoureHandler:指的是对外暴露的访问路径addResourceLocations:指的是内部文件放置的目录2.4configureDefaultServletHandling:默认静态资源处理器此时会注册一个默认的Handler:DefaultServletHttpRequestHandler,这个Handler也是用来处理静态文件的,它会尝试映射/。当DispatcherServelt映射/时(/和/是有区别的),并且没有找到合适的Handler来处理请求时,就会交给DefaultServletHttpRequestHandler来处理。注意:这里的静态资源是放置在web根目录下,而非WEB-INF下。可能这里的描述有点不好懂(我自己也这么觉得),所以简单举个例子,例如:在webroot目录下有一个图片:1.png我们知道Servelt规范中web根目录(webroot)下的文件可以直接访问的,但是由于DispatcherServlet配置了映射路径是:/,它几乎把所有的请求都拦截了,从而导致1.png访问不到,这时注册一个DefaultServletHttpRequestHandler就可以解决这个问题。其实可以理解为DispatcherServlet破坏了Servlet的一个特性(根目录下的文件可以直接访问),DefaultServletHttpRequestHandler是帮助回归这个特性的。2.5configureViewResolvers:视图解析器这个方法是用来配置视图解析器的,该方法的参数ViewResolverRegistry是一个注册器,用来注册你想自定义的视图解析器等。2.6addCorsMappings:跨域2.7configureMessageConverters:信息转换器参考【1】zhangpower1993.SpringBoot---WebMvcConfigurer详解.CSDN【2】小仙.SpringBoot——》WebMvcConfigurerAdapter详解.CSDN

    LoveIT 2019-11-21
    Spring Boot
  • SpringBoot从入门到精通—Spring Boot 错误处理机制

    SpringBoot从入门到精通—Spring Boot 错误处理机制

    1、SpringBoot默认错误处理机制(现象)        当我们使用SpringBoot发生错误的时候,如果我们没有配置错误的处理规则,那么SpringBoot就会启用内部的默认错误处理办法。比如当发生404错误的时候,网页端的效果如下:而在别的客户端访问的时候如果出现了404错误,默认会给客户端发送一串错误消息的JSON数据客户端的测试使用到了一个工具:Postman,感兴趣的小伙伴可以去Postman官网下载后来测试。2、SpringBoot默认错误处理机制(原理)        看到这些现象我们不禁会有疑问,SpringBoot的底层是如何生成不同错误的默认错误页面的?还有他是如何区分浏览器和其他客户端的?带着疑问我们继续往下看。        我们参照源码来分析一下(SpringBoot2.1.7版本),具体在ErrorMvcAutoConfiguration这个错误处理自动配置类,下面是在这个类中注册的几个重要的组件的源码:2.1ErrorMvcAutoConfiguration源码片段可以看到,ErrorMvcAutoConfiguration这个错误处理类中配置了几个重要的组件:*DefaultErrorAttributs:见名知意,这是SpringBoot定义的默认错误属性,他就是和错误信息的填充有关。*BasicErrorController:他是SpringBoot中默认处理/error请求的Controller*ErrorPageCustomizer:系统出现错误以后来到error请求进行处理*DefaultErrorViewResolver:默认的出现错误后的视图解析器继续跟踪源码(1)DefaultErrorAttributs源码片段(2)BasicErrorController源码片段首选通过判断媒体的类型来选择不同的错误处理方法,核心就是下面两个方法在BasicErrorController类的源码我们看到它调用了父类AbstractErrorControlle的方法resolveErrorView来处理ModelAndView,具体的实现细节如下:AbstractErrorController源码片段(3)ErrorPageCustomizer源码片段(4)DefaultErrorViewResolver源码片段        大致分析源码后可以总结SpringBoot对错误的处理流程如下:如果系统出现4xx或者5xx之类的错误,ErrorPageCustomizer就会生效(定制错误的响应规则),就会发出/error请求,然后就会被BasicErrorController处理并返回ModelAndView(网页)或者JSON(客户端)。3、使用SpringBoot默认错误处理机制来处理我们程序中的异常        通过分析源码我们可以发现,如果要使用SpringBoot默认的错误处理机制,我们可以把我们定制的错误页面放在/templates/error目录下的,交给模板引擎来处理;或者不使用模板引擎那就放在static/error目录下。并且给这些错误页面命名为错误码.html或4xx.html、5xx.html。SpringBoot就可以自动帮我们映射到错误页面。例如,处理404错误:在/templates/error目录下放404.html        访问浏览器,在地址栏中随便输入一个地址让他发生404错误,结果来到了我们定制的404错误页面,而不是SpringBoot默认的那个难看的白板页面。4xx.html测试结果:4、定制自己的错误信息默认情况下,SpringBoot的错误页面中可以可得一下错误信息:timestamp:时间戳status:状态码error:错误提示exception:异常对象message:异常消息errors:JSR303数据校验的错误都在这里4.1第一种方式:使用SpringMVC的异常处理器这样无论是浏览器还是别的客户端,只要出错了就全部返回的JSON数据。4.2第二种方式:转发到/error请求进行自适应效果处理4.3第三种方式:编写一个MyErrorAttributes继承DefaultErrorAttributes并重写其getErrorAttributes方法        前两种虽然都可以解决错误,但是当我们自己定义一个错误属性(比如上面的code属性)就没办法带到页面,因此我们设置的信息也就无法被带到页面显示。我们可以编写一个MyErrorAttributes继承自DefaultErrorAttributes重写其getErrorAttributes方法将我们的错误数据添加进去。最终的效果:响应是自适应的,以后可以通过定制ErrorAttributes改变需要返回的内容。

    LoveIT 2019-10-13
    Spring Boot
  • SpringBoot从入门到精通—Spring Boot 对静态文件的默认映射规则

    SpringBoot从入门到精通—Spring Boot 对静态文件的默认映射规则

    1、Webjars(官网:http://www.webjars.org/)webjars:以jar包的方式引入静态资源;SpringBoot中所有/webjars/**,都去classpath:/META-INF/resources/webjars/找资源。推荐使用Webjars的三大理由:将静态资源版本化,更利于升级和维护。剥离静态资源,提高编译速度和打包效率。实现资源共享,有利于统一前端开发。1.1使用Webjars引入公共的静态资源使用Webjars在POM文件中很方便的引入静态资源文件,比如JQuery、Vue.js.....例如引入jquery和BootStrap,这样引入后,我们可以像管理Java依赖一样管理静态文件依赖。引入之后我们可以尝试访问一下BootStrap里面的东西,在地址栏输入localhost/webjars/bootstrap/4.0.0/webjars-requirejs.js2、引入自己的静态资源文件使用Webjars是好,但是没办法引入我们自己编写的静态资源文件。别急!SpringBoot开发者早已想到这个问题了,SpringBoot规定可以放在以下几个地方放置静态文件:3、给网页标签栏设置小图标SpringBoot支持给网页标签栏设置图标的功能,方法十分简单只需要将图标命名为favicon.ico,然后放在静态资源文件夹根目录下,SpringBoot在启动的时候就会扫描到并设置到网页中。在classpath:/public/放一个我自己的图标启动来看看效果:很nice!我们的小图标被用上了。4、使用spring.resources.static-locations改变静态资源文件夹位置在SpringBoot的主配置文件中,我们可以使用spring.resources.static-locations来指定静态资源文件的位置,可以指定多个,多个路径之间用","(逗号)隔开。需要注意的是,我们这么指定后,那些默认的资源文件夹就会失效。在resources下新建webapps文件夹,把静态资源放在里面。启动来看看效果:

    LoveIT 2019-10-12
    Spring Boot
  • SpringBoot从入门到精通—SpringBoot异步任务、定时服务和邮件服务

    SpringBoot从入门到精通—SpringBoot异步任务、定时服务和邮件服务

    1、SpringBoot—异步任务    异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步程序执行完即可执行。    实现异步处理任务的方式有很多,我们可以自己通过多线程来实现或者也可以使用SpringBoot提供的@EableAysnc和@Aysnc这两个注解来实现。1.1通过多线程来实现异步处理任务直接在需要异步任务处理的方法中开启新的线程来处理任务。执行结果如下:1.2使用SpringBoot提供的注解处理异步任务首先在需要异步任务处理的方法上加上@Async注解告诉SpringBoot这个方法需要异步处理然后在主配置类使用@EnableAsync注解开启异步注解功能执行结果如下,SpringBoot也是开启了一个新的线程task-1来处理这个任务的:2、SpringBoot—定时任务定时任务就是提前设置好时间点,然后每到这个时间点就会执行的任务。SpringBoot中可以通过@Scheduled和@EableScheduled这两个注解来实现定时任务。同样在需要定时任务对方法上标注@Scheduled注解,然后在主配置类上标注@EableScheduled注解开启定时注解功能执行结果:从上面这个例子中可以看到,对于定时任务使用主要就是对cron表达式的编写,cron允许的值可以有以下几种:字段允许值允许的特殊字符秒0-59,-*/分0-59,-*/小时0-23,-*/日1-31,-*/?LWC月1-12,-*/星期0-7或SUN-STA,-*/?LWC#解释:,:表示枚举,可以用它在一个一段上枚举多个值—:表示一个区间*:表示任意/:步长?:日/星期冲突匹配L:最后W:工作日C:和Calendar联系后计算后的值#:星期,例如4#2表示第二个星期四下面是几个用法示例:3、SpringBoot—邮件任务    SpringEmail抽象的核心是MailSender接口,MailSender的实现能够把Email发送给邮件服务器,由邮件服务器实现邮件发送的功能。    Spring自带了一个MailSender的实现JavaMailSenderImpl,它会使用JavaMailAPI来发送Email。Spring或SpringBoot应用在发送Email之前,我们必须要JavaMailSenderImpl装配为Spring应用上下文的一个bean。3.1首先引入邮件服务的starter3.2邮件配置3.3简单邮件服务—SimpleMessage使用简单邮件服务只能发送文本消息执行的结果,成功收到了邮件:3.4复杂邮件服务—MimeMessage使用复杂邮件服务可以发送文本消息、HTML语句、甚至支持上传附件执行结果:在GMail收到了邮件,并且设置HTML样式起作用了,附件也上传成功了。

    LoveIT 2019-10-01
    Spring Boot
  • SpringBoot从入门到精通—Spring Boot + Eureka 实现微服务负载均衡

    SpringBoot从入门到精通—Spring Boot + Eureka 实现微服务负载均衡

    1、什么是Eureka?        Eureka这个单词原本的意思就是“我发现了,我找到了”,他在Spring中的功能也和他的本意是一样的。Eureka是netflix的一个子模块,也是核心模块之一,Eureka是一个基于RESTful的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现和注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务,而不需要修改服务调用的配置文件了,功能类似于dubbo的注册中心,比如zookeeper。        SpringCloud封装了Netflix公司开发的Eureka模块来实现服务注册时和发现。        Eureka采用了C/S设计架构。EurekaServer作为服务注册功能的服务器,它是服务注册时中心。而系统中的其他微服务,使用eureka的客户端连接到eurekaserver并维持心跳连接。这样系统的维护人员就可以通过eurekaserver来监控系统中各个微服务是否正常运行。SpringCloud的一些其他模块就可以通过eurekaserver来发现系统中的其他微服务,并执行相关的逻辑。        Eureka包含两个组件:EurekaServer和EurekaClient。        EurekaServer提供服务注册服务。各个节点启动后,会在EurekaServer中进行注册,这样Eurekaserver中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。        Eurekaclient是一个Java客户端,用于简化eurekaserver的交互,客户端同时也具备一个内置的,使用轮询负载算法的负载均衡器。在应用启动后,将会向EurekaServer发送心跳。如果EurekaServer在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表把这个服务节点移除。Eureka的三大角色:1.Eurekaserver提供服务注册和发现2.ServiceProvider服务提供方将自身服务注册到Eureka,从而使服务消费方能够找到。3.ServiceConsumer服务消费方从Eureka获取注册服务列表,从而能够消费服务。总结起来就是说1.Eureka是Netflix开源的一个RESTful服务,主要用于服务的注册和发现。2.Eureka由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注册服务器。3.Eureka客户端是一个Java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。4.Netflix在其生产环境中使用的是另外的客户端,它提供基于流量、资源利用率以及出错状态的加权负载均衡。2、搭建一个基于SpringBoot+Eureka的微服务工程工程的搭建我使用IDEA,首先新建一个空工程【Emptyproject】,选择空工程点击【next】,之后我们需要在这个工程中建立三个子模块,分别是euraka-server注册中心,poervider服务提供者,customer消费者。新建一个空工程在新建项目的时候我们可以使用【SpringInitializr】,在新建eurake-server模块的时候选上EurekaServer,新建provider和customer模块的时候可以选上Web的satrter和EurakeDiscoveryClient的satrter建好后的项目结构:3、EurekaServer—注册中心的配置在EurekaServer的启动类上使用@EnableEurekaServer开启Eureka服务配置好后启动enureka-server,它将会在配置的端口8761启动,输入http://localhost:8761就可一个看到enureka-server的管理界面:4、ServiceProvider—服务提供方的配置在服务提供方的配置文件中配置如下信息:实现一个服务,TicketServiceEureka的底层还是基于HTTP协议的,在消费者端要调用服务提供方的服务时,实际是通过HTTP请求的方式来调用的,因此需要在服务提供方给对应的service提供对应的controller。TicketController如下:最后在服务提供方的启动类上使用@EnableEurekaClient来告诉Spring这是Eureka的Cilent端,这个服务要注册到注册中心上去。(也可以使用@EnableDiscoveryClient注解,这两个注解的作用是相同的,但是还是有差别的,具体的可以参考@EnableDiscoveryClient与@EnableEurekaClient区别)。配置完成后启动ServerProvider(注意在启动Client端的服务时EurekaServer要保持运行),启动后可以正常访问http://localhost:8080/ticket,并且在注册中心可以看到8080端口的PROVIDER实例已经注册了就算是成功了。我们可以开启多个服务提供方,方法是把当前的provider使用Maven命令(mvninstall)打包成可执行jar包,然后在把server.port改成另一个端口再使用Maven命令打包后运行...下面是我启动了两个provider,分别在8080和8081端口5、ServiceCustomer—服务消费方的配置在服务消费方的配置文件中配置如下内容:在服务消费方的启动类上使用@EnableDiscoveryClient注解告诉SpringBoot把这个服务注册到注册中心。并且注册RestTemplate到IoC容器中,可以使用他来远程调用服务提供方的服务。编写一个controller使用RestTemplate来调用服务提供方的注册在服务中心的服务。最后启动服务消费方看看效果吧!首先我们可以访问http://localhost:8761/,可以在注册中心看到消费方也在注册中心注册了:我们接着访问http://localhost:8020/buy?name=李四&num=6就可以看到下面的页面:微服务负载均衡的体现把另一个打包的可执行jar包在命令行使用java-jar命令运行,注意不要让端口冲突。让两个服务提供方同时运行,然后我们访问http://localhost:8020/buy?name=李四&num=6,不断改变num的值查看控制台的打印发现这两个端口的服务是轮流工作的,从而达到了一个负载均衡的作用。

    LoveIT 2019-09-30
    Spring Boot
  • SpringBoot从入门到精通—自定义starter

    SpringBoot从入门到精通—自定义starter

    SpringBoot中提供了各种starter,starter可以理解为一个可拔插式的插件,当我们要使用的时候只用导入需要的starter即可。例如:你想使用jdbc插件,那么可以使用spring-boot-starter-jdbc;如果想使用mongodb,可以使用spring-boot-starter-data-mongodb。但是当我们需要的场景没有的时候我们可以来定制starter。首先在IDEA中创建一个maven工程,在其中创建两个Model,一个是hello-spring-boot-starter,另一个是hello-spring-boot-starter-configurer,目结构如下:要特别注意artifactId的命名规则:Spring官方starter通常命名为spring-boot-starter-{name},如spring-boot-starter-webSpring官方建议非官方Starter命名应遵循{name}-spring-boot-starter的格式,如mybatis-spring-boot-starter。一般我们不会直接在starter中写配置,starter一般只一个空项目,然后主要的配置写在这个starter对应的autoconfigurer中,让starer依赖configurer就可以了。1、在starter中引入对应的configurer依赖starter一般是一个空模块,真正的实现放在configurer中,让starter依赖configurer,以后需要使用这个模块的时候只用引入starter就可以引入它所依赖的configurer。2、在hello-spring-boot-starter-configurer模块中写我们需要的配置2.1XxxPrperoties2.2核心业务类2.3自动配置类XxxAutoConfigurer2.4spring.factories然后需要在hello-spring-boot-starter-configurer的src/main/resources文件夹下新建META-INF文件夹然后新建spring.factories文件,配置这个类让他可以自动启动。2.5打包mvncleaninstall使用Maven命令mvncleaninstall或直接使用IDEA提供的Maven插件执行install命令把我们的这个starter安装到本地Maven仓库。注意:如果提示没有找到pom文件的错误,那就使用命令行找到对应的项目执行Maven命令测试一下之后我们再新建一个普通的SpringBoot项目,引入我们自定义的starter引入后的效果:写一个controller来测试一下我们的starter是否有效可以在主配置文件中配置UserProperties中的属性(不配置将会使用默认值)启动运行看看效果:

    LoveIT 2019-09-29
    Spring Boot
  • SpringBoot从入门到经通过—Spring —Cache

    SpringBoot从入门到经通过—Spring —Cache

    1、JSR-107规范1.1JSP-107是什么?        要回答这个问题,首先要知道JSR是什么,JSR是JavaSpecificationRequests的缩写,Java规范请求,故名思议就是Java规范,大家一同遵守这个规范的话,会让大家‘沟通’起来更加轻松。规范是很重要的,举个例子大家都知道红灯停,路灯行吧,如果每个城市的信号灯代表不一样,那就麻烦了,B城市红灯行,绿灯停,C城市甚至出现紫灯行,闪灯行,想想都知道,如果我们保证不出问题,必须知道每个城市的信号等代表的意义。我们一直使用的JDBC就一个访问数据库的一个规范的例子。而JSR-107呢就是关于如何使用缓存的规范。1.2JSR-107核心APIJavaCaching定义了5个核心接口,分别是CachingProvider,CacheManager,Cache,Entry和Expiry。CachingProvider用于定义创建、配置、获取、管理和控制Cachemanager。CacheManager用于定义了建立,配置,得到,管理和控制有着唯一名字的Cache,一个CacheManager被包含在单一的CachingProvider。CacheCache是一个Map类型的数据结构,用来存储基于键的数据,很多方面都像java.util.Map数据类型。一个Cache存在在单一的CacheManager。EntryEntry是一个存在于Cache的key-value键值对Expiry每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy来设置。这些接口之间的关系可以用下图表示:2、Spring缓存抽象Spring3.1从开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术,并使用JCache(JSR-107)注解简化我们的开发。Cache接口为缓存的组件规范定义,包含缓存的各种操作集合Cache接口下Spring提供了各种xxxCache的实现,如RedisCache、EncheCache、ConcurrentMapCache......每次调用需要缓存功能的方法是,Spring会检查指定的参数的是定目标方法时候已经被调用过,如果有就直接从缓存中获取方法调用后对结果,如果没有就调用方法去数据库查询并缓存结果后返回给用户,下次回直接从缓存中获取。重要的缓存注解注解功能Cache缓存接口,定义缓存操作。CacheManager缓存管理器。管理和中缓存组件@Cacheable主要用于方法,能够根据方法的请求参数对其进行缓存@CachePut方法被调用,并且在调用后结果被缓存,主要用于更新操作@CacheEvict清除缓存@Caching配置复杂对缓存策略@CacheConfig同一配置本类的缓存注解额属性@EnableCaching开启基于注解的缓存serialize缓存数据的value序列haul策略@Cacheable/@CachePut/@CacheEvict主要的参数参数解释value/cacheNames缓存的名字。必须指定至少一个,可以配置多个例如:@Cacheable(value={"cache1","cache2"})key缓存的key。可以为空,如果指定要使用SpEL。默认将方法的所有参数组合起来作为key。例如:@Cacheable(value="cache1",key="#id")keyGenerator定义自动生成主键的策略,使用的时候key和keyGenerator二选一condition作缓存的条件。可以为空,使用SpEL表达式指定,返回true表示作缓存,否者不缓存。例如:@Cacheable(vlaue="cache",condition="#id>0")unless也是作缓存的条件。当条件为true时,就不缓存(和condition的效果是反的)。例如:@Cacheable(value="cache",unless="#idsync(@Cacheable)是否使用异步支持,这是Spring4.3以后才支持的,默认值false,不开启异步模式例如:@Cacheable(value="cache",sync=true)//开启异步模式allEntries(@CacheEvict)是否清空所有缓存内容。默认为false,如果指定为true,则方法调用后将立即清空所有缓存。beforeInvocation(@CacheEvict)是否在方法执行前清空缓存。默认为false,如果指定为true,则方法还没有执行的时候就清空缓存。默认情况下如果方法抛出异常,就没有办法清空缓存了。SpEL上下文数据,Spring提供了一些供我们使用的SpEL表达式,名称位置描述用法示例methodName(方法名)root对象当前被调用的方法名#root.methodnamemethod(方法)root对象当前被调用的方法#root.method.nametarget(当前对象)root对象当前被调用的目标对象实例#root.targettargetClass(目标类)root对象当前被调用的目标对象的类#root.targetClassargs(参数列表)root对象当前被调用的方法的参数列表#root.args[0]caches(缓存列表)root对象当前方法调用使用的缓存列表#root.caches[0].nameArgumentName(参数名)执行上下文当前被调用的方法的参数,如findArtisan(Artisanartisan),可以通过#artsian.id获得参数#artsian.idresult(方法返回值)执行上下文方法执行后的返回值(仅当方法执行后的判断有效,如unlesscacheEvict的beforeInvocation=false)#result3、Spring缓存的配置和使用3.1@Cacheable@Cacheable注解会先查询是否已经有缓存,有会使用缓存,没有则会执行方法并缓存。在CacheAspectSupport这个类的findCachedItem上打上断点,观察发下我们配置的key是有效:3.2自定义主键生成策略在方法中可以这么使用:同样,通过打断点发现我们配置的主键生成也起作用了:其他参数的用法可以参考下面的程序:3.3@CachePut@CachePut注解的作用主要用于对方法配置,能够根据方法的请求参数对其结果进行缓存,和@Cacheable不同的是,它每次都会触发真实方法的调用。简单来说就是用户更新缓存数据。但需要注意的是该注解的value和key必须与要更新的缓存相同,也就是与@Cacheable相同。@CachePut的其他参数的用法和一样@Cacheable参数的用法一样。这里不再赘述。3.4@CacheEvict@CachEvict的作用主要用于方法的配置,能够根据一定的条件对缓存进行清空。3.5@Caching有时候我们可能组合多个Cache注解使用,此时就需要@Caching组合多个注解标签了。3.6@CachingConfig当我们需要缓存的地方越来越多,你可以使用@CacheConfig(cacheNames={"cacheName"})注解来统一指定value/cacheNames的值,这时可省略value/cacheNames,如果你在你的方法依旧写上了value/cacheNames,那么依然以方法的@CacheConfig配置的值为准。使用方法如下:@CacheConfig可以配置单的属性如下:

    LoveIT 2019-09-28
    Spring Boot
  • Spring从入门到精通—自动配置Spring MVC的原理

    Spring从入门到精通—自动配置Spring MVC的原理

    1、SpringMVC自动配置SpringBoot对SpringMVC自动配置的详细可以参考管方文档。SpringBoot为SpringMVC提供的AutoConfiguration适用于大多数应用场景,SpringBoot对SpringMVC做了以下默认的自动配置:引入ContentNegotiatingViewResolver和BeanNameViewResolver。对静态资源的支持,包括对WebJars的支持自动注册Converter,GenericConverter,Formatter。对HttpMessageConverters的支持。自动注册MessageCodeResolver。对静态资源的支持对自定义Favicon的支持自动使用ConfigurableWebBindingInitializerbean。SpringBoot默认情况下是自动配置好SpringMVC的,可以直接使用,但是SpringBoot也支持我们修改SpringBoot对SpringMVC的配置。如果保留SpringBootMVC特性,我们只需添加其他的MVC配置(拦截器,格式化处理器,视图控制器等)。我们可以添加自己的WebMvcConfigurerAdapter类型的@Configuration类(配置类),而不需要注解@EnableWebMvc。如果希望使用自定义的RequestMappingHandlerMapping,RequestMappingHandlerAdapter,或ExceptionHandlerExceptionResolver,我们可以声明一个WebMvcRegistrationsAdapter实例提供这些组件。但是如果想全面控制SpringMVC,我们可以添加自己的@Configuration类,并使用@EnableWebMvc注解。这样SpringBoot就不会对MVC进行配置了。然后我们就可以像刚开始使用SpringMVC那样对他进行配置。2、SpringMVC自动配置原理细节SpringBoot对SpringMVC的自动配置主要是通过WebMvcAutoConfiguration这个类实现的,接下来我们就结合这个类来简单分析一下自动配置的细节。2.1ContentNegotiatingViewResolver和BeanNameViewResolver这两个一听名字就知道是和视图解析器有关,也确实是这样的,他们自动配置了ViewReslover,然后由ViewReslover得到View对象,View对象调用他的render方法渲染页面等等。其中BeanNameViewResolver就是SpringMVC中的一个视图解析器,他可以通过视图名来获得视图解析器,而ContentNegotiatingViewResolver的作用就是组合所有的视图解析器,下面他们的源码:问题:ContentNegotiatingViewResolver是如何组合所有视图解析器的因此,我们可以实现自己的视图解析器,然后ContentNegotiatingViewResolver把它注册到容器中。定制自己的视图解析器,我们可以在启动类中实现ViewResolver接口,编写我们自己的视图解析器,然使用@Bean标签配置给IOC容器。3、Converter,GenericConverter,Formatter这些功能在SpringBoot中也有默认的自动配置,这里我们要了解的是如何扩展配置Converter和Formatter。源码:我们也可以定制自己的转换器4、HttpMessageConvertersSpringMVC使用HttpMessageConverter接口转换HTTP请求和响应,合适的默认配置可以开箱即用,例如对象自动转换为JSON(使用Jackson库)或XML(如果JacksonXML扩展可用,否则使用JAXB),字符串默认使用UTF-8编码。可以使用SpringBoot的HttpMessageConverters类添加或自定义转换类:5、扩展SpringBoot对SpringMVC的配置想要扩展SpringBoot的MVC功能,我们要WebMvcConfigurer接口,但是这样太麻烦了,因此SpringBoot提供了一个适配器类WebMvcConfigurerAdapter,它里面全部是一些空方法,我们可以继承WebMvcConfigurerAdapter类,然后我们只需要按照我们的需要重写里面的方法就好了。6、全面接管SpringBoot对SpringMVC的自动配置官网中的一句话:IfyouwanttotakecompletecontrolofSpringMVC,youcanaddyourown@Configurationannotatedwith@EnableWebMvc.意思就是我们可以配置类上加上EnableWebMvc来全面接管SpringMVC,这样一来SpringBoot就不会对SpringMVC进行配置了,一切都需要我们来配置。

    LoveIT 2019-09-27
    Spring Boot
  • SpringBoot从入门到精通—MyBatis的配置和使用(注解+XML配置)

    SpringBoot从入门到精通—MyBatis的配置和使用(注解+XML配置)

    关于MyBatis,大部分人都很熟悉。MyBatis是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。这篇文章主要介绍了SpringBoot集成MyBatis的两种方式(注解和XML文件配置),需要的朋友可以参考下.1、使用XML配置MyBatis1.1在pom.xml文件中引入MyBatis的依赖1.2编写MyBatis的主配置文件Mybatis-config.xml在src/main/resources目录下新建mybatis文件夹,然后新建Mybatis-config.xml文件并配置如下:1.3编写Mapper接口以及对应的Mapper映射文件在src/main/java下新建mapper包,然后新建ArticleMapper接口如下:在src/main.resoures下新建mapper文件夹,然后在mapper文件夹中新建对应的Mapper映射文件ArticleMapper.xml如下:然后在application.yml文件中配置mybatis这两个文件的位置:编写一个controller,简单测试一下看看我们配置的MyBatis能不能用。这里为了简单就没有写对应的service。测试结果:2、使用注解配置MyBatisMyBatis提供了以下几个CRUD基本注解:*@Select*@Update*@Insert*@Delete增删改查占据了绝大部分的业务操作,掌握这些基础注解的使用还是很有必要的,例如下面这段代码无需XML即可完成数据查询:MyBatis提供的映射注解:@Results用于填写结果集的多个字段的映射关系.@Result用于填写结果集的单个字段的映射关系.@ResultMap根据ID关联XML里面.在启动类上使用@MapperScan扫描mapper包下的所有的Mapper接口,这样做的好处是可以省去在每个Mapper接口上写@Mapper注解。还可以写一个配置类彻底取代MyBatis的所有XML文件。MyBatisConfig.java编写一个controller,看看实际的效果:测试结果:

    LoveIT 2019-09-26
    Spring Boot
  • SpringBoot从入门到精通—SpringBoot启动流程剖析

    SpringBoot从入门到精通—SpringBoot启动流程剖析

           上图为SpringBoot启动结构图,我们发现启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器,第二部分实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块,第三部分是自动化配置模块,该模块作为springboot自动配置核心,在后面的分析中会详细讨论。在下面的启动程序中我们会串联起结构中的主要功能。1、基于源码简单剖析SpringBoot的启动流程Springboot的启动过程:SpringBoot应用启动后首先执行SpringBoot启动类的main方法中的publicstaticConfigurableApplicationContextrun(Class<?>primarySource,String...args)这个run方法,他又调用了重载方法的publicstaticConfigurableApplicationContextrun(Class<?>[]primarySources,String[]args),在这个run方法中调用了真正的run方法。他们的调用关系如下图:在调用正真干活的run方法之前,SpringAppication先进行了初始化:最终真正干活的run方法该方法中有几个关键的步骤:(1)创建了应用监听器SpringApplicationRunListeners并开始监听(2)加载SpringBoot配置环境ConfigurableEnvironment,如果是通过web容器发布,会加载StandardEnvironment,其最终也是继承了ConfigurableEnvironment,类图如下:(3)将从配置文件中加载进来的配置环境(Enviroment)加入到监听器中(4)创建应用配置上下文对象ConfigurableApplicationContext,我们可以到其具体的实现中看看:(5)回到run方法继续往下走,prepareContext()方法将listeners、environment、applicationArguments、banner等组件与上下文对象关联(6)调用refreshContext()方法是SpringBoot启动中最重要的一步,包括spring.factories的加载,bean的实例化等核心工作。这一步完成后SpringBoot的启动工作基本就完成了。下面是最终真正干活的refresh()方法的截图:方法首先获取显式获取并设置了应用上下文(applicationContextClass),如果不存在,再根据不同的Web环境选择实例化不同的上下文对象,默认选择AnnotationConfigApplicationContext注解上下文(通过扫描所有注解类来加载bean),最后通过BeanUtils实例化上下文对象,并返回。配置结束后,Springboot做了一些基本的收尾工作,返回了应用环境上下文。回顾整体流程,Springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),并基于以上条件,在容器中开始实例化我们需要的Bean,至此,通过SpringBoot启动的程序已经构造完成。启动过程中的一些细节代码说明:(1)在run方法一开始执行他就new了一个StopWatch,这个类有啥用呢?开启单步调试,最终发现这个类的功能就是统计一下SpringBoot启动所用的时间并在最会在启动完成打印出来。(2)在启动中有一个Banner,他的用处就是打印一下SpringBoot的logo

    LoveIT 2019-09-25
    Spring Boot
  • SpringBoot从入门到精通—嵌入式Servlet容器的配置、切换

    SpringBoot从入门到精通—嵌入式Servlet容器的配置、切换

    声明:以下的所有方法、原理、源码全部是建立在SpringBoot2.1.7版本。1、修改SpringBoot对嵌入式Server容器的默认配置SpringBoot默认使用Tomcat作为嵌入式的Servlet容器。实际应用中我们需要对他进行专门的定制。定制的方式不外乎两种:在配置文件中配置或在配置类中注册组件的方式配置1.1直接在application.properties/application.xml文件中配置和server有关的属性配置方式是server.属性名=值,下面是ServerProperties类中定义的绝大多数可以配置的属性配置示例:1.2向IoC容器中添加servlet容器工厂定制器WebServerFactoryCustomizer运行结果:如果使用的是SpringBoot1.x版本可以参考下面的方法来使用配置1.3向IoC容器中添加可配置的servlet容器工厂ConfigurableServletWebServerFactory运行自然是没有什么问题,在地址栏输入http://localhost:8089/springboot/也来到了目标页面:1.4在SpringBoot中注册Servlet三大组件【Servlet、Filter、Listener以前注册这些组件都是在web.xml中配置,由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。注册三大组件用以下方式:①、借助ServletRegistrationBean注册自定义Servlet组件;自定义【MyServlet】:定义【ServletRegistrationBean】并放入容器中:②、借助FilterRegistrationBean注册自定义Filter组件;(自定义的MyFilter忽略)③、借助ServletListenerRegistrationBean注册自定义Listener组件;(自定义的MyListener忽略)2、嵌入式Servlet容器切换2.1三大容器比较容器优点缺点默认tomcat功能齐全庞大,荣泽truejetty轻量功能不全falseundertow异步,高效不支持jspfalse2.2容器切换TomcatSpringBoot引入web模块默认就是使用嵌入式的Tomcat作为Servlet容器。`Jettyundertow3、嵌入式Servlet容器自动配置原理主要看三个类:*ServletWebServerFactoryConfiguration*ServletWebServerFactoryAutoConfiguration*ServletWebServerFactoryCustomizer3.1ServletWebServerFactoryConfiguration有三个:EmbeddedUndertow,EmbeddedJetty,EmbeddedTomcat@Conditionalxxx标注的类;条件满足才向容器中添加组件。ServletWebServerFactory:嵌入式Servlet工厂。作用:创建嵌入式Servlet容器在判断@ConditionalOnClass({Servlet.class,Tomcat.class,UpgradeProtocol.class})是否导入依赖,满足条件后returnnewTomcatServletWebServerFactory();添加对应的Servlet容器工厂;通过工厂的唯一方法getWebServer获取对应的Servlet容器TomcatServer.TomcatServletWebServerFactoryTomcatWebServer3.2ServletWebServerFactoryAutoConfiguration修改定制Servlet容器的方法:   1、配置文件中添加配置。   2、ServerProperties绑定/修改定制组件WebServerFactoryCustomizer他们的本质是一样的:在ServletWebServerFactoryAutoConfiguration配置类中@EnableConfigurationProperties({ServerProperties.class})。导入了BeanPostProcessorsRegistrar,在这个类的方法中添加了组件WebServerFactoryCustomizerBeanPostProcessor(定制器后置处理器)。也就是说一旦容器中添加任何组件都会启动定制后置处理器,进行Servlet的赋值。后置处理器起作用的过程:3.3ServletWebServerFactoryCustomizer在这个配置类中使用customize(ConfigurableServletWebServerFactoryfactory)这个方法完成了Tomcat的各项配置的修改和定制总结配置修改定制原理:以tomcat为例总结配置修改定制原理:以tomcat为例1、SpringBoot根据根据导入依赖的情况,给容器中添加相应的ServletWebServerFactory(比如tomcat就会添加TomcatServletWebServerFactory)2、如果使用的是通过application.propertoes修改配置,那么server相关的配置修改是与ServerProperties类绑定的,所以相关的修改会直接通过Serverproperties的方法实现【相关的配置类:ServletWebServerFactoryCustomizer】3、如果使用的是修改定制器WebServerFactoryCustomizer的方法来配置server,那么定制器会创建ConfigurableWebServerFactory对象,这样一来就会触发WebServerFactoryCustomizerBeanPostProcessor后置处理器,判断是否为WebServerFactory类型;满足条件后,就会获取容器中的所有定制器(customizer.cutomize(bean)),为Servlet容器修改和定制配置【相关的配置类ServletWebServerFactoryAutoConfiguration,导入了定制处理器】

    LoveIT 2019-09-24
    Spring Boot
  • SpringBoot从入门到精通—整合Druid数据源

    SpringBoot从入门到精通—整合Druid数据源

    java实现的数据库连接池有很多,比如c3p0,dbcp等,还有号称速度最快的HikariCP,并且springboot2.0.2版本默认使用的就是HikariCP。为什么选用Druid呢?-性能够好,比c3p0,dbcp强一些-经过考验,毕竟是阿里开源出来的项目-最关键的是带一个强大的数据库监控这些特性的加持下足以支撑起我使用Druid的理由。1、Druid能监控那些数据数据源SQL监控,对执行的MySQL语句进行记录,并记录执行时间、事务次数等SQL防火墙,对SQL进行预编译,并统计该条SQL的数据指标Web应用,对发布的服务进行监控,统计访问次数,并发数等全局信息URI监控,对访问的URI进行统计,记录次数,并发数,执行jdbc数等Session监控,对用户请求后保存在服务器端的session进行记录,识别出每个用户访问了多少次数据库等Spring监控,(按需配置)利用aop对各个内容接口的执行时间、jdbc数进行记录2、如何配置使用Druid想达到的目标效果,监控sql,监控sql防火墙,监控url,监控session,监控spring其中监控sql、监控url、基础信息,几乎不怎么需要配置,集成好druid,配置好监控页面,就可以显示。需要我们配置的大概分为3部分,基础连接池配置,基础监控配置,定制化监控配置2.1引入Druid的依赖2.2连接池基础配置主要配置用户名,密码,数据库驱动、数据库连接.....以及和连接池有关的配置2.3导入Druid数据源的其他属性上面的配置文件中和数据库连接池有关的配置属性在SpringBoot是没有的,因此我们需要告诉SpringBoot,让他在启动的时候去找加载这些属性,因此我们需要写一个配置类。没有写配置类之前的效果:写一个配置类写配置类后的效果,配置类起作用了:2.4配置Durid监控主要就是配置一个后台管理的Servlet—StarViewServlet和Web监控过滤器—WebStatFilter。具体有哪些初始化参数可以设置,可以参考这两个类以及他们的父类,都是以常量的方式出现的,配置的时候配置他们的值就可以了。写一个controller启动看看效果:启动后在浏览器地址栏输入localhost:8080/query,执行一次请求启动后在浏览器地址栏输入localhost:8080/druid,可以看到Druid后台管理的登录界面输入刚刚设置的用户名个密码,来到后台管理页面,点击SQL监控就可以看到刚才执行的SQL被记录了。其实主打开箱即用的SpringBoot,对于上面Druid监控的配置其实我们还可以直接在SpringBoot的配置文件中配置,下面是关于Druid监控的配置示例:

    LoveIT 2019-09-15
    Spring Boot
  • SpringBoot从入门到精通—Thymeleaf模板引擎快速上手

    SpringBoot从入门到精通—Thymeleaf模板引擎快速上手

    1、引言        在做WEB开发的时候,我们不可避免的要在前端页面之间进行跳转,中间进行数据的查询等等操作。我们在使用SpringBoot之前包括我在内其实大部分都是用的是JSP页面,可以说使用的已经很熟悉。但是我们在使用SpringBoot开发框架以后我们会发现一个致命的问题,就是SpringBoot对Jsp的支持可以说是惨不忍睹,因此官方推荐我们使用Thymeleaf模板引擎来解决问题。目前而言,当然模板引擎有很多,比如Velocity、Freemarker、等等,但是我这一直感觉thymeleaf相对于其他的来说好用的还是不少的。在这里我们就来了解一下thymeleaf这个模板引擎的用法!2、什么是模板引擎?        模板引擎是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档。用于网站的模板引擎(比如Thymeleaf模板引擎)就是将模板文件和数据通过模板引擎生成一个HTML文本。        简单说,通过使用模板引擎,可以将后端的数据填充到前端写好的页面模板中,作用类似JSP。和Thymeleaf类似的模板引擎还有Velocity、FreeMarker,它们完全可以替代JSP。3、SpringBoot中使用Thymeleaf模板引擎SpringBoot中提供了对模板引擎的支持,并且SpringBoot也建议我们使用模板引擎,常用的Thymeleaf使用的方法很简单,首先在pom.xml文件中引入thymeleaf的starter3.1引入Thymeleaf模板引擎的POM依赖        一般SpringBoot引入的都是依赖文件的最新的版本,如果发现不是最新的依赖版本或者你想更改依赖的版本,可以在<properties>标签中修改,比如修改thymeleaf的版本为3.0.10版本3.2使用Thymeleaf        引入Thymeleaf的依赖后,我们就可以使用了。在学习SpringBoot时无论是啥新东西,我们都可以打开XxxxAutoConfigration和XxxxProperties,从中我们可以基本了解SpringBoot对这个东西的默认配置。好了我们来看看Thymeleaf的配置类当然,我们也可以在SpringBoot的主配置文件中进行thymeleaf相关配置:#thymeleaf有关设置spring.thymeleaf.prefix=classpath:/templatesspring.thymeleaf.suffix=.htmlspring.thymeleaf.mode=HTML5spring.thymeleaf.encoding=UTF-8spring.thymeleaf.servlet.content-type=text/html#关闭模板缓存,避免更新无效spring.thymeleaf.cache=false(1)在控制层写一个跳转到hello.html页面的处理器方法(2)在html页面中导入thymeleaf名称空间,名称空间的导入不是必须的,但是导入后可以有提示,提示还是挺好用的。(3).然后在页面只用Thymeleaf语法获取服务器响应的数据测试结果:4、Thymeleaf模板引擎的基本语法4.1Thymeleaf常用属性下面列举一些Thymeleaf常用的属性,全部的属性还请参考Thymeleaf官方手册。Thymeleaf的属性都有一个优先级,优先级从1~8,数字越低优先级越高就会被先执行。(以下用order表示优先级大小)1、th:text:设置当前元素的文本内容,相同功能的还用th:utext,两者的区别是前者会转义特殊字符,后者不会。order=72、th:value:设置当前元素的value值,类似修改指定属性的还有th:src,th:herf,优先级order=63、th:each:遍历循环元素,和th:value或th:value一起使用。order=24、th:if:条件判断,类似的还有th:unless,th:switch,th:case。order=35、th:insert:代码块引入,类似的还有th:replaceth:include,三者的区别较大,若使用不恰当会破坏html结构,常用于公共代码块提取的场景。优先级最高:order=16、th:fragment:定义代码块,方便被th:insert引用。优先级最低:order=87、th:object:声明变量,一般和*{}一起配合使用,达到偷懒的效果。优先级一般:order=48、th:attr:修改任意属性,实际开发中用的较少,因为有丰富的其他th属性帮忙,类似的还有th:attrappend,th:attrprepend。优先级一般:order=5除了这些Thymeleaf定义的一些属性外,在HTML中所有的结点属性都可以使用th:属性名=值的方式来动态设定值,具体使用方法参考下面的例子。4.2Thymeleaf标准表达式语法${.....}变量表达式(VariableExpressions)#{.....}消息表达式(MessageExpressions)@{.....}链接表达式(LinkURLExpressions)~{.....}代码块表达式(FragmentExpressions)*{.....}选择变量表达式(SelectionVariableExpressions)1、${}变量表达式Thymeleaf的变量表达式使用的其实是OGNL表达式,变量表达式的功能非常丰富。(1)可以获取对象的属性、调用方法等(OGNL可以做的事他都可以做)(2)可以使用内置对象。官方手册上给的可以使用的内置对象如下:(3)可以使用一些内置的工具对象(方法)2、*{}选择表达式对于变量我们还可以使用*{}来处理,它和${}在功能上是一样的。但是有一个重要的区别:*{}评估所选对象上的表达式而不是整个上下文。也就是说,只要没有选定的对象,${}和*{}语法就会完全相同。下面是官网给的一个例子,可以说明这个问题:3、#{}消息表达式:主要用于处理资源国际化的。4、@{}链接表达式Thymeleaf中专门用于定义超链接的表达式。配合Thymeleaf中的th:href属性一起使用链接表达式@{}基本用法:链接表达式@{}高级用法:动态拼接URL请求路径:比如要拼接一个如下的动态路径:127.0.0.1/article/index/{id}?articleType=xxx&page=xxx,其中id是项目中每篇文章的id,articleType是文章的类型,page是控制分页的参数,现在要在页面提供这么一个连接来实现分页。实现结果:5、~{}代码块表达式Thymeleaf中专门用于引用片段的表达式。经常配合th:insert和th:replace属性使用,例如:合理的使用代码块表达式可以极大的减少我们项目中的冗余代码,尤其是页面中的冗余代码。我们可以把几个页面中公共使用的代码抽象成一个片段,然后在页面需要的位置引入代码块即可,而且更厉害的是Thymeleaf可以把页面的的head部分或者是JS脚本部分抽取出来统一管理,这样当我们项目发生改变的时候只用改一处就可以了。

    LoveIT 2019-09-11
    Spring Boot
  • SpringBoot从入门到精通—自动配置原理(深入源码)

    SpringBoot从入门到精通—自动配置原理(深入源码)

    1、引言不论在工作中,亦或是求职面试,SpringBoot已经成为我们必知必会的技能项。除了某些老旧的政府项目或金融项目持有观望态度外,如今的各行各业都在飞速的拥抱这个已经不是很新的Spring启动框架。当然,作为SpringBoot的精髓,自动配置原理的工作过程往往只有在“面试”的时候才能用得上,但是如果在工作中你能够深入的理解SpringBoot的自动配置原理,将无往不利。SpringBoot的出现,得益于“约定优于配置”的理念,没有繁琐的配置、难以集成的内容(大多数流行第三方技术都被集成),这是基于Spring4.x提供的按条件配置Bean的能力。2、SpringBoot自动配置原理2.1配置文件到底能写什么?怎么写?我们一接触SpringBoot的时候就了解到:SpringBoot有一个全局配置文件application.properties或application.yml。我们的各种属性都可以在这个文件中进行配置,最常配置的比如:server.port、logging.level.*、数据库配置、Redis配置等等,然而我们实际用到的往往只是很少的一部分,而且可以配置的属性都可以在官方文档中查找到。2.2自动配置原理?(1)@SpringBootApplication每个SpringBoot应用都有一个启动类,所有的SpringBoot项目必须从启动类启动(一般情况下SpringBoot启动类类名就是项目名+Application),启动类上必须使用@SpringBootApplication注解标注而且主程序类必须位于项目基包的根目录。这个注解是SpringBoot的核心注解,标有这个注解的应用就是基于SpringBoot的应用,我们的自动配置原理和这个注解还有着千丝万缕的联系!我们可以点看进去看看。@SpringBootApplication注解是一个复合注解,这里有三个重要注解:@SpringBootConfiguration:这也是一个复合注解,底层使用的是Spring的基础注解**@Configuration**,它的作用就是让SpringBoot引用支持JavaConfig的配置方式进行配置@EnableAutoConfiguration:开启自动配置,后面着重说明它的原理。@ComponentScan:开启包扫描,也是Spring的基础注解。默认扫描的是当前类下的包。这就是要把启动类放置到基包根目录下的原因,这样启动类就可以在启动的时候把包下的@Controller/@Service/@Component/@Repository等注解类加载到IOC容器中(2)@SpringBootConfiguration注解:@SpringBootConfiguratuon注解的作用是用来告诉SpringBoot这是一个SpringBoot的配置类,从他的源码可以看出它是@Configuration注解的派生注解,对于这个注解我们应该不会陌生,这个类是Spring的核心注解之一。因此可以知道的是这两个注解的功能大致是一样的,只不过一个是专门用于SpringBoot的配置类,另一个则在Spinrg体系中是通用的。(3)@EnableAutoConfiguration注解我们点进去看一下,发现有两个比较重要的注解:@AutoConfigurationPackage:自动配置包@Import:给IOC容器导入组件(3.1)@AutoConfigurationPackage注解这个注解的作用即使自动配置包,查看源码我们可以发现,依靠的还是**@Import**注解,它使用@Import注解导入再点进去查看,我们发现重要的就是以下的代码:在默认的情况下就是将主配置类(@SpringBootApplication)的所在包及其子包里边的组件扫描到Spring容器中。看完这句话,会不会觉得,这不就是@ComponentScan注解的功能吗?这俩不就重复了吗?我开始也有这个疑问,直到我看到文档的这句话:itwillbeusedwhenscanningforcode@Entityclasses.ItisgenerallyrecommendedthatyouplaceEnableAutoConfiguration(ifyou'renotusing@SpringBootApplication)inarootpackagesothatallsub-packagesandclassescanbesearched.比如说,你用了SpringDataJPA,可能会在实体类上写@Entity注解。这个@Entity注解由@AutoConfigurationPackage扫描并加载,而我们平时开发用的@Controller/@Service/@Component/@Repository这些注解是由ComponentScan来扫描并加载的。因此这二者扫描的对象是不一样的。(3.2)@Import注解SpringBoot自动配置功能就是由Import注解后面那个类AutoConfigurationImportSelector实现的(1.5版本以前使用EnableAutoConfigurationImportSelector类,1.5以后这个类废弃了使用的是AutoConfigurationImportSelector类)。这个类会调用SpringFactoriesLoader.loadFactoryNames()方法来扫描定义在MEAT-INF/spring.factories文件中的jar包AutoConfigurationImportSelector实现了ImportSelector接口,这个接口中只有一个方法selectImports(),它的作用是控制哪些类自动的实例加入到容器中,在SpringBoot2.1.7版本中得源码如下:在selectImports()方法的源码中使用了getAutoConfigurationEntry()这个方法,其中configurations存放的数据就是加入容器的自动配置类的完整包路径,继续追踪源码,进入getAutoConfigurationEntry()源码:从getCandidateConfigurations()方法的实现中,我们发现他调用SpringFactoriesLoader.loadFactoryNames反返回了List集合,返回的东西是啥呢?我们直接追踪源码:通过DEBUG可以看到,返回对List中全部是一些类的全限定名。如果继续往下追踪发现他最终在loadFactories方法中使用本类的一个私有静态方法loadSpringFactories加载了META-INF/spring.factories这个配置文件。查看spring-boot-autoconfigure包下META-INF/spring.factories:看到的非常多的xxxxAutoConfiguration类,这些类都是容器中的一个组件,加入到容器中,用他们做自动配置。2.2SpringBoot自动配置原理总结@SpringBootApplication等同于下面三个注解:@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan其中@EnableAutoConfiguration是关键(启用自动配置),内部实际上就去加载META-INF/spring.factories文件的信息,然后筛选出以EnableAutoConfiguration为key的数据,加载到IOC容器中,实现自动配置功能!官网参考文档:https://docs.spring.io/spring-boot/docs/2.2.0.BUILD-SNAPSHOT/reference/html/using-spring-boot.html#using-boot-structuring-your-code3、@Conditional派生注解SpringBoot在启动的时候为我们加载了这么多组件,我们不可能全部用得上,那如果用不上的还注册进容器,岂不是耗费资源。其实底层使用了条件装配@Conditional,在我们需要的情况下才会注册对应的组件。比如,SpringBoot中对AOP的自动配置如下所示:AOP的自动配置中使用了非常多的条件注解:@ConditionalOnClass({EnableAspectJAutoProxy.class,Aspect.class,Advice.class,AnnotatedElement.class})表示当类路径上存在EnableAspectJAutoProxy、Aspect、Advice、AnnotatedElement时才会自动配置@ConditionalOnProperty(prefix="spring.aop",name={"auto"},havingValue="true",matchIfMissing=true)表示当配置文件中存在配置项spring.aop.auto=true时会自动配置,不过这里默认值就是true,所以默认会配置@ConditionalOnProperty(prefix="spring.aop",name={"proxy-target-class"},havingValue="true/false",matchIfMissing=true/false)表示当配置文件中存在配置项spring.aop.proxy-target-class并且当它的值为true的时候会使用CGLib代理,否则默认会使用JDK动态代理在SporingBoot源码中下方这些Condition注解比较常见:Conditional扩展注解作用(判断是否满足当前指定条件)@ConditionalOnJava系统的java版本是否符合要求@ConditionalOnBean容器中存在指定Bean;@ConditionalOnMissingBean容器中不存在指定Bean;@ConditionalOnExpression满足SpEL表达式指定@ConditionalOnClass类路径上有指定的类@ConditionalOnMissingClass系统中没有指定的类@ConditionalOnSingleCandidate容器中只有一个指定的Bean,或者这个Bean是首选Bean@ConditionalOnProperty系统中指定的属性是否有指定的值@ConditionalOnResource类路径下是否存在指定资源文件@ConditionalOnWebApplication当前是web环境@ConditionalOnNotWebApplication当前不是web环境@ConditionalOnJndiJNDI存在指定项Q:如何知道哪些自动配置类生效了,哪些配置类没有生效?A:我们可以通过在主配置文件中配置debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效。如下:

    LoveIT 2019-09-10
    Spring Boot
  • SpringBoot从入门到精通—配置文件详解

    SpringBoot从入门到精通—配置文件详解

    1、SpringBoot配置文件    SpringBoot支持两种形式的配置文件,分别是.properties、和.yml,而且配置文件的名字是固定不可变的:*application.properties*application.yml    配置文件的作用是修改SpringBoot自动配置的默认值。相对于properties文件而言,yml文件更年轻,也有很多的坑。下面我们就来一一学习一下。    注意:当application.properties文件和application.yml同时存在的时候,application.properties会优先加载,application.yml则后加载,而且在applicatin.properties中已经加载的属性如果在application.yml中再次出现会被忽略,如果是application.yml中的独有的属性则会加载。2、YAML/YML文件简介2.1什么是YAML/YML文件    YAML是"YAMLAin'taMarkupLanguage"(YAML不是一种置标语言)的递回缩写。YAML是一个可读性高,用来表达资料序列的编程语言。YAML是一种直观的能够被电脑识别的的数据数据序列化格式,容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,比如:C/C++,Ruby,Python,Java,Perl,C#,PHP等。YAML以数据为中心,比json、xml等更适合做配置文件。2.2YAML/YML的基本语法基本语法:key:value,key:和value中间要有一个空格,而且key:value的形式可以写无限层。还有一下规则:1.大小写敏感2.使用缩进表示层级关系3.缩进时不允许使用Tab键,只允许使用空格。4.缩进的空格数目不重要,只要相同层级的元素左侧对齐即可5.只有一种注释方式,使用#2.3YAML/YML支持的数据结构YML支持3中类型的数据结构类型1.字面量2.对象(属性和值),Map(键值对)3.数组(List、Set)1、字面量具体包括:字符串、布尔值、整数、浮点数、Null、时间、日期字面量可以直接使用,但是特别注意字符串的字面量在写的时候是不需要引号的(无论单引号还是双引号)。单/双引号在yml语法中有特殊的含义:​*“”:双引号;会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思​name:“zhangsan\nlisi”:输出;zhangsan换行lisi*​”:单引号;不会转义特殊字符,特殊字符最终只是一个普通的字符串数据name:‘zhangsan\nlisi’:输出;zhangsan\nlisi2.对象(属性和值),Map(键值对)基本的语法还是key:value,以一个例子来说明:对应的行内写法:3.数组(List、Set)用-值表示数组中的一个元素行内写法举个栗子:配置一个Person的信息我们可以导入配置文件处理器,编写配置的时候就有提示了在application.yml配置文件中配置preson信息:在SpringBoot测试类中测试IOC是否可以拿到在配置文件中配置的信息测试结果:3、properties文件简介    properties文件大家经常用,这里就简单介绍一下。其语法结构形如:key=value。注意中文乱码问题,需要转码成ASCII。在IDEA中可以设置自动转换把uft-8格式自动转成ASCII,设置方式是:依次点击【File】=>【OtherSettings】=>【settigsfornewprojects】,搜索FileEncodings,然后做如下配置:上面Person信息的properties配置如下:4、配置文件值注入4.1@Value获取值和@ConfigurationProperties获取值比较    SpringBoot通过ConfigurationProperties注解从配置文件中获取属性。从上面的例子可以看出ConfigurationProperties注解可以通过设置prefix指定需要批量导入的数据。支持获取字面值,集合,Map,对象等复杂数据。ConfigurationProperties注解还有其他特么呢?它和Spring的Value注解又有什么区别呢?带着这些问题,我们继续往下看。比较@ConfigurationProperties@Value功能批量注入配置文件中的属性一个个指定松散绑定(松散语法)支持不支持SpEL不支持支持JSR303数据校验支持不支持复杂类型封装支持不支持**何时使用@Value何时使用@ConfigrationProperties?**如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value。如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties。4.1配置文件注入值数据校验使用@Vaildatad可以给配置的属性数据校验功能。可以用在类、方法、参数上。可以加的验证注解如下:下面举个例子:4.2@PropertySource&@ImportResource&@Bean@PropertySource:加载指定的配置文件;person.properties@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效;在src/main/resources下新建一个Spring配置文件applicationContext.xml在SpringBoot的主程序类中使用@ImportResource引入配置这个配置文件然后在测试类中自动注入ApplicationContext来拿这个组件测试结果:虽然这种方式可以用,但是一般我们不这么用,而且SpringBoot也不推荐这么使用,SpringBoot推荐使用全注解的方式来添加配置文件。*1、配置类**@Configuration**------>Spring配置文件2、使用**@Bean**给容器中添加组件接下类,我们在com.xust.iot基包下新建配置类ApplicationConfig.java运行后得到的效果一样:5、配置文件占位符在application.properties和application.yml文件可以使用${random}来设置随机值5.1常用随机设值如下在application.yml文件中写如下配置:在测试类中打印person的信息,结果如下:6、SpringBootprofile    Spring支持对不同环境,提供不同配置,可以通过激活、指定参数等方式快速的切换环境。环境profile可以是开发环境(develop)、测试环境(fuy)、生产环境(production)等6.1配置多个profile在主配置文件编写的时候,文件名可以是application-{profile_name}.properties/yml,比如下面分别编写的application-develop.properties和application-production.propertiesapplication-develop.propertiesapplication-production.properties目录结构:在主配置文件application.properties中,使用spring.profiles.active=[profile]来激活不同的环境,如下激活develop环境:启动SpringBoot观察Tomcat启动的端口激活生产环境:spring.profiles.active=production可以看到,配置的不同环境被激活后都起作用了。这在以后的开发中无疑是个十分强大而且方便的功能。6.2YML配置多个profile然而使用properties文件配置不同环境还是太麻烦了,YML对多profile的支持更加简单粗暴,直接通过连续的三个-就可以划分出不同的文件,配置示例:注意:SpringBoot启动的时候会优先加载.properties的文件,然后才来加载.yml文件,如果要想使applicaton.yml中配置的信息可以使用,那么.properties中不能有和.yml相同的配置。6.3激活指定profile的不同方式1、在主配置文件中指定spring.profiles.active=dev,上面的配置方式就是这种。​2、命令行:可以在IDEA中配置--spring.profiles.active=develop来启动开发环境,操作如下:也可以在命令行中使用java-jarspring_boot_config-0.0.1-SNAPSHOT.jar--spring.profiles.active=develop来启动开发环境3、虚拟机参数:可以在IDEA中做如下配置:-Dspring.profiles.active=dev,示例如下:7、配置文件的加载位置springboot启动会扫描以下位置的application.properties或者application.yml文件作为Springboot的默认配置文件–file:./config/–file:./–classpath:/config/–classpath:/这些位置的配置文件加载的优先级由高到底,而且高优先级的配置如果在低优先即中出现,那么低优先优先级中重复配置不会生效。但是低优先级中独有的配置还是会生效。也就是说SpringBoot会从这四个位置全部加载主配置文件;并且会互补配置;==我们还可以通过spring.config.location来改变默认的配置文件位置==比如:项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形成互补配置;首先在硬盘的另一个地方(我这里在E://)创建application.properties。添加如下配置:然后可以在命令行输入java-jarspring_boot_config-0.0.1-SNAPSHOT.jar--spring.config.location=E://application.properties####8、外部配置加载顺序**==SpringBoot也可以从以下位置加载配置,加载顺序的优先级从高到低;高优先级的配置会覆盖低优先级的配置,所有的配置会形成互补配置==**。**1.命令行参数**所有的配置都可以在命令行上进行指定java-jarspring_boot_config-0.0.1-SNAPSHOT.jar--server.port=8087--server.context-path=/abc多个配置用空格分开;`--配置项=值`2.来自java:comp/env的JNDI属性3.Java系统属性(System.getProperties())4.操作系统环境变量5.RandomValuePropertySource配置的random.*属性值==**由jar包外向jar包内进行寻找;**====**优先加载带profile的配置文件**==**6.jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件****7.jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件**==**再来加载不带profile的配置文件**==**8.jar包外部的application.properties或application.yml(不带spring.profile)配置文件****9.jar包内部的application.properties或application.yml(不带spring.profile)配置文件**10.@Configuration注解类上的@PropertySource11.通过SpringApplication.setDefaultProperties指定的默认属性所有支持的配置加载来源[参考官方文档](https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/htmlsingle/#boot-features-external-config)。

    LoveIT 2019-09-09
    Spring Boot
  • SpringBoot与日志

    SpringBoot与日志

    一、日志框架分类目前,日志框架有很多,例如:JUL(java.util.logging)、JCL(ApacheJakartaCommonsLogging)、Log4j、Log4j2、LogBack、SLF4J、jboss-logging等等。日志门面日志实现JCL(ApacheJakartaCommonsLogging)SLF4J(SimpleLoggingFacadeforJava)jboss-loggingLog4jJUL(java.util.logging)Log4j2Logback    日志门面就是日志的抽象层,里面只是定义了日志的规范,日志实现就是来具体实现日志门面的。日志门面中这里重点来介绍一下SLF4J。1、SLF4J    slf4j是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现。因为接口并不能独立使用,需要和具体的日志框架实现配合使用(如log4j、logback)。那么问题来了,我们有了日志的实现,为什么还需要日志门面(日志抽象层)?    我们都知道使用一个接口实际上使用的是这个接口的实现类,那好了,我只要在程序中使用接口中的API来操作日志,然后导入实现了这个日志接口的日志实现类,程序就可以正常的记录日志;下次我们导入了另一套基于这个接口实现的日志实现类,不用改我们在程序中写的任何日志代码程序还是可以正常的记录日志。原理很简单,日志实现类实现了日志接口的规范。因此这个问题的回答总结为一句话:使用日志框架接口更便于更换为其他的日志框架。    log4j、logback、log4j2都有SLF4J的具体实现,他们既可以单独使用,也可以结合SLF4J框架使用。相关的Maven依赖写法:2、Log4J    log4j是apache实现的一个开源日志组件。通过使用log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIXSyslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。然而log4j已经很多年没有更新过了,小项目可以使用,大项目还是算了吧。相关的Maven依赖写法:3、Logback    logback同样是由log4j的作者设计完成的,拥有更好的特性,是用来取代log4j的一个日志框架,是slf4j的原生实现,所以logback与slf4j的结合最好。    Logback,一个“可靠、通用、快速而又灵活的Java日志框架”。logback当前分成三个模块:logback-core,logback-classic和logback-access。logback-core是其它两个模块的基础模块。logback-classic是log4j的一个改良版本。此外logback-classic完整实现SLF4JAPI使你可以很方便地更换成其它日志系统如log4j或JDKLogging。logback-access访问模块与Servlet容器集成提供通过Http来访问日志的功能。因此在log4j和logback之间选择的话,我们应该选择更强大的logback。理由如下:1.logback比log4j要快大约10倍,而且消耗更少的内存。2.logback-classic模块直接实现了SLF4J的接口,所以我们迁移到logback几乎是零开销的。3.logback不仅支持xml格式的配置文件,还支持groovy格式的配置文件。相比之下,Groovy风格的配置文件更加直观,简洁。4.logback-classic能够检测到配置文件的更新,并且自动重新加载配置文件。5.logback能够优雅的从I/O异常中恢复,从而我们不用重新启动应用程序来恢复logger。6.logback能够根据配置文件中设置的上限值,自动删除旧的日志文件。7.logback能够自动压缩日志文件。8.logback能够在配置文件中加入条件判断(if-then-else)。可以避免不同的开发环境(dev、test、uat…)的配置文件的重复。9.logback带来更多的filter。10.logback的stacktrace中会包含详细的包信息。11.logback-access和Jetty、Tomcat集成提供了功能强大的HTTP-access日志。相关的Maven依赖写法:4、log4j2引用官网的一句话ApacheLog4j2isanupgradetoLog4jthatprovidessignificantimprovementsoveritspredecessor,Log4j1.x,andprovidesmanyoftheimprovementsavailableinLogbackwhilefixingsomeinherentproblemsinLogback’sarchitecture.翻译过来就是说:ApacheLog4j2是对Log4j的升级,它比其前身Log4j1.x提供了重大改进,并提供了Logback中可用的许多改进,同时修复了Logback架构中的一些固有问题。Log4j2的特性:1.插件式结构。Log4j2支持插件式结构。我们可以根据自己的需要自行扩展Log4j2.我们可以实现自己的appender、logger、filter。2.配置文件优化。在配置文件中可以引用属性,还可以直接替代或传递到组件。而且支持json格式的配置文件。不像其他的日志框架,它在重新配置的时候不会丢失之前的日志文件。3.Java5的并发性。Log4j2利用Java5中的并发特性支持,尽可能地执行最低层次的加锁。解决了在log4j1.x中存留的死锁的问题。4.异步logger。Log4j2是基于LMAXDisruptor库的。在多线程的场景下,和已有的日志框架相比,异步的logger拥有10倍左右的效率提升。相关的Maven依赖写法:二、日志框架的使用1、SLF4J2、什么时候使用SLF4J比较合适呢?    如果你开发的是类库或者嵌入式组件,那么就应该考虑采用SLF4J,因为不可能影响最终用户选择哪种日志系统。在另一方面,如果是一个简单或者独立的应用,确定只有一种日志系统,那么就没有使用SLF4J的必要。3、如何在系统中使用SLF4J?(官网:https://www.slf4j.org/manual.html)下面是官网给的一个使用实例,以后如果要是用SLF4J,那就不要直接调用实现类的API,而是应该调用SLF4J里面的API,当然只是使用日志实现类另当别论!4、Log4J    log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、数据库等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。    Log4j有7种不同的log级别,按照等级从低到高依次为:TRACE、DEBUG、INFO、WARN、ERROR、FATAL、OFF。如果配置为OFF级别,表示关闭log。Log4j支持两种格式的配置文件:properties和xml。包含三个主要的组件:Logger、appender、Layout。一个简单的log4j配置文件在SpringBoot中使用log4j    首先创建一个SpringBoot工程,在创建SpringBoot工程时,我们引入了spring-boot-starter,其中包含了spring-boot-starter-logging,由于SpringBoot默认的日志框架是Logback,所以我们在引入log4j之前,需要先排除该包的依赖,再引入log4j的依赖。配置log4j-spring.properties    配置文件的编写方法上面介绍的没有啥区别,但是配置文件的名字可以是log4j-spring.properties也可以是log4j.properties,但是SpringBoot官方推荐的命名方式是第一种方式。配置文件的内容参考上面。在SpringBoot主配置文件中指定日志文件的配置5、Logbacklogblack的加载顺序SLF4J+Logback是SpringBoot默认的日志策略,logback支持xml和groovy形式的配置文件,而且还支持编程式地配置,它加载配置文件的顺序:在classpath中寻找logback-test.xml文件如果找不到logback-test.xml,则在classpath中寻找logback.groovy文件如果找不到logback.groovy,则在classpath中寻找logback.xml文件如果上述的文件都找不到,则logback会使用JDK的SPI机制查找META-INF/services/ch.qos.logback.classic.spi.Configurator中的logback配置实现类,这个实现类必须实现Configuration接口,使用它的实现来进行配置如果上述操作都不成功,logback就会使用它自带的BasicConfigurator来配置,并将日志输出到console在SpringBoot中使用LogBack(官网:https://logback.qos.ch/documentation.html)前面说过,logback是SpringBoot默认的日志系统,假如对日志没有特殊要求,可以完全零配置使用SLF4J(SimpleLoggingFacadeForJava)的logback来输出日志。    上面这段程序,不经过任何配置,默认的日志系统是完全可以正常运行的。但是SpringBoot也支持我们修改默认配置,修改的方式有两种,一种是在src/main/resources下新建logback-spring.xml文件(logback.xml也可以,但官方推荐前面的写法);第二种是直接在SpringBoot主配置文件中配置,下面是简单的配置示例:logbac-spring.xmlapplication.properties6、扩展使用springProperty    在logback-spring.xml中可以使用SpringBoot扩展的,使用它可以把在application.properties中定义的属性值映射为logback环境中的一个属性,从而可以在logback的上下文使用。举个例子:    下面的配置中定义了属性appName对应于SpringBoot的Environment中的app.name(由source属性指定),当未指定时默认使用defaultValue属性指定的TEST;属性name对应于SpringBoot的Environment中的logging.path,未指定时使用/logs/${appName}.log,其中的${appName}又对应于变量appName的值。定义好的变量可以在logback的配置文件中以${varName}的形式进行引用。三、多个不同的日志框架共用SLF4J    经常在实际的开发环境中,我们会使用到不同的框架,而且不同的框架默认的日志系统不同,那么如何在SpringBoot中设置一下,让这些不同框架的默认日志系统可以借助于SpringBoot的默认日志系统来工作?这是可以办到的,具体的步骤如下:1、在pom.xml文件中导入依赖的时候排除所使用框架对默认日志系统的依赖2、用SLF4J提供的中间包替换原有日志框架下图有详细的配置方法:

    LoveIT 2019-09-07
    Spring Boot
  • SpringBoot从入门到精通—SpringBoot快速入门

    SpringBoot从入门到精通—SpringBoot快速入门

    1、入门环境准备在本地安装3.3版本以上的Maven,以及JDK1.7以上的java环境,然后在IDEA【settings】=>【File|Settings|Build,Execution,Deployment】=>【Maven】,设置如下内容:2、使用Maven构建SpringBoot工程    第一个程序我们先创建一个Maven工程。创建好Maven项目后,首先导入SpringBoot的依赖包,他的依赖可以在SpringBoot的官网找到。注意:    1.spring-boot-starter-parent的父项目是spring-boot-dependencies(SpringBoot的版本仲裁中心),他的作用是用来管理SpringBoot应用里面的所有依赖版本    2.spring-boot-starter-web:spring-boot-starter我们称作spring-boot场景启动器,SpringBoot将所有的功能场景都抽取出来,做成一个个的starters(启动器),只需要在项目里面引入这些starter,相关场景的所有依赖都会导入进来(要用什么功能就导入什么场景的启动器)。spring-boot-starter-web的作用是帮我们导入了web模块正常运行所依赖的组件;完成上面的操作后,在src/main/java下新建一个主程序类Application.java类注意!    1、主程序类必须位于项目基包的根目录(具体原因下面会说),而且要使用@SpringBootApplication来告诉SpringBoot这是一个主程序类(配置类),这么标注后SpringBoot就会从这个类的main方法启动并加载配置。    2、@SpringBootApplication是基于SpringBoot基本注解的一个复合注解,源码片段如下:        2.1、@SpringBootConfiguration:标注在某个类上,表示这是一个SpringBoot的配置类;底层实际还是使用的是Spring的底层注解@Configuration        2.2、@ComponnetScan:标注在类上,就是我们熟悉的包扫描        2.3、@EnableAutoConfiguration:开启自动配置功能;以前我们需要配置的文件,在类上写上这个注解,SpringBoot帮我们自动配置。自动配置是SpringBoot的一大特性,关于它的原理可以参看我的另一篇文章SpringBoot从入门到精通—自动配置原理(深入源码)然后在src/main/java包下新建controller包,在这个包下新建HelloWordController.java这样一个简单的SpringBoot程序就写好了,在主程序类中点击运行按钮启动它。下面是运行后的结果:关于运行结果的说明:启动后我们访问http://localhost:8080,回车后就会出现WhitelableErrorPage提示,这是SpringBoot默认的错误页面,由于我们没有指定初始页面,出错很正常,之后在地址栏中请求hello,就可以看到我们写的Helloword,helloSpringBoot!1.2SpringBoot使用可执行jar文件部署应用    基于SpringBoot开发项目,不仅开发起来十分容易,而且由于他内置了Tomcat、Jetty等应用服务器,因此使得我们的部署也不再需要外部的应用服务器了,我们可以把SpringBoot使用Maven打包成jar文件后直接执行起来就可以了。    把SpringBoot打包成jar文件需要spring-boot-maven-plugin这个插件(在上面有依赖文件中已经导入)。在POM文件中导入后,我们在IDEA有侧边栏点击【Maven】=>【项目名】=>【Lifecycle】=>【package】,双击package就会运行插件就可以我们的应用打包成一个可运行的jar包(或者在IDEA自带的控制台中在当前项目的根目录下使用命令mvncleanpackage)。打包后我们在target目录下可以找到他,然后复制在里一个目录中在命令行中cd到这个目录,执行java-jarjar包名这个命令可以执行打包后的应用。下面是执行后命令行的打印:2、使用SpringInitializer快速创建SpringBoot项目【推荐】除了使用Maven构建一个SpringBoot项目之外,我们还可以使用Spring官方提供的SpringInitializer来快速构建一个SpringBoot项目。在IDEA依次点击【New】=>【Project】然后选择【SpringInitializr】使用SpringInitializr构建的SpringBoot项目中主程序类已经生成好了,我们只需要我们实现业务逻辑resources文件夹中目录结构static:保存所有的静态资源,如:jscssimages;templates:保存所有的模板页面,SpringBoot默认jar包使用嵌入式的Tomcat,默认不支持JSP页面,可以使用模板引擎(freemarker、thymeleaf);application.properties:SpringBoot的配置文件;可以修改一些默认设置。这个文件也支持YAML格式的文件,用YAML格式配置的文件结构更加简洁,清晰。

    LoveIT 2019-09-07
    Spring Boot
  • SpringMVC文件下载和上传

    SpringMVC文件下载和上传

    1、文件下载文件下载的最重要的一点是设置响应头的Content-disposition为attachmen;filename=要下载的文件的名字,然后得到文件的输入流写入本地即可1.常规方法2.使用SpringMVC提供的ResponseEntity<T>类型,使用它可以很方便地定义返回的HttpHeaders和HttpStatus。下载页面测试结果2、文件上传文件上传这里使用的是commons-fileupload-1.4,他需要依赖commons-io,他们的Maven依赖如下:(1)单文件上传上传表单页面文件上传最重要的一点就是将表单的提交方法设置为post,并且将enctype的值设置为"multipart/form-data"。控制器在Controller的处理方法中,使用MultipartFile对象作为参数接收前端上传过来的文件在springmvc配置文件中注册文件上传组件使用MultipartFile对象接收前端上传过来的文件,还需要在springmvc的配置文件中进行如下配置:(2)多文件上传其实多文件上传也很简单,单文件上传是在Controller的处理方法中使用MultipartFile对象作为参数接收前端上传过来的文件,而多文件上传则使用MultipartFile对象数组来接收。页面该页面中有几个name值一样的file类型的input标签,其他跟单文件上传的页面没区别。控制器同样的,使用MultipartFile数组接收前端上传过来的多个文件,也需要在springmvc的配置文件进行配置,具体配置与上述单文件上传的springmvc.xml配置没差别。这样,就可以进行多文件上传了。多种文件上传情景综合当然,项目开发中,场景可能并不是这么简单,上述的多文件上传是一个个文件选择后一起上传(即多个name相同的input标签),那要是我项目中只要一个input标签就可以一次性多个文件呢?又或者一个页面中既要一个个选择的多文件上传,又要一次性选择的多文件上传,还要有单文件上传呢?没问题,MultipartFile[]通吃,代码也很easy,下面直接上代码。页面控制器测试结果MultipartFile[]就是如此强大,不管单个多个,逻辑处理一样,所以建议在项目开发中使用MultipartFile[]作为文件的接收参数。3、重要方法和参数1、MutipartFile类的一些常用方法:StringgetContentType()//获取文件MIME类型InputStreamgetInputStream()//获取文件流StringgetName()//获取表单中文件组件的名字StringgetOriginalFilename()//获取上传文件的原名longgetSize()//获取文件的字节大小,单位bytebooleanisEmpty()//是否为空voidtransferTo(Filedest)//保存文件到服务器指定路径2、CommonsMultipartResolver的属性解析defaultEncoding:表示用来解析request请求的默认编码格式,当没有指定的时候根据Servlet规范会使用默认值ISO-8859-1。当request自己指明了它的编码格式的时候就会忽略这里指定的defaultEncoding。uploadTempDir:设置上传文件时的临时目录,默认是Servlet容器的临时目录。maxUploadSize:设置允许上传的总的最大文件大小,以字节为单位计算。当设为-1时表示无限制,默认是-1。maxUploadSizePerFile:跟maxUploadSize差不多,不过maxUploadSizePerFile是限制每个上传文件的大小,而maxUploadSize是限制总的上传文件大小。maxInMemorySize:设置在文件上传时允许写到内存中的最大值,以字节为单位计算,默认是10240。resolveLazily:为true时,启用推迟文件解析,以便在UploadAction中捕获文件大小异常。

    LoveIT 2019-08-12
    Spring MVC
  • SpringMVC拦截器(Interceptor)详解

    SpringMVC拦截器(Interceptor)详解

    1、拦截器概述1.1什么是拦截器?       SpringMVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),但是比过滤器的功能更加强大,它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。要使用SpringMVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义:1.通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。2.通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。2、自定义拦截器以实现HandlerInterceptor接口方式为例,自定义拦截器类的代码如下:上述代码中,自定义拦截器实现了HandlerInterceptor接口,并实现了接口中的三个方法:preHandle():在目标方法执行之前回执行,有个boolean类型的返回值,当返回true表示放行,即允许执行目标方法;当返回false,表示不放行,即不运行执行目标方法,此时会中断以后的所有过程postHandle():在目标方法执行结束后会执行,且解析视图之前执行afterCompletion():在请求到达页面,即视图渲染完成后执行开发拦截器就像开发servlet或者filter一样,都需要在配置文件进行配置,配置代码如下:上面的代码中,<mvc:interceptors>元素用于配置一组拦截器,子元素<bean>中定义的是全局拦截器,它会拦截所有的请求;而也可以使用<mvc:interceptor>元素中定义指定路径的拦截器,它会对指定路径下的请求生效。<mvc:interceptor>元素的子元素<mvc:mapping>用于配置拦截器作用的路径,该路径在其属性path中定义。如果在请求路径中包含不需要拦截的内容,还可以通过<mvc:exclude-mapping>元素进行配置。注意:<mvc:interceptor>中的子元素必须按照上述代码中的配置顺序进行编写,即<mvc:mapping><mvc:exclude-mapping><bean>,否则文件会报错。下面写一个控制器来测试一下正常情况下单个拦截器的工作流程:目标页面success.jsp测试结果2.1单个拦截器正常情况下的工作流程:拦截器preHandle方法执行,返回true继续以后的过程控制器目标方法执行拦截器postHandle方法执行页面渲染完成来到页面拦截器afterCompletion方法执行单个拦截器非正常情况下的工作流程:单个拦截器的非正常情况分为两种情况:    1、拦截器中的preHandler方法返回false;    2、虽然preHandler方法返回了true,但是其中有一个过程“炸了”,比如发生了异常没有处理接下来通过代码来测试:-第一种情况:preHandler返回false测试结果:可以看到,后面的过程直接无法执行第二种情况:preHandle方法放行了,但是有一个过程“炸了”,比如我们在控制器目标方法中制造一个异常:测试结果:可以看到,只要拦截器的prehandle方法放行了,拦截器的afterCompletion方法总会执行/font>#####2.2多个拦截器正常情况下的工作流程:实现第二个自定义拦截器:```javapackagecom.xust.iot.interceptor;importorg.springframework.web.servlet.HandlerInterceptor;importorg.springframework.web.servlet.ModelAndView;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;publicclassMySecondInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{System.out.println("1.执行目标方法之前......MySecondInterceptor");returntrue;}@OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{System.out.println("3.执行目标方法之后......MySecondInterceptor");}@OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{System.out.println("5.来到页面之后......MySecondInterceptor");}}```配置第二个拦截器```xml可以具体配置拦截器拦截那些请求>-->```执行结果:交换拦截器在springmvc配置文件中的定义顺序:```xml可以具体配置拦截器拦截那些请求>-->```执行结果:测试结果表明:多个拦截器是有执行的先后顺序的,这个顺序就是定义的先后顺序拦截器的preHandle方法:按照定义顺序顺序执行的拦截器的postHandle方法:按照定义顺序逆序执行的拦截器的preHandle方法:按照定义顺序顺逆序执行的***多个拦截器非正常情况下的工作流程**:1、一个拦截器的preHandle方法返回false的情况:2、所有拦截器的preHandle方法都返回true,但是中间有过程发生了异常:####3、小结#####3.1单拦截器的执行顺序*正常情况下会按照:preHandle--->目标方法--->postHnadle--->页面渲染--->afterCompetion执行*当preHandle返回false,就没有以后流程的事儿了当preHandler返回了true,但是中间过程发生异常,会直接结束以后的流程但是afterCompetion总会执行3.2多个拦截器的执行顺序正常情况会按照配置中定义的顺序顺序执行所有拦截器的preHandle方法,然后执行控制器中目标方法,之后按照定义顺序的逆序执行postHandle方法,然后渲染页面,最后按照定义的顺序的逆序执行afterComprtion方法有拦截器返回false在多个拦截器中只要有一个拦截器的preHandle方法返回了false,那么以后的流程都没有了,会直接回按照这些拦截器配置的定义顺序的逆序执行afterCompetion方法

    LoveIT 2019-08-11
    Spring MVC
  • SpringMVC对Ajax异步请求的支持

    SpringMVC对Ajax异步请求的支持

    1、Ajax异步请求概念1.1AJAX:AnsycJavascriptAndXml(异步请求)       异步是指基于Ajax的应用与服务器通信的方法。对于传统的Web应用,每次用户发送请求或向服务器请求获得新数据时,浏览器都会完全丢弃当前页面,而等待重新加载的页面。在服务器完全响应之前,用户浏览器将是一片空白,用户的动作必须中断。异步是指用户发送请求后,完全无须等待,请求在后台发送,不会阻塞用户的当前活动,用户无须等待第一次请求得到完全响应,就可以立即发送第二次请求。简单的说,异步请求不会刷新当前html页面。异步指的是服务器端响应数据的获取方式。同步:异步:#####1.2异步&同步的区别1.同步请求:>请求的过程:浏览器(当前的html页面会丢弃)--->http协议--->Web服务器(tomcat)响应的过程:Web服务器(tomcat)--->http协议-->返回一个新html页面.2.异步请求:>请求的过程:浏览器(当前的html页面不会丢弃)--->Ajax引擎(http协议)--->Web服务器(tomcat)响应的过程:Web服务器(tomcat)--->准备部分数据-->Ajax引擎(http协议)-->DOM编程.总而言之,异步请求只是局部刷新页面,同步请求会全部刷新当前的页面####2、jQuery框架的异步请求和处理1.$.ajax([settings])—jQuery核心处理异步请求的方法:语法:>$.ajax([settings])最简单的情况下,$.ajax()可以不带任何参数直接使用。具体语法格式都有哪些参数的参照:https://www.w3school.com.cn/jquery/ajax_ajax.asp2.$.post()$.post()方法通过HTTPPOST请求从服务器上请求数据。语法:>$.post(url,data,function(data,status){>//status(状态码):success、error>//data:响应数据>},dataType);必需的URL参数规定您希望请求的URL。可选的data参数规定连同请求发送的数据。可选的function参数是请求成功后所执行的函数名,其中data是响应的数据,status是状态码可选的dataType参数是服务器响应返回的数据3.$.get()$.get()方法通过HTTPGET请求从服务器上请求数据。>$.get(url,data,function(data,status){>//status(状态码):success、error>//data:响应数据>},dataType);必需的URL参数规定您希望请求的URL。可选的data参数规定连同请求发送的数据。可选的function参数是请求成功后所执行的函数名,其中data是响应的数据,status是状态码可选的dataType参数是服务器响应返回的数据####3、SpringMVC支持ajax异步请求和处理返回json数据#####3.1数据绑定@RequestBody/@ResponseBody***@RequestBody**    功能:用于将HttpServletRequest的getInputStream()的内容绑定到方法入参例如:>@RequestMapping(value="/hello")>publicStringhandleRequest(@RequestBodyStringbody){>//body参数就被请求参数自动绑定>}***@ResponseBody**    功能:被ResponseBody修饰的方法的返回值会被作为响应体>@RequestMapping(value="/hello")>@ResponseBody>publicUserhandleRequest(Ueseruser){>>returnUser;//返回值会被作为响应体,而且如果返回值是对象时SpringMVC会自动转换成JSON给页面>}#####3.2使用@RequestBody/@ResponseBody来支持Ajax可以使用@RequestBody来自动获取Ajax上传的数据,同时也可以使用@ResponseBody,把要返回的对象自动拼成JSON的格式返回。当然,需要加入几个jackson的包,这里加入了:jackson-core-2.9.3.jar、jackson-annotations-2.9.3.jar、jackson-databind-2.9.3.jar,Maven依赖如下:```xmlcom.fasterxml.jackson.corejackson-databind2.9.3com.fasterxml.jackson.corejackson-core2.9.3com.fasterxml.jackson.corejackson-annotations2.9.3```Controller```java/***ResponseBody:用于将ResponseBody方法的返回值作为响应体*RequestBody:用于将HttpServletRequest的getInputStream()内容绑定到入参**@paramusers*@return*/@ResponseBody@RequestMapping(value="/getAllUserByAJAX",produces="application/json;charset=UTF-8")publicListgetAllUserByAJAX(@ModelAttribute("users")Listusers){returnusers;}/***RequestBody:将请求体的数据绑定到入参**@paramuser*@return*/@ResponseBody@RequestMapping("/testRequestBody")publicUsertestRequestBody(@RequestBodyUseruser,Modelmodel){System.out.println("请求的数据:"+user);model.addAttribute("requestInfo",user);returnuser;}/***提前把全部信息查询好放在隐含模型中*@parammodel*/@ModelAttribute("users")publicvoidgetAll(Modelmodel){IUserServiceuserService=newIUserServiceImpl();Listlists=userService.getUser(null,null,null);model.addAttribute("users",lists);}```1.通过AJAX获得服务器数据的页面:```jspajax获取全部用户信息```测试结果2.通过AJAX向服务器发JSON数据,服务器返回JSON数据```jspTitleAJAX发送JSON数据给服务器```测试结果

    LoveIT 2019-08-10
    Spring MVC
  • SpringMVC异常处理

    SpringMVC异常处理

    1、重要的接口和类1.1HandlerExceptionResolver       他是SpringMVC“九大组件”之一,SpringMVC异常处理核心接口。该接口定义了1个解析异常的方法:1.2ExceptionHandlerExceptionResolver       继承自AbstractHandlerMethodExceptionResolver,该类主要处理Controller中用@ExceptionHandler注解定义的方法。该类是<annotation-driven/>配置中定义的HandlerExceptionResolver实现类之一,大多数异常处理都是由该类操作。 在Controller中使用@ExceptionHandler处理异常异常后的页面:测试结果:       像这样在Controller中借助@ExceptionHandler这个注解定义的异常处理方法只能在定义的那个Controller中使用,当Controller类十分多的时候,那么写异常处理方法就是个体力活了,因此SpringMVC就提供了@ControllerAdvice这个注解,它只能用在类上,而这个类中的异常处理方法都是全局范围,如下定义一个类专门集中处理异常:1.3DefaultHandlerExceptionResovler       HandlerExceptionResolver接口的默认实现之一 ,基本上是SpringMVC内部使用,用来处理Spring定义的各种标准异常,将其转化为相对应的HTTPStatusCode。其处理的异常类型有:1.4ResponseStatusExceptionResovler       用来支持@ResponseStatus的使用,处理使用了ResponseStatus注解的异常,根据注解的内容,返回相应的HTTPStatusCode和异常页面给客户端。如果Web应用程序中配置了ResponseStatusExceptionResolver,那么我们就可以使用ResponseStatus注解来注解我们自己编写的异常类,并在Controller中抛出该异常类,之后ResponseStatusExceptionResolver就会自动帮我们处理剩下的工作。<annotation-driven/>配置中定义的HandlerExceptionResolver实现类之一。 自定义一个异常另一个自定义异常在Controller中主动抛出这个异常看看效果:测试结果:ExceptionHandlerExceptionResolver、DefaultHandlerExceptionResolver和ResponseStatusExceptionResolver这三个类是<mvc:annotation-driver>配置后默认的3个实现类,他们的优先级是按书写的顺序由高到底。1.5SimpleMappingExceptionResovler提供了将异常映射为视图的能力,高度可定制化。其提供的能力有:1.根据异常的类型,将异常映射到视图;2.可以为不符合处理条件没有被处理的异常,指定一个默认的错误返回;3.处理异常时,记录log信息;4.指定需要添加到Modle中的Exception属性,从而在视图中展示该属性。

    LoveIT 2019-08-09
    Spring MVC
  • SpringMVC对资源国际化的支持

    SpringMVC对资源国际化的支持

    1、资源国际化开发1.1什么是资源国际化?       软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的、符合来访者阅读习惯的页面或数据。国际化(internationalization)又称为i18n(读法为i18n,据说是因为internationalization(国际化)这个单词从i到n之间有18个英文字母,i18n的名字由此而来)1.2国际化的基本规则       国际化信息”也称为“本地化信息”,一般需要两个条件才可以确定一个特定类型的本地化信息,它们分别是“语言类型”和“国家/地区的类型”。如中文本地化信息既有中国大陆地区的中文,又有中国台湾、中国香港地区的中文,还有新加坡地区的中文。Java通过java.util.Locale类表示一个本地化对象,它允许通过语言参数和国家/地区参数创建一个确定的本地化对象。       语言参数使用ISO标准语言代码表示,这些代码是由ISO-639标准定义的,每一种语言由两个小写字母表示。在许多网站上都可以找到这些代码的完整列表,下面的网址是提供了标准语言代码的信息:http://www.loc.gov/standards/iso639-2/php/English_list.php。       国家/地区参数也由标准的ISO国家/地区代码表示,这些代码是由ISO-3166标准定义的,每个国家/地区由两个大写字母表示。用户可以从以下网址查看ISO-3166的标准代码:http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html。下面是常用的国家/地区语言参数:2、资源国际化简单示例编写国际化资源文件:国际化资源文件就是用一种key-value的形式把要显示的信息的不同语言的翻译版本写到properties资源文件中。(1)英文的资源文件(2)简体中文的资源文件注意:一般情况下我们用*._zh_CN.properties表示中文资源文件,*.properties表示默认的资源文件。在springmvc配置文件中简单的配置一下,把我们的资源文件交给SpringMVC管理编写一个用户登录表单上面的代码中用到了JSTL中的fmt标签<fmt:message>,因此需要导入对应的jar包。测试结果我的浏览器默认就是中文,因此显示的就是中文的欢迎信息:在火狐浏览器中手动更改语言为英文英文环境下就显示的是英文信息:3、资源文件的编码问题       一般我们采用properties文件来保存资源文件。properties文件是以key-value的形式来保存文件的。login_zh_CN.properties中保存的是经过utf-8编码字后的ASCII字符,Unicode字符中不允许出现中文、日文等其他字符的文字。但是Unicode编码后的文字阅读起来比较困难,在IDEA中,可以在File->Settings->Editor->FileEncodings设置中勾选Transparentnative-to-asciiconversion,如下图,设置好后点击Apply,然后回到刚才编写的中文资源文件发现中文字符全部乱码了,这时可以在编辑器中直接重新输入中文。虽然我们输入的是中文,但是IDEA已经帮我们做了中文转码。4、在程序中获取国际化信息在程序中我们可以通过ResourceBundleMessageSource来获取资源文件的信息:执行结果:可以看到在不同对语言环境下使用了不同的资源文件。5、自定义区域信息解析器3个步骤:1、写一个类实现LocaleResolver接口或他的子接口或继承他的实现类,最主要是要实现它的resolveLocale方法2、在springmvc的配置文件中注册自定义的区域信息解析器3、启动测试(1)写一个类实现LocalResolver接口(2.1)在springmvc的配置文件中注册自定义的区域信息解析器注意:解析器的id必须是localeResolver,如果写错了就没有效果了。至于为啥非要这么写请参考SpringMVC源码中的DispatcherServlet这个类。(2.2)在页面中加入可以切换语言的链接(3)测试6、SessionLocaleResolver从SpringMVC的区域信息的继承图中我么看到了几个特别的区域信息解析器:1.AcceptHeaderLocaleResolver:它是SpringMVC默认装配的区域信息解析器,他会默认从accept-language请求头信息进行解析处理,通常这个头信息包含客户端操作信息的本地标示。它不支持通过链接的方式改变locale信息。2.FixedLocaleResolver:从字面意思就可以知道,这也是一个不支持通过链接的方式改变locale信息的一个解析器,它默认会从操作系统拿locale信息。3.SessionocaleResolver:从session中拿locale信息,允许设置区域信息。4.CookieLocaleResolver:从Cookie中拿locale信息,允许设置区域信息。下面我们借助SessionLocaleResolver来实现我们上面自定义区域信息解析器的功能:测试结果:7、使用LocaleChangeInterceptor通过配置LocaleChangeInterceptor,我们可以动态改变本地语言。它会检测请求中的参数并且改变地区信息。它调用LoacalResolver.setLocal()进行配置。既然是拦截器,要使用他就需要在springmvc配置文件中配置它,配置也很简单:然后在配合SessionLocaleResovler,实现动态的改变本地信息控制器层的代码瞬间变得极其简单,就一个跳转页面对返回语句测试结果:

    LoveIT 2019-08-08
    Spring MVC
  • SpringMVC 数据绑定&数据格式化&数据校验

    SpringMVC 数据绑定&数据格式化&数据校验

    1、数据绑定流程SpringMVC将ServletRequest对象及目标方法的入参实例传给WebDataBinderFactory实例,创建出DataBinder(数据绑定的核心部件)DataBinder调用转配在SpringMVC上下文中的ConversionService组件进行数据类型转换、数据格式化。并将servlet中的请求信息填充到入参对象中调用Validator组件对已经绑定好的请求消息的入参进行数据合法性校验,并最终生成数据绑定结果BindingResult对象SpringMVC抽取BindingResult中的入参对象和检验错误对象,将他们赋给处理方法的响应入参SpringMVC通过反射机制对目标方法进行解析,将请求消息绑定到处理方法的入参中。2、数据转换2.1ConversionServiceSpringMVC上下文中内建了很多转换器,可完成大多数Java类型的转换工作。Spring3.0添加了一个通用的类型转换模块,位于org.springframework.core.convert包中ConversionService接口是类型转换的核心接口ModifierandTypeMethodandDescriptionbooleancanConvert(ClasssourceType,ClasstargetType)判断是否可以将一个java类转换为另一个java类booleancanConvert(TypeDescriptorsourceType,TypeDescriptortargetType)需转换的类将以成员变量的方式出现在宿主类中,TypeDescriptor不但描述了需转换类的信息,还描述了从宿主类的上下文信息,如成员变量上的注解,成员是否是数组、集合或Map的方式呈现等Tconvert(Objectsource,ClasstargetType)将原类型对象转换为目标类型对象.Objectconvert(Objectsource,TypeDescriptorsourceType,TypeDescriptortargetType)将对象从原类型对象转换为目标类型对象,此时往往会用到所在宿主类的上下文信息2.2自定义类型转换器       Spring在org.springframework.core.convert.converter包中定义了3种类型转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到ConversionServiceFactroyBean中:-Converter<S,T>:将S类型对象转换为T类型对象-ConverterFactory:将相同系列多个Converter封装在一起.如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将String转换为Number及Number子类(Integer、Long、Double等)对象)可使用该转换器工厂类-GenericConverter:会根据源类对象及目标类对象所在的宿主类找那个的上下文信息进行类型转换       ConverstionServiceFactoryBean的converters属性可以接受Converter、ConverterFactory、GenericConverter或ConditionalGenericConverter接口的实现类,并把这些转换器的转换逻辑统一封装到一个ConverstionService实例对象中(GenericConversionService),Spring在Bean属性配置及SpringMVC请求消息绑定时将利用这个ConversionService实例完成类型转换工作。实际应用中常用的是Converter<S,T>,下面通过他实现一个自定义的类型转换器。关键步骤:1.实现Converter接口,他有两个泛型,S:是转换前的了类型,T:是转换后的类型,实现Converter接口的conver方法,在方法中定制对S类型如何转换换成T类型的规则2.在springmvc配置文件中将自定义的Converter配置在ConversionService中3.告诉SpringMVC使用我们自定义的类型转换器假设处理方法有一个User类型的入参,我们希望将一个格式化的请求字符串直接转为User对象,该字符串格式如(小明:男:软件工程:软工3306班:1134556)-编写自定义类型转换器在SpringMVC配置文件中将自定义的Converter方在IOC容器中交给Spring管理用<mvc:annotation-drivenconversion-service=”xxx”/>覆盖默认的类型转换器控制器:测试结果3、数据格式化       Spring使用转换器进行源类型对象到目标类型对象的转换,Spring的转换不提供输入及输出信息格式化工作,像日期、时间、数字、货币等数据都具有一定格式的,在不同的本地化环境中,同一类型的数还会相应地呈现不同的显示格式。如何从格式化的数据中获取真正的数据以完成数据绑定,并将处理完成的数据输出为格式化的数据,是spring格式化框架要解决的问题,Spring引入了一个新的格式化框架,这个框架位于org.springframework.format类包中,其中最重要的一个接口FormatterSpring的org.springframework.format.datetime包中提供了一个用于时间对象格式化的DateFormatter实现类,而org.springframework.format.number包中提供了3个用于数字对象格式化的实现类。-NumberFormatter:用于数字类型对象的格式化-CurrencyFormatter:用于货币类型对象的格式化-PercentFormatter:用于百分数数字类型对象的格式化示例:有一个员工类employee.java要使注解可以发挥作用还需要在注解中配置如下信息:       对属性对象的输入/输出进行格式化,从其本质上讲依然属于“类型转换”的范畴。Spring在格式化模块中定义了一个实现ConversionService接口的FormattingConversionService实现类,该实现类扩展了GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能。    FormattingConversionService拥有FormattingConversionServiceFactroyBean工厂类,后者用于在Spring上下文中构造前者FormattingConversionServiceFactroyBean内部已经注册了:NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性使用@NumberFormat注解JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型的属性使用@DateTimeFormat注解装配了FormattingConversionServiceFactroyBean后,就可以在SpringMVC入参绑定及模型数据输出时使用注解驱动了。<mvc:annotation-driven/>默认创建的ConversionService实例即为FormattingConversionServiceFactroyBean.4、数据校验       应用程序在执行业务逻辑前,必须通过数据校验保证接收到的输入数据是正确合法的,如代表生日的日期应该是一个过去的时间、工资的数值必须是一个整数等。一般情况下,应用程序的开发时分层的,不同层的代码由不同的开发人员负责。很多时候,同样的数据验证会出现在不同的层中,这样就会导致代码冗余,违反了DRY原则。为了避免这样的情况,最好将验证逻辑和响应的域模型进行绑定,将代码验证的逻辑集中起来管理。4.1JSR-303规范       JSR-303规范是Java为Bean数据合法校验锁提供的标准框架,它已经包含在JavaEE6.0中。JSR-303通过在Bean属性上标注类似于@NotNull、@Max等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。可以通过http://jcp.org/en/jsr/detail?id=303了解更多详细内容。JSR-303定义了一套可标注在成员变量、属性方法上的校验注解:JSR-303支持XML风格的和注解风格的验证,接下来我们首先看一下如何和Spring集成。1.导入jar包,此处使用Hibernate-validator实现(版本:hibernate-validator-6.0.17.Final-dist.zip),他的Maven依赖如下:在Spring配置中添加JSR-303验证框架支持通过ConfigurableWebBindingInitializer注册validator使用JSR-303验证框架注解为模型对象指定验证信息控制器通过在命令对象上注解@Valid来告诉SpringMVC此命令对象在绑定完毕后需要进行JSR-303验证,如果验证失败会将错误信息添加到Errors错误对象中。5.验证失败后回到填写表单的页面(/WEB-INF/jsp/pages/add.jsp)测试结果:4.2自定义国际化错误消息提示在上面的程序中有一个不好的地方,错误消息不是我们自定义的,而且都是英文的,下面我们来看看如何在通过国际化配置文件实现自定义国际化错误消息提示。使用System.out.println("错误码:"+fieldError.getCodes());可以得到错误的错误码,每种错误都定义了4中错误码,如下:他们从上到下所包含的范围由小到大,我们在写国际化配置文件的时候,每条配置的key必须是4个code中的一个code。`error_en_US.properties`error_zh_CN.properties在springmvc.xml文件中配置国际化资源:测试结果:

    LoveIT 2019-08-07
    Spring MVC
  • Spring MVC视图解析

    Spring MVC视图解析

          对于控制器的目标方法,无论其返回值是String、View、ModelMap或是ModelAndView,SpringMVC都会在内部将它们封装为一个ModelAndView对象进行返回。   SpringMVC借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是JSP也可是Excell、JFreeChart等各种表现形式的视图。1、视图(View)视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户。为了实现视图模型和具体实现技术的解耦,Spring在org.springframework.web.servlet包中定义了一个高度抽象的View接口。视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们不会有线程安全的问题。所谓视图是无状态的,是指对于每一个请求,都会创建一个View对象。 JSP是最常见的视图技术。2、视图解析器(ViewResolver)和视图(View)springMVC用于处理视图最重要的两个接口是ViewResolver和View。所以视图解析器的作用就是通过视图名(处理方法的返回值)生成View对象,所有的视图解析器都必须实现ViewResolver接口。  SpringMVC为逻辑视图名的解析提供了不同的策略,可以在SpringWEB上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。程序员可以选择一种视图解析器或混用多种视图解析器。可以通过order属性指定解析器的优先顺序,order越小优先级越高,SpringMVC会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则抛出ServletException异常。在项目中可以配置InternalResourceViewResolver作为视图解析器,在springmvc.xml中可以做如下配置:3、forward:和redirect:一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理,会经过视图解析器拼串,但如果返回的字符串中带forward:或redirect:前缀时,SpringMVC会对它们进行特殊处理:将forward:和redirect:当成指示符,其后的字符串作为URL来处理。示例如下:index.htmlhello.jsp,在当前项目的根路径下,和index.html同级ViewTestController.java测试结果:按F12打开开发者工具,可以看到确实两次重定向4、SpringMVC视图的解析流程(结合源码分析)源码中把任何返回返回值封装为ModelAndView的实现:这里以发出了一个GET请求为例:首先FrameworkServlet类会来处理这个GET请求doGetprocessRequestDispatcherServlet类doService方法doDispatch方法processDispatchResult方法,这个方法就是最终将数据交给页面的方法DispatcherServlet类的render方法并没有继承View接口的render,和View接口的render不是一回事,这个render仅仅是为了命名统一而起的一个名字resolveViewName方法,循环遍历你配置的视图解析器,viewResolvers是进过order排序的,这一步就是ViewResolvers是如何通过视图名产生View对象的关键InternalResourceViewResolver继承了AbstractCachingViewResolver,resolveViewName方法首先会判断有没有缓存,要是有缓存,它会先去缓存中通过viewName查找是否有View对象的存在,要是没有,它会通过viewName创建一个新的View对象,并将View对象存入缓存中,这样再次遇到同样的视图名的时候就可以直接在缓存中取出View对象了createView的实现细节:以下都是解析视图名的实现细节,感兴趣的可以看一下。父类AbstractCachingViewResolver类的createView实现细节:InternalResourceViewResolver继承了UrlBasedViewResolverUrlBasedViewResolver类中loadView方法的实现:UrlBasedViewResolver的buildView方法会获取一个View对象,这个对象会将视图以什么格式呈现给用户,例如如果是jsp显示呈现给用户的话,那这个view对象就是JstlView,默认的是JstlView。在这个方法中我们看到了getPrefix()+viewName+getSuffix()这样一段代码,这就是对视图路径的一个拼接了,getPrefix()方法获取前缀,也就是我们在配置文件中配置的<propertyname="prefix"value="/WEB-INF/PAGE/"/>的value中的值了,getSuffix()方法就是获取后缀值了,也就是我们在配置文件中配置的<propertyname="suffix"value=".jsp"/>的value中的值。这样就将将视图的物理路径找到了,并赋值到View的URL属性中去。就这样我们得到了一个View对象,这个视图的name就是逻辑视图名,因为当将View对象放在缓存的时候,我们可以通过逻辑视图名在缓存中找出View对象。我们在获取到View对象的时候,我们还要将View进行渲染,并呈现给用户。View是个接口,AbstractView实现了render方法:最后一行的renderMergedOutputModel方法由AbstractView的孙子类InternalResourceView实现InternalResourceView的renderMergedOutputModel方法帮我们获取到视图的物理路径,然后将这段路径传给RequestDispatcher对象,再调用RequestDispatcher的forward方法将页面呈现给用户,这样就走完了视图的解析了。最后一句话总结:视图解析器只是为了得到视图对象;视图对象才是真正的转发(将模型数据发在request域中数据)或重定向到页面(视图对象才是真正的渲染视图)。

    LoveIT 2019-08-06
    Spring MVC
  • Spring MVC从入门到精通—向页面带回响应数据的方法

    Spring MVC从入门到精通—向页面带回响应数据的方法

    1、SpringMVC提供了以下几种途径输出模型数据:ModelAndView:处理方法返回值类型为ModelAndView时,方法体即可通过该对象添加模型数据Map、Model以及ModelMap:入参为org.springframework.ui.Model、org.springframework.ui.ModelMap或Java.uti.Map时,处理方法返回时,Map中的数据会自动添加到模型中。@SessionAttributes:将模型中的某个属性暂存到HttpSession中,以便多个请求之间可以共享这个属性@ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中。当然,除了上面这些SpringMVC提供的几种方法,SpringMVC支持直接使用Servlet几个原生API来给页面传值:HttpServletRequestrequest、HttpservletResponseresponse、HttpSessionsession、InputStream/Reader对应request.getInputStream()、OutputStream/Writer对应response.getOutputStram()1.1Servlet原生API给页面传值页面测试代码:success.jsp测试结果:1.2Model、Map、ModelMap首先通过通过源码看看他们三者的关系:(1)ModelMap类(2)Model接口(3)ExtendModelMap类(4)BindingAwareModelMap类通过打开源码,我们不难总结出如下继承关系:接下来看看他们的用法:示例代码页面代码和上面样测试结果(1)页面的显示:(2)控制台打印的信息:从测试结果可以总结出:Model(SpringMVC接口)其中一个实现类是ExtendedModelMapModelMap是Map(JDK的接口)Map的一个实现类,并且ModelMap被ExtendedModelMapExtendedModelMap被BindingAwareModelMap继承Model、Map、ModelMap不论用哪个,最终工作的都是BindingAwareModelMap,而且从测试结果可以看到通过这三个设置的值,SpringMVC都把他们放在了request域中。1.3ModelAndView目标方法的返回值可以是ModelAndView类型,从名字上就可以看到,这是一个既包括模型(Model)又有视图(View)的一个类,然而事实也确实如此,他的model就可以理解为送给页面的数据,他的View可以理解为目标页面地址。但我们在他的model中放入值后,SpringMVC会把ModelAndView的model中数据放在request域对象中。示例代码测试结果:1.4使用@SessionAttributes注解       如果希望在多个请求之间共用某个模型属性数据,则可以在控制器类标注一个@SessionAttributes,SpringMVC会将模型中对应的属性暂存到HTTPSession中。@SessionAttributes除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中。1.@SessionAttributes(types=User.class)会将隐含模型中所有类型为User的属性添加到会话中2.@SessionAttributes(value={"user1","user2"})将名为user1和user2的模型属性添加到会话中3.@SessionAttributes(types={"User.class","Dept.class"})将模型中所有类型为User及Dept的属性添加到会话中4.@SessionAtributes(value={"user1","user2"},types={Dept.class})将名为user1和user2的模型属性添加到会话中,同时将所有类型为Dept的模型属性添加到会话中总之:当使用@SessionAttributes注解时就是告诉SpringMVC,当@SessionAttributes中的value值和BindingAwareModelMap的key一样时,那么在session也你也给我保存一份相同的值示例代码:页面代码对success.jsp中的sessionScope稍作修改:测试结果:1.5使用@ModelAttribute注解先来看看ModelAttribute的定义:通过@ModelAttribute的定义可以看到这个注解可以用在方法和参数上。在SpringMVC的Controller中使用@ModelAttribute时,应用情况包括下面几种:1、应用在方法上。2、应用在方法的参数上。3、应用在方法上,并且方法也使用了@RequestMapping示例代码:修改图书信息的页面:提交图书修改信息后的页面:如果没有使用@ModelAttribute,那么要更新数据信息,必须要全字段更新,即使你不需要更新的的字段,你也要填写,这显然不和常理,因为如果你不填写这个值,值就会为null。最主要是因为SpringMVC在封装提交的信息的时候只会new一个Book对象,里面的属性的值初始就是null。你没有填写也只会以null存到数据库。不使用@ModelAttribute进行非全字段更新测试结果:页面的显示:看看控制台的打印信息:可以看到果然不出预料的出问题了,更新信息后书名和作者的信息没了。这就相当于你更改了一下你的QQ密码,然后你的QQ号没了!这是很可怕的事情。使用@ModelAttribute解决问题:测试结果:页面展示的结果:控制台打印的信息:而且从控制台打印的信息来看,被@ModelAttribute标识的方法确实是在处理器方法之前执行了1.6@Modelattribute的原理废话不多说,直接看代码测试结果:最后总结为一张图:

    LoveIT 2019-08-04
    Spring MVC
  • Spring MVC从入门到精通—@RequestMapping注解详解

    Spring MVC从入门到精通—@RequestMapping注解详解

           在SpringMVC中@RequestMapping注解是一个十分强大的注解,SpringMVC使用@RequestMapping注解可以为控制器指定可以处理那些URL请求,在控制器的类上或类中的方法上均可以使用这个注解:在类上使用可以提供初步的映射信息。相当于一个根路径在方法上使用提供更进一步的细分映射信息。(1)这是一个只在方法上使用@RequestMapping注解的例子:(2)这是一个在类和方法同时使用@RequestMapping注解的例子:@Requestmapping的属性:属性作用value默认的属性就是value,他就是一个URL路径,可以在一个方法上或类上给多个value值method用来定义接收浏览器发来的何种请求。在Spring中,使用枚举类RequestMethod来封装了HTTP协议的所有请求方式。最基本的有GET、POST、DELETE、PUTparams表示请求参数,也就是追加在URL上的键值对,多个请求参数以&隔开headers该属性表示请求头,通过@RequestMapping中的headers属性,可以限制客户端发来的请求consumes规定请求头的Content-Typeproduces告诉浏览器返回的内容是什么,给响应头中加上Content-Type示例代码:method:限定请求方法parmars:限定参数parmars支持简单的表达式计算,例如:eg1:params={"username"},表示请求的路径中必须要有username这个关键字,如果没有就会报异常eg2:params={"!username"},表示请求的路径中不能有username这个关键字,如果有这个参数就会报异常eg2:params={"username","age=20","pwd"},表示请求的路径中必须要有username、age、pwd这三个关键字,并且age必须是20,如果没有或age的值不等就会报异常headers:限定请求头部示例一:测试结果:

    LoveIT 2019-08-03
    Spring MVC
  • Spring MVC从入门到精通—SpringMVC获取请求参数

    Spring MVC从入门到精通—SpringMVC获取请求参数

    第一种方式:方法的形参上给一个和请求参数同名的参数1.获得普通类型的参数值示例代码2.获得POJO类型的值示例代码新建Book.java以及Address.java两个POJOBook.javaAddress.java写一个简单的表单:index.html提交后的页面:book.jsp提供一个控制器:BookContorller.java测试结果:第二种方式:使用SpringMVC提供的注解1.使用@RequestParam获取参数@RequestParam的源码:示例代码:2.使用@RequestHeader获得请求的头部信息@RequestHeader和@ReuqestParma的实现方式如出一辙,使用方法也基本相同。示例代码1:使用RequestHeader注解获得浏览器的信息示例代码2:使用RequestHeader注解获取请求头部的Cookie信息3.使用@CookieValue获得请求头部的JSESSIONID示例代码:4.使用@RequestBody接收前端传给后端的JSON格式的数据       由于GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为)实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性。使用示例;

    LoveIT 2019-08-02
    Spring MVC
  • Spring MVC快速入门—Spring MVC体系结构及工作流程

    Spring MVC快速入门—Spring MVC体系结构及工作流程

    SpringMVC体系结构:SpringMVC是基于MVC软件架构实现的技术框架SpringMVC的执行流程具体步骤:第一步:客户端发起请求到前端控制器(DispatcherServlet)第二步:前端控制器请求HandlerMapping查找Handler(可以根据xml配置、注解进行查找)并返回一个Handler第三步:处理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映射策略第四步:前端控制器调用处理器适配器HandlerAdapter去执行Handler,处理器适配器HandlerAdapter将会根据适配的结果去执行Handler第五步:Handler执行完成给适配器返回ModelAndView第六步:处理器适配器向前端控制器返回ModelAndView(ModelAndView是springmvc框架的一个底层对象,包括Model和view)第七步:前端控制器请求视图解析器ViewResolver对ModelAndView进行解析(根据逻辑视图名解析成真正的视图(jsp)),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可。视图解析器最终向前端控制器返回View第八步:前端控制器进行视图渲染(视图渲染将模型数据(在ModelAndView对象中)填充到request域)第九步:前端控制器向用户响应结果第一个SpringMVC程序第一步:配置环境(新建Web工程+导包+配置Tomcat)在IDEA中新建MavenWeb工程,新建好后导包,使用SpringMVC所需要的基本的Maven依赖如下:第二步:配置DispatcherServlet通过DispatcherServlet这个名字可以大概了解到,这就是一个servlet,因此要想使一个sevlet起作用无非两种方法:一种是在servle类的头部加@WebServlet注解,二是在web.xml文件中配置<servlet>和servlet-mapping,第一中方法在这里显然不可行,人家源码肯定不能让改,那就需要在web.xml配置它,配置如下:接着在src/resources下新建springmvc.xml,配置springmvc:第三步:在webapp包下新建一个index.html以及hello.jsp,随便写点啥第四步:新建一个Controller,比如就叫HelloController测试结果:总结在做的时候的几细节1.SpringMVC下Web项目的运行流程:1.点击http://localhost/SpringMVC_01_war_exploded/后浏览器把请求给tomcat服务器2.服务器中由于配置了SpringMVC的Dispatcherservlet,他可以收到所有的请求3.Dispatcherservlet拿到请求后查看请求地址和@RequestMapping()中的那个地址(对应的方法)匹配4.前端控制器找到目标处理器和方法后,直接利用反射调用方法5.方法执行完成会有返回值(视图名),SpringMVC认为这就是方法执行完后要去的页面6.拿到方法返回值后,视图解析器拼接触页面地址7.拿到页面地址后,前段控制器就会使用转发的方式到目标页面2.关于springmvc.xml配置文件的配置:在web.xml配置前段控制器又这么一段配置,他的作用是告诉服务器去哪里加载对于前端控制器的配置文件:<init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param>如果我们没有写他会发生什么呢?会发生异常:一大堆异常信息最终就是告诉中我们你没有给配置文件的路径,那我(SpringMVC)就会在/WEB-INF目录下默认加载一个文件叫app-servlet.xml的文件,然而也没有找到,从而无法完成初始化。从这里我们知道,在配置前端控制器的时候也可以不写初始化参数,但是我们必须将springmvc配置文件放在WEB-INF目录下,并且文件的必须名字是:前端控制器的<servlet-name>app</servlet-name>+-servlet.xml,这是规定,不可随便来,你想节省一些操作就得按人家的要求来。

    LoveIT 2019-08-01
    Spring MVC
  • Spring从入门到精通—Spring事务详解

    Spring从入门到精通—Spring事务详解

    1、Spring事务核心接口Spring事务管理涉及的接口的联系如下:        Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。此接口的内容如下:2、基本事务属性的定义—TransactionDefinition        上面讲到的Spring的事务管理器核心接口PlatformTransactionManager通过getTransaction(TransactionDefinitiondefinition)方法来得到事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性。那么什么是事务属性呢?事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。事务属性包含了5个方面,如图所示:TransactionDefinition接口内容如下:2.1事物的传播行为        事务的传播行为(propagationbehavior)是指当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。Spring定义了七种传播行为:传播行为含义PROPAGATION_REQUIRED表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务PROPAGATION_SUPPORTS表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行PROPAGATION_MANDATORY表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常PROPAGATION_REQUIRED_NEW表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManagerPROPAGATION_NOT_SUPPORTED表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManagerPROPAGATION_NEVER表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常PROPAGATION_NESTED表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务2.2事物的隔离级别        事物的隔离级别(isolationlevel)定义了一个事务可能受其他并发事务影响的程度。在并发事务中,经常会引起以下问题:脏读(Dirtyreads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。不可重复读(Nonrepeatableread)——不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。幻读(Phantomread)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。        所以为了解决这些问题,引入了数据库的事务隔离级别的概念。Spring定义的事务隔离级别和数据库中定义的事务隔离级别是对应的,具体如下:隔离级别含义ISOLATION_DEFAULT使用后端数据库默认的隔离级别ISOLATION_READ_UNCOMMITTED最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读ISOLATION_READ_COMMITTED允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生ISOLATION_REPEATABLE_READ对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生ISOLATION_SERIALIZABLE最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的2.3事务只读        事务的第三个特性是它是否为只读事务。如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认为合适的优化措施。在TransactionDefinition中以boolean类型来表示该事务是否只读。2.4事务超时        为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。在TransactionDefinition中以int的值来表示超时时间,其单位是秒。2.5回滚规则        这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚3、事务状态——TransactionStatus        TransactionStatus接口用来记录事务的状态该接口定义了一组方法,用来获取或判断事务的相应状态信息.PlatformTransactionManager.getTransaction(…)方法返回一个TransactionStatus对象。返回的TransactionStatus对象可能代表一个新的或已经存在的事务(如果在当前调用堆栈有一个符合条件的事务)。TransactionStatus接口接口内容如下:

    LoveIT 2019-07-22
    Spring
  • Spring从入门到精通—Spring事务配置使用实例

    Spring从入门到精通—Spring事务配置使用实例

    1、Spring事务控制概述       Spring支持编程式事务管理和声明式事务管理两种数据库事务管理方式。编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager,通过硬编码的方式来管理数据库的事物。对于编程式事务管理,Spring推荐使用TransactionTemplate。声明式事务管理是建立在AOP(面向切面编程)之上的。其本质是对将要执行的SQL与语句进行拦截,然后在目标SQL开始之前创建或者加入一个事务,在执行完目标SQL之后根据执行情况提交或者回滚事务。声明式事务管理有两种常用的使用方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用。       显然声明式事务管理要优于编程式事务管理,这也正是Spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。       说了这么多,不如来点实际的,下面我们就来看看Spring推荐的声明式事物如何在我们的项目中使用。我将以注解和XML两种配置方式来一一为大家介绍。2、搭建实验环境首先新建一个Maven项目,导入需要的依赖:创建数据库和表:新建tx数据库,并在tx数据库中新建三张表account、book、book_stock。具体的数据库脚本如下:导入后应该是这样的三张表:3、基于Annotation的声明式事务管理配置和使用(1)首先配置数据源,这里使用的阿里的Druid数据连接池(2)数据库配置jdbc.properties如下:(3)配置JdbcTemplate,这里出于学习的目的先使用JdbcTemplate。(4)配置事物管理器(5)配置开启注解事物管理完整的ApplicationContext.xml配置文件如下:       完成上面的操作后,我们就可以在需要事物管理的地方使用@Transactional注解标注在类或方法上,以此告诉Spring这里需要事物管理。当作用于类上时,该类的所有public方法将都具有该类型的事务属性。另外,@Transactional注解应该只被应用到public方法上,这是由SpringAOP的本质决定的。如果你在protected、private或者默认可见性的方法上使用@Transactional注解,这将被忽略,也不会抛出任何异常。@Transactional注解的属性总结属性需要的参数的类型描述valueString指定使用的事务管理器(必须)propagationenum:Propagation事务传播行为设置(可选)isolationenum:Isolation事务隔离级别设置(可选)readOnlyboolean读写或只读事务,默认(false)读写timeoutint事务超时时间设置,单位:秒rollbackForClass[],必须继承自Throwable指定发生异常后哪些异常要回滚rollbackForClassNameString[],必须继承自Throwable指定发生异常后哪些异常要回滚的异常类名字数组noRollbackForClass[],必须继承自Throwable指定发生异常后哪些异常不回滚noRollbackForClassNameString[],必须继承自Throwable指定发生异常后哪些异常不回滚的异常类名字数组使用示例:DAO层,直接使用JdbcTemplate操作数据库,写3个方法分别用于:更新用户余额、更新图书库存、以及查询价格,具体如下:业务层,写一个结账的方法,使用@Transactional告诉Spring要帮我们控制事务4、基于XML的声明式事务管理配置和使用其他的步骤和使用注解一样,不同点的核心的在下面:测试:在src/main/test包下新建测试类TxTest.java测试

    LoveIT 2019-07-21
    Spring
  • Spring从入门到精通—Spring IOC高级依赖注入配置使用实例

    Spring从入门到精通—Spring IOC高级依赖注入配置使用实例

    1、环境与Profile    在开发中我们测试用一套数据库,开发用一套数据库,而且要将应用程序从一个环境迁移到另一个环境,Spring允许我们定义多套配置,可以配置声明应用哪套配置的Bean#####1.1Profile***Spring中的Profile是什么?**    Spring中的Profile功能其实早在Spring3.1的版本就已经出来,它可以理解为我们在Spring容器中所定义的Bean的逻辑组名称,只有当这些Profile被激活的时候,才会将Profile中所对应的Bean注册到Spring容器中。举个更具体的例子,我们以前所定义的Bean,当Spring容器一启动的时候,就会一股脑的全部加载这些信息完成对Bean的创建;而使用了Profile之后,它会将Bean的定义进行更细粒度的划分,将这些定义的Bean划分为几个不同的组,当Spring容器加载配置信息的时候,首先查找激活的Profile,然后只会去加载被激活的组中所定义的Bean信息,而不被激活的Profile中所定义的Bean定义信息是不会加载用于创建Bean的。***Profile有什么用?**    由于我们平时在开发中,通常会出现在开发的时候使用一个开发数据库,测试的时候使用一个测试的数据库,而实际部署的时候需要一个数据库。以前的做法是将这些信息写在一个配置文件中,当我把代码部署到测试的环境中,将配置文件改成测试环境;当测试完成,项目需要部署到现网了,又要将配置信息改成现网的,真的好烦。。。而使用了Profile之后,我们就可以分别定义3个配置文件,一个用于开发、一个用户测试、一个用户生产,其分别对应于3个Profile。当在实际运行的时候,只需给定一个参数来激活对应的Profile即可,那么容器就会只加载激活后的配置文件,这样就可以大大省去我们修改配置信息而带来的烦恼。下面我将以两个例子介绍一下目前常用的两种配置方式下如何配置Springprofile方式一:用xml配置profile方式二:用Annotation配置profile,这种方式配置和用xml配置是等价的在同一个类的不同方法上使用@Profile注解与@Bean一起使用配置出不同的profile实例激活profile        Spring在确定哪个profile处于激活状态时,需要依赖两个独立属性:sping.profiles.active和spring.profiles.default。Spring提供了@ActiveProfiles用来指定运行测试时要激活哪个profile,如果没有指定sping.profiles.active,会采用spring.profiles.default的默认值。测试代码:2、条件化Bean    Spring4引入了一个新的@Conditional注解,它可以用到带@Bean注解的方法上,如果条件计算结果为true,就会创建个Bean设置给@Conditional的类可以是任意实现了Condition接口的类型,如果matches()方法返回true,那么就会创建带有@Conditional注解的bean。若返回false,将不会创建这些bean。其中:ConditionContext:getRegistry():返回的BeanDefinitionRegistry检查Bean定义:getBeanFactory():返回ConfigurableListableBeanFactory检查Bean是否存在getEnvironments():返回Environment检查环境变量是否存在以及它的值是什么getResourceLoader():返回ResourceLoader所加载的瓷源getClassLoader():返回ClassLoder加载并检查是否存在AnnotatedTypeMetadata:可以让我们检查带@Bean注解的方法上还有什么其它注解,它也是一个接口举个栗子:写个条件类,实现Condition接口的matches方法,简单的判断一下当前的系统是不是Windows7的,如果是返回true,否则返回false测试代码:测试代码:程序运行结果:如果把“Windows7”改成“Windows10”就是条件Bean就会返回false,由于无法正常的注入就会出现以下的异常:

    LoveIT 2019-07-20
    Spring
  • Spring从入门到精通—基于Annotation配置和使用AOP

    Spring从入门到精通—基于Annotation配置和使用AOP

    1、AspectJ通知类型AOP联盟定义通知类型,AOP联盟的jar都是接口,必须要有实现类。AspectJ通知类型只定义类型名称,以及方法格式,总共有6种;1.brfore:前置通知(应用:各种校验)在方法执行前执行,如果通知抛出异常,将不会执行方法2.afterReturning:后置通知(应用:常规数据处理)方法正常返回后执行,如果方法中抛出异常,通知将无法执行3.around:环绕通知(应用:十分强大,可以做任何事)方法执行前后分别执行,可阻止方法执行4.afterThrowing:抛出异常通知(应用:包装异常信息)方法抛出异常后执行,如果方法没有抛出异常,无法执行5.after:最终通知(应用:清理现场)方法执行完毕后执行,无论方法中是否出现异常都会执行(类似于finally代码块)2、回顾基于XML配置AOP在上一篇笔记*Spring从入门到精通—SpringAOP的XML配置和使用*中讲了如何使用xml的方式配置和使用Spring的AOP,这里我们再回顾一下:首先编写一个service接口,模拟要处理的业务实现sevice接口:编写切面类:写一个方法before(),他是在目标方法执行需要增强的功能在XML中的配置如下:测试:测试结果:如下图所示,前置通知确实起作用了,在目标方法执行之前就执行了下面我们在来测测<aop:advisor>中的其他通知方式<aop:after-returning>    在切面类中增加方法:afterReturning(JoinPointjp,Objectobj),其中第一个参数是连接点,第二个参数是目标方法运行后的返回值。要获得返回返回值需要在配置中设置returning="obj",就是把这个第二个参数的名字放进去,Spring就会把返回值注入。配置新增的切面类方法:测试代码不变,测试结果如下:#####<aop:around>around具有before和after-returning两者的功能,这里就不在重复测试了。所以一般使用了around就不在使用brfore和after-returning<aop:after-throwing>、<aop:after>切面类中增加方法afterThrowing和after配置xml并在deleteUser方法中主动抛出异常:测试结果如下:如果去掉异常的测试结果如下:2、基于Annotation配置AOP既然使用注解配置,那就全部用注解,包括配置文件都用注解+Java类来实现*编写配置类Appconfig.java替代xml文件当然这段java代码可以用下面这段XML配置文件替代编写一个日志记录的切面类LoggerApsect.java在切面类中可以使用如下几个注解来定制一个切面:@Aspect:告诉Spring这是切面类@Brfore:前置通知@AfterRuning:返回后通知@Around:环绕通知,是@Brfore和@AfterRuning@After-Throwing:抛出异常后的通知,没有异常不会执行@After:最终通知,无论有没有异常一定会执行的@PointCut:定义切点具体用法如下:测试类如下:测试结果:现在去掉before、after-return以及在deleteUser中抛出一个异常:

    LoveIT 2019-07-19
    Spring
  • Spring从入门到精通—基于XML配置和使用AOP

    Spring从入门到精通—基于XML配置和使用AOP

    1、SpringAOP半自动编程核心步骤:1.创建一个接口以及它的实现类2.编写切面类,实现MethodInterceptor接口的invoke方法3.配置Spring的配置文件,xml文件中的配置重要是:【重要】  1).配置目标类的bean   2).配置切面类的bean   3).配置代理对象,其中代理对象中主要的配置如下'      a.配置接口      b.配置目标类      c.配置切面类      d.还可以用<propertyname="optimize"value="true"/>,指明使用cglib的代理对象1.1首先编写一个接口1.2编写接口的实现类:1.3编写一个切面类:让这个切面类实现MethodInvocation接口的invoke方法1.4在Spring的配置文件Application.xml中注册代理对象1.5测试:测试结果:2、SpringAOP全自动编程主要步骤:1).实现切面类2).在bean配置文件中吧切点和切面关联起来2.1实现一个切面类,继承MethodInterceptor接口实现它的invoke方法接着在Spring配置文件Application.xml中配置aop的schema文件,如下红框的配置:接着在配置文件中添加如下内容:对于配置全自动AOP代理的一点说明,如下图所示<aop:config>标签中重要的三种元素:切点:<aop:pointcut>、切面:<aop:aspect>、通知:<aop:advisor>其中通知:``又有以下5种:测试:测试结果:写在最后       通过实际的操作可以明显感受到第二种方式实现AOP是省事儿又简单的一种方式,然而第二种方式也是Spring中使用到AOP是常用到的一种配置方式。既然有全自动xml的配置方式,那么一定就会有对应对一套使用注解配置对方式。下一节就讲讲如何用注解配置使用SpringAOP

    LoveIT 2019-07-19
    Spring
  • Spring从入门到精通—AOP与AspectJ的关系?原生JDK和CGLib手动实现AOP?

    Spring从入门到精通—AOP与AspectJ的关系?原生JDK和CGLib手动实现AOP?

    1、AOP和AspectJ概述(SpringAOP是什么?AOP有什么用?)1.1AOP简介在软件行业,AOP为AspectOrientedprogramming的缩写,意为:面向切面编程,它是一种编程思想。AOP是OOP(面向对象编程)思想的延续。AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码的编写方式(例如性能监视、事务管理、安全检查、缓存、日志记录等)AOP的核心思想:基于代理思想,对目标对象创建代理对象,在不修改原目标对象的情况下,通过代理对象,调用增强功能代码,从而对原有业务方法的功能进行增强。1.2AOP的作用利用AOP可以对业务逻辑的各个部分进行分离,从而使得业务逻辑各个部分之间的耦合度降低,提高程序的可重用性,同时提高了开发效率。AOP采用横向抽取机制,取代了传统继承体系的纵向机制。AOP的经典应用场景:事务管理、性能监视、安全、缓存、日志.....1.3SpringAOP编程的两种方式SpringAOP使用纯Java代码实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码。AspectJ是一个基于Java的AOP框架,Spring2.0开始,SpringAOP引入AspectJ的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入。1.4AspectJ是什么?能做什么?AspectJ是一个易用且功能强大的AOP框架,并不是Spring的一部分。AspectJ的全称是EclipseAspectJ,其官网地址是:www.eclipse.org/aspectj/.AspectJ的特性如下:是一种基于Java平台的面向切面编程的语言兼容Java,可以无缝扩展易学易用,可以单独使用,也可以整合到其他框架中,单独使用AspectJ需要使用专门的编译器ajc1.5AspectJ和SpringAOP的区别?两者的区别如下:SpringAOP:基于动态代理来实现,默认如果使用接口,那么会用JDK提供动态代理实现,如果是方法则使用CGLib提供代理实现。SpringAOP需要依赖IOC容器来管理,并且只能用于Spring容器,使用纯Java代码实现。在性能上,由于SpringAOP是基于动态代理实现的,在容器启动时需要生成代理实例,在方法调用上也会增加桟的深度,使用SpringAOP的性能不如AspectJ好。AspectJ:AspectJ属于静态织入,通过修改代码来实现,一般AOP有三种织入的方式:编译期织入(Compile-timeweaving):类A中使用了AspectJ添加了一个属性,类B引用了它,这个场景就需要在编译时进行织入,否则没法编译类B。编译后织入(Post-compileweaving):当目标代码已经编译成.class字节码文件了的时候可以使用此方法来织入增强的代码类加载后织入(Load-timeweaving):在类加载的时候进行织入,要实现这个时期的织入一般有两种办法:自定义类加载器专门来进行织入;在JVM启动的时候指定AspectJ提供agent:-javaagent:xxx/xxx/aspectjweaver.jarAspectJ是AOP编程的完全解决方案,SpringAOP则只是致力于解决企业级开发中最普遍的AOP(方法织入)由于AspectJ在实际运行之前就完成了织入,因此由AspectJ生成的类是没有额外的运行时开销的。2、AOP的一些术语【了解】AOP(AspectOrientedProgramming)像大多数技术一样形成了自己的术语,而且这些术语比较难理解,不论是否理解都对编程影响不太大,但是最起码要清除有这样一个东西。连接点(Joinpoint)程序执行的某个特定位置:如类开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。一个类或一段程序代码拥有一些具有边界性质的特定点,这些点中的特定点就称为“连接点”。Spring仅支持方法的连接点,即仅能在方法调用前、方法调用后、方法抛出异常时以及方法调用前后这些程序执行点织入增强。切点(Pointcut)每个程序类都拥有多个连接点,如一个拥有两个方法的类,这两个方法都是连接点,即连接点是程序类中客观存在的事物。AOP通过“切点”定位特定的连接点。连接点相当于数据库中的记录,而切点相当于查询条件。切点和连接点不是一对一的关系,一个切点可以匹配多个连接点。通知或增强(Advice)增强是织入到目标类连接点上的一段程序代码,在Spring中,增强除用于描述一段程序代码外,还拥有另一个和连接点相关的信息,这便是执行点的方位。结合执行点方位信息和切点信息,我们就可以找到特定的连接点。目标对象(Target)增强逻辑的织入目标类。如果没有AOP,目标业务类需要自己实现所有逻辑,而在AOP的帮助下,目标业务类只实现那些非横切逻辑的程序逻辑,而性能监视和事务管理等这些横切逻辑则可以使用AOP动态织入到特定的连接点上.引介(Introduction)引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能,我们可以动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。织入(Weaving)织入是将增强添加对目标类具体连接点上的过程。AOP像一台织布机,将目标类、增强或引介通过AOP这台织布机天衣无缝地编织到一起。根据不同的实现技术,AOP有三种织入的方式:代理(Proxy)一个类被AOP织入增强后,就产出了一个结果类,它是融合了原类和增强逻辑的代理类。根据不同的代理方式,代理类既可能是和原类具有相同接口的类,也可能就是原类的子类,所以我们可以采用调用原类相同的方式调用代理类。切面(Aspect)切面由切点和增强(引介)组成,它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。对于Spring中的AOP术语,确实不好理解,为了帮助大家理解这些术语,我们想象一下这样的场景:        有2条高速公路可以通向北京,分别为A,B(相当于2个目标个业务Target(功能),每条高速公路上有3个服务站(相当于每个业务上的连接点(Joinpoint)有3个),在每条高速公路的第2个服务站需要测速(相当于一个切点(Pointcut),匹配了3个连接点),在第一条(A)进入服务站之前进行测速,在第二条(b)进入服务站之后测速(通知或增强Advice,其实也定义了调用测速功能进行测速,以及怎么测),每条高速路第2个服务站加入测速功能,这件事情相当于切面Aspect,它包含了测速功能的定义与切点的定义,将测速功能应用到服务站上,这个过程叫织入(Weaving)3、AOP的实现原理接下来是重点,我们来学习一下AOP的实现原理,并利用原理自己手动实现AOP。AOP底层采用代理机制进行实现,具体的实现方法有以下两种:1)接口+实现类:采用jdk的动态代理2)使用实现类:Spring采用了cglib字节码增强接下来我们就用这两个原理分别自己手动实现AOP。4、使用jdk的动态代理实现AOP实现思路:使用jdk中的Proxy类的newProxyInstance方法来获得一个代理对象,此后当使用某个对象的时候就使用这个代理对象而不直接去new对象,好了废话不多说,直接上代码步骤:1.写一个普通的接口以及这个接口的实现类2.写一个切面类(就是一个普通的java类,里面的方法写要增强的功能)3.上面的操作完成后,在工厂类(为了方便,当然也可以不写这个工厂类)中首先创建一个目标类对象(就是new一个业务类的对象),接着new一个切面类对象,使用动态代理把切面类中的增强功能织入到目标方法的前后,下面是示例代码:4.1首先写定义一个业务类接口:UserServiceBase.java4.2写一个业务接口的实现类:UserSeviceImpi.java4.3基于Java原生API写一个切面类:MyAspect.java4.4写一个工厂类,专门用于生产代理对象(可以没有)4.5测试:测试结果:5、使用Cglib实现CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。CGLIB作为一个开源项目,其代码托管在github,地址为:https://github.com/cglib/cglib下面是CGLib的组成结构:CGLIB底层使用了ASM(一个短小精悍的字节码操作框架)来操作字节码生成新的类。除了CGLIB库外,脚本语言(如Groovy何BeanShell)也使用ASM生成字节码。ASM使用类似SAX的解析器来实现高性能。CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了。接下来我们就用CGLib手动实现AOP5.1首先,需要导入Cglib所需的jar包,Maven依赖写法如下:5.2实现业务类还是需要一个业务类(这次不需要接口了)以及一个切面类,前面写过,这里就跳过了。5.3基于cglib的API实现切面类接着在刚才的工厂类中再写一个方法createUserService2(),步骤还是那几步,只不过这次是用cglib提供的api来写,具体如下:5.4测试:测试结果:可以看到结果和刚才用JDK动态代理的结果一样,但是这里要特别注意:jdk代理只能动态代理接口+实现类的形式;Cglib代理的优势是可以直接代理普通的类,但同时接口也可以

    LoveIT 2019-07-19
    Spring
  • Spring从入门到精通—IOC详解

    Spring从入门到精通—IOC详解

    1、什么是SpringIOC/DI控制反转(InversionofControl,IoC)所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。依赖注入(DependencyInjection,DI)在运行期,由外部容器动态地将依赖对象注入到组件中。换句话说,就是在运行时能Bean对象设置属性值2、bean标签一个bean标签代表一个spring容器中的java对象,可以在bean中经常使用的属性如下:1.id属性:起名称不能包含特殊符号根据id获得配置对象2.class属性:创建对象所在全路径3.name属性:功能和id一样,id不能包含特殊符号,name可以(基本不用,为了满足struts1遗留问题)4.scope属性:Bean的作用范围,scope常用的值有:-singleton和-prototype,分别表示单例和多例,如果没写默认就是单例3、Bean的3种实例化方式1.直接使用bean标签来实例化pojo,这中方法Spring默认调用的是这个pojo的无参构造器来实例化bean对象的首先创建一个EmailDaoImpl.java在ApplicationContext.xml文件中使用<beanid=“"class=""/>标签配置bean:经过这两步就配置好了一个bean,测试代码简单,就是调用了一下sent方法,下面是执行的结果:2.使用静态工厂实例化pojo首先新建一个静态工厂DaoFactory.java接着在xml中配置如下:3.使用实例化工厂实例化pojo首先新建一个实例化工厂:在xml文件中配置如下:4、Spring依赖注入的2种常用方式构造方法注入setter方法注入首先,新建学生实体类Student:1.使用构造方法注入在xml中配置如下,正常情况下只用指定参数的名字和参数的值:<constructor-argname=""value=""/>,name就是构造方法中的参数名,value即为这个参数的值下面是一个简单的配置示例:程序运行的结果:当构造方法出现命名冲突的时候,可以使用type属性指定参数的数据类型:程序运行的结果:2.setter方法注入,这种方法和实例化bean相同,都是用了property属性程寻运行的结果:5、SpEL(Spring表达式)        SpEL(SpringExpressionLanguage),即Spring表达式语言,是比JSP的EL更强大的一种表达式语言。为什么要总结SpEL,因为它可以在运行时查询和操作数据,尤其是数组列表型数据,因此可以缩减代码量,优化代码结构。个人认为很有用。        SpEL有三种用法,一种是在注解@Value中;一种是用于XML配置;最后一种是在代码块中使用Expression。下面说一下它最基础最重要的一种用法:xml配置法。(使用注解的方式的语法和xml方式的语法一样的,只是使用注解会更方便)5.1SpEL的基本语法语法格式``#{123}、#{'字符串'}:数字、字符串#{beanId}:对另一个bean的引用,类似ref属性#{beanId.propName}::操作数据#{beanId.toString()}:执行方法#{T(类).字段|方法}:静态方法或字段Spring表达式支持大多数的数学操作符、逻辑操作符、关系操作符。1.关系操作符包括:等于(==,eq),不等于(!=,ne),小于(le),大于(>,gt),大于等于(>=,ge)2.逻辑操作符包括:and,or,andnot(!)3.数学操作符包括:加(+),减(-),乘(*),除(/),取模(%),幂指数(^)。新建一个实体Customer```javapackagecom.xzy.bean;importjava.util.Arrays;importjava.util.List;importjava.util.Map;importjava.util.Set;publicclassCustomer{privateStringname;privateStringsex="男";privatedoublepi;@OverridepublicStringtoString(){return"Customer{"+"name='"+name+'\''+",sex='"+sex+'\''+",pi="+pi'}';}```在配置文件中如下配置:```xml```程序的执行结果如下:剩下的各种运算就不在这里试了,有兴趣的话可以自己尝试。####6、Spring集合类型注入    官方的一句话:`Inthe,,,andelements,yousetthepropertiesandargumentsoftheJavaCollectiontypesList,Set,Map,andProperties,respectively.`就是说,你可以用``、`set`、`map`、`props`来配置对应的Java集合类型:List、Set、Map、以及Array(数组),以及Properties也可以配置。举个栗子:在上例Customer实体类的基础上修改,分别增加List属性、Set属性、Map属性和数组属性一个,具体代码如下:```javapackagecom.xzy.bean;importjava.util.Arrays;importjava.util.List;importjava.util.Map;importjava.util.Set;publicclassCustomer{privateStringname;privateStringsex="男";privateListshopCar;//购物车privateSetprice;//价格privateMapgoods;//物品privateString[]address;//地址//省略getter、setter....@OverridepublicStringtoString(){return"Customer{"+"name='"+name+'\''+",sex='"+sex+'\''+",shopCar="+shopCar+",price="+price+",goods="+goods+",address="+Arrays.toString(address)+'}';}}```-使用``标签给List类型注入初始值:```xml元素-->书手机衣服电脑```-使用``标签给Set类型注入初始值:```xml元素-->"#{3.5*6}""#{2000*2}""#{100*6}""#{5000*1}"```-使用``标签给Map类型注入初始值:```xml元素,特别注意,使用来指定一条数据的key和value-->```-使用``标签给List类型注入初始值:```xml元素-->书手机衣服电脑```-使用``标签给List类型注入初始值:```xml元素-->西安北京南京广州```最后,对于customer的DI配置如下:```xml元素-->书手机衣服电脑元素-->"#{3.5*6}""#{2000*2}""#{100*6}""#{5000*1}"元素,特别注意,使用来指定一条数据的key和value-->元素-->西安北京南京广州```程序执行结果:####7、使用Annotation自动装配扫描要使用Anntation配置spring容器,首先需要在ApplicationContext.xml文件中配置如下信息:```xml```设置组件与bean命名>1.@Repository,@Service,and@Controller,@Component这四个Annotation功能相同都是声明一个bean组件,不同的是>@Repository声明Dao层>@Service声明Service层>@controller声明控制器层,>@Component就是一个普通的组件,例如对pojo实体可以使用他>都是用在类上的Annotation,说明让Spring实例化此类的对像,并放入spring容器中>2.@componet(“id”)其中id声明bean对像的名字举个栗子:新建Student.java```javapackagecom.xzy.bean;importorg.springframework.stereotype.Component;@Component//这一句就是告诉Spring这是个普通的组件publicclassStudent{privateintage;privateStringname;publicStudent(){System.out.println("1.实例化了bean。。。。。");}//省略getter、setter@OverridepublicStringtoString(){return"Student{"+"age="+age+",name='"+name+'\''+'}';}}```测试代码:```javapackagecom.xzy;importcom.xzy.bean.Student;importorg.apache.log4j.Logger;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.test.context.ContextConfiguration;importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner;/***UnittestforsimpleApp.*/@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(value={"/ApplicationContext.xml"})publicclassAppTest{privatestaticLoggerlog=Logger.getLogger(AppTest.class);@Autowired//自动注入,Spring会为我们自动从容器中找到student的对象然后注入这里的变量privateStudentstudent;@Testpublicvoidtest01(){System.out.println(student);}}```程序运行结果:@Repository,@Service,and@Controller新建StudentDao以及StudentDaoImpl```javaStudentDaopackagecom.xzy.Dao;importcom.xzy.bean.Student;publicinterfaceStudentDao{/***增加一个学生*@paramstu*@return*/publicvoidaddStudent(Studentstu);}```写一个StudentDaoImpi,模拟DAO层,并使用@Respositiry告诉Spring这是DAO层的组件```javaStudentDaoImplpackagecom.xzy.Dao.DaoImpi;importcom.xzy.Dao.StudentDao;importcom.xzy.bean.Student;importorg.springframework.stereotype.Repository;@RepositorypublicclassStudentDaoImpiimplementsStudentDao{publicStudentDaoImpl(){System.out.println("Repository层实例化");}@OverridepublicvoidaddStudent(Studentstu){System.out.print("3.Dao层处理数据:");System.out.println("向数据库发一条insert语句添加一个学生:"+stu.getName());}}```新建StudentService.java,模拟Service层,使用@Service注解告诉Spring这是一个Service的组件```javaStudentService.javapackagecom.xzy.Service;importcom.xzy.Dao.StudentDao;importcom.xzy.bean.Student;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;@ServicepublicclassStudentService{publicStudentService(){System.out.println("Service层实例化");}@AutowiredprivateStudentDaostuImp;publicvoidadd(Studentstu){System.out.println("2.service层收到控制层的数据后发给Dao层");stuImp.addStudent(stu);}}```新建StudentServlet.java,模拟控制器层,并使用@Controller注解告诉Spring这是控制器。```javaStudentServlet.javapackagecom.xzy.Servlet;importcom.xzy.Service.StudentService;importcom.xzy.bean.Student;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Controller;@ControllerpublicclassStudentServlet{publicStudentServlet(){System.out.println("Controller层实例化");}@AutowiredprivateStudentServicestuService;@AutowiredprivateStudentstu;publicvoidaddAction(){System.out.println("1.控制层发数据给sevice层");stu.setAge(23);stu.setName("狗子");stuService.add(stu);}}```最终的执行结果:可以看到这三个注解是由其存在的意义的,@Repository是告诉spring这是一个DAO层的类应该最先实例化(确实也应该如此),@Service层接着DAO层实例化完成后实例化,and@Controller层最后实例化,只用这样才可以确保不会空指针。设置组件扫描的base-packages>@Configuration@ComponentScan(“基包名”)PublicclassAppConfig{}>@Configuration@ComponentScan(basepackages=“基包名”)PublicclassAppConfig{}>@Configuration@ComponentScan(basepackages={“基包名”,”...”})PublicclassAppConfig{}>@Configuration@ComponentScan(basePackageClasses={App1Config.class,App2Config.class})PublicclassAppConfig{}以上App1Config与App2Config所在的包作为组件扫描的基础包8.3Annotation自动装配>1.@Autowired自动装配和JSR330’s@Inject对应,可用在构造方法、属性setter方法,有属性@Autowired(required=false)>@Primary用于声明bean的首先,用在多个bean,无法选择装配谁的情况可以指明使用哪个>2.@Required声明依赖必须提供用在setter方法>@RequiredpublicvoidsetMovieFinder(MovieFindermovieFinder){this.movieFinder=movieFinder;}>3.@Qualifiers注明要装配bean的标识,用于多个bean无法确定装配哪个的情况8.4处理自动装配的歧义Spring提供的自动装配是非常好用,可是用这么个问题:比如,一个接口有三个实现类,当要将接口类型自动装配置时,就出现不唯一的问题,Spring会抛出NoUniqueBeanDefinitionException。正如下面这种情况:写一个接口:```javapackagecom.xzy.utils;importorg.springframework.stereotype.Component;@ComponentpublicinterfaceReadData{publicvoidread();}```接口的三个实现类:```javapackagecom.xzy.utils;importorg.springframework.stereotype.Component;@ComponentpublicclassUSBReadimplementsReadData{@Overridepublicvoidread(){System.out.println("USB读取数据.....");}}``````javapackagecom.xzy.utils;importorg.springframework.stereotype.Component;@ComponentpublicclassSSDReadimplementsReadData{@Overridepublicvoidread(){System.out.println("SSD读取数据......");}}``````javapackagecom.xzy.utils;importorg.springframework.stereotype.Component;@ComponentpublicclassBlueReadimplementsReadData{@Overridepublicvoidread(){System.out.println("蓝牙读取数据.......");}}```这时如果让Spring给我们自动装配,他都懵逼了,因为这个接口有3个实现类,都可以装配,他不知道装配那个,如下图所示:此时如果直接运行就会发生如下异常:```accesslog2019-08-0121:49:51[ERROR]-[org.springframework.test.context.TestContextManager]CaughtexceptionwhileallowingTestExecutionListener[org.springframework.test.context.support.DependencyInjectionTestExecutionListener@685cb137]topreparetestinstance[com.xzy.AppTest@50a638b5]org.springframework.beans.factory.UnsatisfiedDependencyException:Errorcreatingbeanwithname'com.xzy.AppTest':Unsatisfieddependencyexpressedthroughfield'read';nestedexceptionisorg.springframework.beans.factory.NoUniqueBeanDefinitionException:Noqualifyingbeanoftype'com.xzy.utils.ReadData'available:expectedsinglematchingbeanbutfound3:blueRead,SSDRead,USBRead```解决办法解决方法1:在实现类的头上使用`@Primary`注解告诉Spring首选哪个装配,比如在USBRead类的头上加上@Primary:解决方法2:使用`@Qualifier`注解限定自动装配的Bean

    LoveIT 2019-07-18
    Spring
  • Spring从入门到精通-认识Spring框架

    Spring从入门到精通-认识Spring框架

    1.什么是Spring?Spring是一个J2EE框架,这个框架提供了对轻量级IoC(InversionofControl,控制反转)的良好支持,同时也提供了对AOP(AspectOrientedProgramming,面向切面编程)技术非常好的封装。相比其他框架,Spring框架的设计更加模块化,框架内的每个模块都能完成特定的工作,而且每个模块可以独立的运行,不会互相牵制。总结起来就是:Spring是一个支持IoC和AOP的轻量级开源框架,来源于RodJohnson在其著作《ExpertoneononeJ2EEdesignanddevelopment》中阐述的部分理念和原型衍生而来。Spring提倡以“最少侵入”的方式来管理应用中的代码,这意味着我们可以随时安装或者卸载Spring适用范围:任何Java应用Spring的根本使命:简化Java开发2.Spring中常用术语框架:是能完成一定功能的半成品。框架能够帮助我们完成的是:项目的整体架构、一些基础功能、规定了类和对象如何创建,如何协作等,当我们开发一个项目时,框架帮助我们完成了一部分功能,我们自己再完成一部分,那这个项目就完成了。非侵入式设计:从框架的角度可以理解为:无需继承框架提供的任何类这样我们在更换框架时,之前写过的代码几乎可以继续使用。轻量级和重量级:轻量级是相对于重量级而言的,轻量级一般就是非入侵性的、所依赖的东西非常少、资源占用非常少、部署简单等等,其实就是比较容易使用,而重量级正好相反。JavaBean:即符合JavaBean规范的Java类POJO:即PlainOldJavaObjects,简单老式Java对象它可以包含业务逻辑或持久化逻辑,但不担当任何特殊角色且不继承或不实现任何其它Java框架的类或接口。>注意:bean的各种名称——虽然Spring用bean或者JavaBean来表示应用组件,但并不意味着Spring组件必须遵循JavaBean规范,一个Spring组件可以是任意形式的POJO。容器:在日常生活中容器就是一种盛放东西的器具,从程序设计角度看就是装对象的的对象,因为存在放入、拿出等操作,所以容器还要管理对象的生命周期。3.使用Spring框架的好处是什么?轻量:Spring是轻量的,基本的版本大约2MB控制反转(IOC):Spring通过控制反转实现了松散耦合,对像们给出它们的依赖,而不是创建或查找依赖的对象们面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开容器:Spring包含并管理应用中对象的生命周期和配置MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品事务管理:Spring提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)异常处理:Spring提供方便的API把具体技术相关的异常(比如由JDBC,HibernateorJDO抛出的)转化为一致的unchecked异常4.Spring能帮我们做什么?Spring能帮我们根据配置文件创建及组装对象之间的依赖关系。Spring面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制。Spring能非常简单的帮我们管理数据库事务。Spring还提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,而且自己也提供了一套JDBC访问模板来方便数据库访问。Spring还提供与第三方Web(如Struts1/2、JSF)框架无缝集成,而且自己也提供了一套SpringMVC框架,来方便web层搭建。Spring能方便的与JavaEE(如JavaMail、任务调度)整合,与更多技术整合(比如缓存框架)。5.Spring由哪些模块组成?Spring的模块组成架构图大致如下图所示。Spring5框架体系结构示意图从上图可以看到,Spring框架主由5个模块组成,他们分别是:Spring核心容器、SpringAOP、数据访问\集成、Web、SpringTest。下面介绍这5个部分的作用。(1)Spring核心容器Spring框架的核心容器,它提供了Spring的基本功能。这个模块中最主要的一个组件是BeanFactory(IoC容器),它使用工厂模式来创建所需要的对象。同时BeanFactory使用IOC思想、通过读取XML文件的方式实例化对象,BeanFactory提供了组件生命周期的管理、组件的创建、装配、销毁等功能。Spring核心容器主要包含4个包:spring-core:依赖注入IoC与DI的最基本实现spring-beans:Bean工厂与bean的装配spring-context:扩展核心容器,提供了spring的上下文环境,给我们提供了非常有用的服务,比如:国际化、EMail、JNDI访问等。spring-expression:spring表达式语言SPEL它们的依赖关系#####(2)SpringAOPSpringAOP是对面向切面编程思想的实现,它使得Spring框架管理对象支持AOP。SpringAOP部分包含4个包:spring-aop:面向切面编程spring-aspects:集成AspectJspring-instrument:提供一些类级的工具支持和ClassLoader级的实现,用于服务器spring-instrument-tomcat:针对tomcat的instrument实现它们的依赖关系#####(3)数据访问/集成提供了对数据访问对象模式(DAO)、JDBC、事务控制、对现有ORM框架的集成的支持等功能。spring-jdbc:jdbc的支持spring-tx:事务控制spring-orm:对象关系映射,集成orm框架spring-oxm:对象xml映射spring-jms:java消息服务它们的依赖关系(4)Web;该层提供了创建Web应用程序的支持。web部分包含4个包:spring-web:提供了Servlet监听器的Context和Web应用的上下文。同时还集成了一些现有的Web框架。spring-webmvc:提供了一个构建Web应用的MVC实现。spring-webmvc-portlet:基于portlet的mvc实现spring-struts:与struts的集成,不推荐使用,spring4不再提供它们的依赖关系#####(5)TestSpring提供的一个类似junit的测试模块,用于测试Spring应用。test部分只有一个模块spring-test:spring测试,提供junit与mock测试功能它们的依赖关系

    LoveIT 2019-07-16
    Spring