一本关于Spring 4.X较好的入门书
这篇书评可能有关键情节透露
第一章
DI(依赖注入)的方式:将依赖作为构造器参数传入。
Spring使用bean表示应用组件。创建应用组件之间协作的行为称为装配(wiring)。XML配置,java配置。 Spring通过applicationContext负责bean的管理。有多种应用上下文:classPathXmlApplicationContext加载xml配置。
AOP(面向切面编程):使软件关注点分离,提高内聚性。
一个业务核心模块,不应该含有日志,事务管理,安全控制这些基础设施的代码。它应该保持简洁。
将切面想象为覆盖于很多组件之上的一个外壳。可以在xml配置中通过<aop:config>定义。
Spring的JdbcTemplate可以避免传统的jdbc样板代码。
bean的生命周期。


第二章 装配bean
spring配置的三种机制: 1 xml显式配置 2 java显式配置 3 隐式bean发现和自动装配
组件扫描和自动装配: @component 表明为组件类,会创建bean,结合@componentScan启用组件扫描。<context:component-scan>为xml配置中的元素。
@component(“自定义bean命名”)。 @componentScan()中可以指定basePackages基础包。
@Autowired表示自动装配,可以用在方法上,表明spring去满足方法参数中声明的依赖。可以设置required为false,表明找不到该依赖bean也不会报错。
java代码装配: @configuration创建配置类。 @bean 声明bean,该对象要注册到spring应用上下文。默认bean名为方法名。spring创建的bean默认为单例的。通过方法参数注入其他bean依赖通常是良好的做法。
xml装配: <beans> id class。 <constructor-arg ref或者value>可以注入初始化bean。 强依赖建议使用构造器注入,可选依赖使用属性注入。 <bean>中的property定义的属性会通过setXXX方法注入到对应属性中。
使用混合配置来装配bean到spring上下文。
在java配置中引用配置: 1 @import 引用java配置 2 @importResource 引用xml配置
在xml配置中引用java配置: 利用<bean>元素可以将java配置导入到xml中。
第三章 高级装配
基于profile的bean创建: @profile(“dev”)可应用于类级别和方法级别。
<beans profile=“dev”>可用于xml配置不同的profile。
profile的激活依赖于spring.profiles.active和spring.profiles.default。 profiles为复数代表可同时激活多个profile。
可通过ActiveProfiles(“dev”)激活dev环境profile以测试。
条件化bean的创建:
@conditional(实现了condition接口的类),condition接口定义了matches方法,返回boolean值。 matches方法有两个参数,ConditionContext和AnnotatedTypeMetadata。
解决自动装配的歧义性: 1 将某个bean设为首选bean:@Primary 2 使用限定符 @Qualifier 可结合 @autowired 和 @qualifier(),或者 @bean 和 @qualifier() 自定义限定符。
bean的作用域:singleton,prototype,session,request
作用域代理能够延迟注入请求和会话作用域的bean。
运行时值注入: @propertySource和Environment 属性占位符:@PropertySourcesPlaceholderConfigurer,或者<context:property-placeholder>
SpEL语言。
第四章 Spring AOP
散布于应用中多处的功能称为横切关注点,例如日志,事务,安全,缓存。 将横切关注点与业务逻辑分离是AOP要解决的问题。

AOP行内术语:

通知 advice:切面的工作 连接点 join point:应用通知的时机。 切点 pointcut:应用通知的地方。 切面 aspect:通知+切点。 引入 introduction:向现有的类添加新方法或属性。 织入 weaving:将切面应用到目标对象并创建新代理。spring aop是运行期织入。
spring的切面由包裹目标对象的代理类来实现。 spring只支持方法级别的连接点。 spring借助AspectJ切点表达式定义切面。
@AspectJ + @EnableAspectJAutoProxy
环绕通知 around advice比较简洁。 切面能够为现有的方法增加新功能。 面向java注解的切面有一个弱点:需要有源码,才能为通知类添加注解。
第五章 构建Spring Web 应用
dispatcherServlet 为前端控制器, Spring应用上下文会位于servlet上下文中。AbstractAnnotationConfigDispatcherServletInitializer是传统web.xml的替代方案。
springMvc 接受查询参数,表单参数,路径变量作为客户端输入。
JSR-303定义了java校验API。 在对应表单处理的控制器方法中,添加方法参数 (@Valid formParameters,Errors errors)
第六章 渲染web视图
ViewResolver 和 View接口。 JSP:前缀,逻辑视图名,后缀。 Apache Tiles定义视图布局。 Thymeleaf三个bean:ThymeleafViewResolver,SpringTemplateEngine,TemplateResolver。 注意${}和*{}的区别。
第七章 Spring MVC高级技术
可设置 web.xml 使用基于java配置 二进制文件一般是byte数组,上传文件可使用MultipartFile。
处理异常: 1 将异常映射为http状态码。@ResponseStatus 2 编写异常处理handler方法(可以使代码更加简洁) 3 @ControllerAdvice 为控制器全局通知
跨重定向请求传递数据: 1 url路径变量或者查询参数 2 flash属性(保存于会话中)
第八章 使用 Spring Web Flow
struts:流程定义与实现紧耦合。 Spring web flow:流程定义和实现分离。 xml声明 web flow命名空间。 flowHandlerMapping定向请求,flowHandlerAdapter处理请求。
流程三要素:状态,转移,数据。 状态分为行为状态,视图状态和决策状态。
第九章 Spring Sercurity
Spring Security,是一种基于Spring AOP和Servlet规范中的Filter实现的安全框架,能够在Web请求级别和方法调用级别处理身份认证和授权。
Spring Security被分成了11个模块。
@EnableWebMvcSecurity注解配置了一个Spring MVC参数解析器(argument resolver),处理器方法能够通过带有@AuthenticationPrincipal注解的参数获得认证用户的principal(或username)。它还配置了一个bean,在使用Spring表单绑定标签库来定义表单时,这个bean会自动添加一个隐藏的跨站请求伪造(cross-site request forgery,CSRF)token输入域。
可通过重载WebSecurityConfigurerAdapter的三个configure()方法来配置Web安全性: · configure(WebSecurity) 通过重载,配置Spring Security的Filter链 · configure(HttpSecurity) 通过重载,配置如何通过拦截器保护请求 · configure(AuthenticationManagerBuilder) 通过重载,配置user-detail服务
1.基于内存的用户存储: inMemoryAuthentication() 2.基于数据库表进行认证: jdbcAuthentication() Spring Security的加密模块包括了三个实现:BCryptPasswordEncoder、NoOpPasswordEncoder和 StandardPasswordEncoder. 3.基于LDAP进行认证: ldapAuthentication()
基于LDAP进行认证的默认策略是进行绑定操作,直接通过LDAP服务器认证用户。另一种可选的方式是进行比对操作。
配置自定义的用户服务:提供一个自定义的UserDetailsService接口实现,并重写 loadUserByUsername() 方法;以及configure(AuthenticationManagerBuilder)方法,将自定义的XXUserService传入userDetailsService()。
Spring Security的SpEL表达式不局限于用户的权限进行访问,可以组合更复杂的验证逻辑。
可通过 requiresChannel() 强制启用 HTTPS。
CSRF防范:所有表单必须在一个“_csrf”域中提交token,而且这个token必须要与服务器端计算并存储的token一致。
HTTP Basic认证(HTTP Basic Authentication)会直接通过HTTP请求本身,对要访问应用程序的用户进行认证。这一点区别于表单页面验证。
Remember-me功能可设置过期时间,私钥。退出会发起对“/logout”的请求,会被Spring Security的LogoutFilter所处理。
使用Thymeleaf的Spring Security方言,需要在 SpringTemplateEngine bean 中包含SpringSecurityDialect。
第10章 通过Spring和JDBC征服数据库
配置数据源的方式: 1.JNDI: java:comp/env/(部署在Java EE应用服务器,例如Tomcat中) 2.数据源连接池: Apache Commons DBCP 或c3p0 或 hikariCP。(用于生产环境) 3.基于JDBC驱动的数据源:DriverManagerDataSource等。(用于本地开发测试) 4.嵌入式的数据源:H2。(用于本地开发测试)
可使用profile选择数据源:@Profile(“dev/qa/test/prod”)。
有多种使用数据库的方式包括传统JDBC、Spring JDBC模版、Hibernate、MyBatis以及JPA。 1.传统JDBC的缺点在于需要自身管理数据库资源和异常处理,造成代码失控。 2.Spring JDBC Template简化了传统JDBC对数据库资源的管理和异常处理。
第11章 使用对象-关系映射持久化数据
延迟加载:只获取直接对象的属性,子对象属性暂不获取。(单次查询很快,但是数据并不完整) 预先抓取:一次查询获取直接对象的属性,以及子对象的属性。(单次查询很慢,但是数据完整) 级联:更改/删除表A的记录的同时也更新/删除关联表的记录。(常见于外键约束)
Spring对ORM框架的支持提供了与这些框架的集成点以及一些附加的服务: · 支持集成Spring声明式事务; · 透明的异常处理; · 线程安全的、轻量级的模板类; · DAO支持类; · 资源管理。
获取Hibernate Session对象的标准方式是借助于Hibernate SessionFactory接口的实现类。
JPA定义了两种类型的实体管理器: 1.LocalEntityManagerFactoryBean生成应用程序管理类型的EntityManagerFactory; 2.LocalContainerEntityManagerFactoryBean生成容器管理类型的EntityManagerFactory。
编写Spring Data JPA Repository的关键在于要从一组接口中挑选一个进行扩展。 其中有JpaRepository、PagingAndSortingRepository和CrudRepository的18个方法。
此外,Spring Data JPA支持编写自定义的查询方法。Repository方法是由一个动词、一个可选的主题(Subject)、关键词By以及一个断言所组成。在findByUsername()样例中,动词是find,断言是Username,主题并没有指定,暗含的主题是Spitter。在断言中,会有一个或多个限制结果的条件。每个条件必须引用一个属性,并且还可以指定一种比较操作。
@Query可以添加自定义查询,但仅限于单个JPA查询。
当Spring Data JPA为Repository接口生成实现的时候,它还会查找名字与接口相同,并且添加了Impl后缀的一个类。 如果这个类存在的话,Spring Data JPA将把它的方法与Spring Data JPA所生成的方法合并在一起。对于SpitterRepository接口而言,要查找的类名为SpitterRepositoryImpl。
第12章 使用NoSQL数据库
Spring Data MongoDB提供了三种方式在Spring应用中使用MongoDB: 1.通过注解实现对象-文档映射; 2.使用MongoTemplate实现基于模板的数据库访问; 3.自动化的运行时Repository生成功能
为Java对象添加MongoDB持久化的注解,@Document和@Id注解类似于JPA的@Entity和@Id注解。 MongoOperations是MongoTemplate所实现的接口,在注入的时候使用接口可以保持松耦合。 - 内置方法 - 自定义方法 - @Query注解 - 混入。OrderRepositoryImpl前半部分与OrderRepository相同,只是添加了“Impl”后缀。当Spring Data MongoDB生成Repository实现时,会查找这个类并将其混合到自动生成的实现中。
使用@EnableNeo4jRepositories来配置Spring Data Neo4j,能够让Spring Data Neo4j自动生成Neo4j Repository实现。 Neo4j定义了两种类型的实体:节点(node)和关联关系(relationship)。可使用注解标注图实体。 常见注解: @NodeEntity 将Java类型声明为节点实体 @RelationshipEntity 将Java类型声明为关联关系实体 @StartNode 将某个属性声明为关联关系实体的开始节点 @EndNode 将某个属性声明为关联关系实体的结束节点 不论是节点实体还是关联关系实体,都必须要有一个图ID,而且其类型必须为Long。
createRelationshipBetween()是可以为两个节点创建关联关系。
OrderRepository -> GraphRepository -> Repository接口。因此,Spring Data Neo4j将会在运行时创建OrderRepository的实现。Neo4j要求图ID的类型为Long,因此在扩展GraphRepository的时候,不需要再去指定ID类型。
0.使用Neo4jTemplate: private Neo4jOperations neo4j;进行CRUD操作。 1.通过遵循命名约定来定义查询方法。 2.自定义查询,使用@Query注解。 3.混合自定义的Repository行为。 · 首先,定义一个中间接口OrderOperations,该接口包含findSiAOrders()方法的定义: · 然后,修改OrderRepository,让它扩展OrderOperations和GraphRepository: · 最后,自己创建OrderRepositoryImpl类,实现OrderOperations的findSiAOrders()方法。
Redis可认为是持久化的HashMap。 可通过JedisConnectionFactory 配置Redis连接。原始RedisConnection只能处理字节数组。 Spring Data Redis以模板的形式提供了较高等级的数据访问方案: · RedisTemplate · StringRedisTemplate(扩展自RedisTemplate) opsForValue(),opsForList(),opsForSet()等
Redis的序列化: RedisTemplate会使用JdkSerializationRedisSerializer,意味着key和value都会通过Java进行序列化。StringRedisTemplate会使用StringRedisSerializer。
第13章 缓存数据
配置类使用@EnableCaching启用声明式缓存。
1.使用Ehcache缓存: Spring提供了EhCacheManagerFactoryBean来生成EhCache的CacheManager。 EhCache的CacheManager要被注入到Spring的EhCacheCacheManager之中。 在配置中声明ehcache.xml的路径。
2.使用Redis缓存: 为了使用RedisCacheManager,需要RedisTemplate bean + RedisConnectionFactory实现类(如JedisConnectionFactory)的一个bean。
3.使用组合缓存: CompositeCacheManager通过一个或更多的缓存管理器来进行配置,它会迭代这些缓存管理器,以查找之前所缓存的值。
缓存注解: · @Cacheable Spring在调用方法之前,首先应该在缓存中查找方法的返回值。如果这个值能够找到,就会 返回缓存的值。否则的话,这个方法就会被调用,返回值会放到缓存之中 · @CachePut Spring应该将方法的返回值放到缓存中。在方法的调用前并不会检查缓存,方法始终都会被调用 · @CacheEvict 表明Spring应该在缓存中清除一个或多个条目 · @Caching 这是一个分组的注解,能够同时应用多个其他的缓存注解
@Cacheable 和 @CachePut 区别在于是否先检查缓存。 unless属性的表达式能够通过#result引用返回值。因为unless属性只有在缓存方法有返回值时才开始发挥作用。 而condition肩负着在方法上禁用缓存的任务,因此它不能等到方法返回时再确定是否该关闭缓存。 @CacheEvict 经常用于数据被删除或者被更新的方法上。
也可以使用XML文件配置缓存。
第14章 保护方法应用
Spring Security提供了三种安全注解: 1.Spring Security自带的@Secured注解; 2.JSR-250的@RolesAllowed注解; 3.表达式驱动的注解,包括@PreAuthorize、@PostAuthorize、@PreFilter和@PostFilter。
自定义许可计算器: hasPermission(targetObject,"delete"); 1.自定义一个类,来实现PermissionEvaluator。 2.重载GlobalMethodSecurityConfiguration的createExpressionHandler方法,设置第一步的实现类。
第15章 使用远程服务
本地方法调用是指同一个应用中的两个代码块之间的执行流交换。 Java API for XML Web Service(JAX-WS),将bean导出为基于SOAP的Web服务。
第16章 使用Spring MVC创建REST API
SOAP一般会关注行为和处理,REST关注的是要处理的数据。 Spring对REST的支持构建在Spring MVC之上。 HTTP方法会映射为CRUD动作。
1.ContentNegotiatingViewResolver是一个特殊的视图解析器,它考虑到了客户端所需要的内容类型。 ContentNegotiationManager + ContentNegotiatingViewResolver :协商资源表述。
2.消息转换(message conversion)能将控制器产生的数据转换为服务于客户端的表述形式。 JSON:MappingJacksonHttpMessageConverter HTML:Jaxb2RootElementHttpMessageConverter
@ResponseBody注解会将返回的对象作为资源发送给客户端,并将其转换为客户端可接受的表述形式。 · produces=application/json 属性表明只处理预期输出为JSON的请求,即只会处理Accept头部信息包含“application/json”的请求。 · consumes属性类似于produces,会关注请求的ContentType头部信息。只会处理POST请求,并且要求请求的ContentType头部信息为“application/json”。 @RestController代替@Controller的话,会为该控制器的所有处理方法应用消息转换功能。 @RestController 包含了@ResponseBody注解。
Spring提供了多种方式来处理非正常的情况: 1. 使用@ResponseStatus注解可以指定状态码; 2. 控制器方法可以返回ResponseEntity<?>对象,该对象能够包含更多响应相关的元数据; 3. 异常处理器能够应对错误场景。@ExceptionHandler注解能够用到控制器方法中,用来处理特定的异常。
RestTemplate定义了11个独立的操作。 XXForEntity可以获取响应对象和额外的Http头部信息,而XXForObject获取的只是响应对象。 如果想在发送给服务端的请求中设置头信息,可以使用RestTemplate的exchange()。
第17章 Spring消息
异步消息中有两个主要的概念:消息代理(message broker)和目的地(destination)。 不同的消息系统会提供不同的消息路由模式,有两种通用的目的地:队列(queue)和主题(topic)。每种类型都与特定的消息模型相关联,分别是点对点模型(队列)和发布/订阅模型(主题)。
· 点对点模型:消息发送者 -> 队列 -> 接收者(消息队列中的每一条消息只被投递给一个接收者) · 发布—订阅消息模型:消息发送者 -> 主题 -> 多个接收者。与队列不同的是,消息不再是只投递给一个接收者,而是主题的所有订阅者都会接收到此消息的副本。
JMSTemplate.convertAndSend() 方法内置 MessageConverter ,可以提供Java 数据类型到JSON,XML,String等的转换。
在AMQP中,通过引入处理信息路由的Exchange,消息的生产者 与消息队列之间实现了解耦。 生产者 -> Exchange -> 队列 -> 消费者 四种标准的AMQP Exchange:Direct、Topic、Headers、Fanout RabbitTemplate:sendAndConvert() receiveAndConvert()
第18章 使用WebSocket和STOMP实现消息功能
Spring 4.0为WebSocket通信提供了支持,包括: · 发送和接收消息的低层级API; · 发送和接收消息的高级API; · 用来发送消息的模板; · 支持SockJS,用来解决浏览器端、服务器以及代理不支持WebSocket的问题。
WebSocket最常见的应用场景是实现服务器和基于浏览器的应用之间的通信。相比直接实现WebSocketHandler,更为简单的方法是扩展AbstractWebSocketHandler,或者更为具体的XXWebSocketHandler。
后端:SockJS优先使用WebSocket,其次使用备用方案。通过withSockJS()方法开启。 前端:创建SockJS实例来代替WebSocket。因为SockJS尽可能地模拟了WebSocket。
直接使用WebSocket(或SockJS)类似于使用TCP套接字来编写Web应用。因为没有高层级的线路协议(wire protocol),因此需要我们定义应用之间所发送消息的语义,还需要确保连接的两端都能遵循这些语义。
STOMP在WebSocket之上提供了一个基于帧的线路格式(framebasedwire format)层,用来定义消息的语义。 1.@EnableWebSocketMessageBroker注解能够在WebSocket之上启用STOMP。 2.@MessageMapping注解能够在控制器中处理STOMP消息。 前端:通过调用Stomp.over(sock)创建STOMP客户端实例。
SimpMessagingTemplate能够在应用的任何地方发送消息。 @ExceptionHandler方法处异常。
第19章 使用Spring发送Email
Spring自带了一个MailSender的实现JavaMailSenderImpl,它会使用JavaMail API来发送Email。 借助JndiObjectFactoryBean,可以使用@Bean方法配置一个bean,从JNDI中查找MailSession。
SimpleMailMessage:纯文本内容的email createMimeMessage() + MimeMessageHelper: 丰富内容的email + 附件
建议使用模板生成Email:velocity、thymeleaf
第20章 使用JMX管理Spring Bean
Spring的MBeanExporter是将Spring Bean转变为MBean的关键。 1.通过名称暴露: · MethodNameBasedMBeanInfoAssembler可以通过名称get/setXX暴露方法。 · MethodExclusionMBeanInfoAssembler指定不需要暴露为MBean托管操作的方法名称列表。
2.通过接口定义MBean的操作和属性: · InterfaceBasedMBeanInfoAssembler
3.使用注解驱动MBean: · 在类级别使用@ManagedResource注解来标识这个bean应该被导出为MBean · 在get、set方法上使用@ManagedAttribute注解来进行标注
被动:等待外部应用对MBean进行查询以获得信息。 主动:当XX类事件发生时让MBean通知我们。
Spring通过NotificationPublisherAware接口提供了发送通知的支持,接收MBean通知的标准方法是实现javax.management.NotificationListener接口。
第21章 借助Spring Boot简化Spring开发
spring run *.groovy 可以同时运行多个groovy文件。