第一章 简化Java开发
1. Spring用于简化Java开发的4个关键策略:
(1) 基于POJO的轻量级和最小侵入性编程
(2) 通过DI和AOP实现松耦合
(3) 基于切面和惯例进行声明式编程
(4) 通过切面和模板减少样板式代码
2. DI:松耦合
3. 通过接口而不是具体实现
4. Spring配置方式:
(1) XML ClassPathXmlApplicationContext
(2) Java AnnotationConfigApplicationContext
(3) Annotation
5. 在不改变所依赖类的情况下,修改依赖关系
6. DI能够让相互协作的组件保持松散耦合,AOP允许组件可重用
7. AOP能够使服务模块化,保持组件具有更高的内聚性。
8. AspectJ切点表达式语言
9. boilerplate code
10. 通过模板封装消除样板式代码
11. Spring负责创建、装配、配置、管理对象
12. Spring自带多个容器实现。bean工厂和应用上下文(org.springframework.context.ApplicationContext)
13. 应用上下文
(1) AnnotationConfigApplicatioinContext:从基于JAVA的配置类中加载Spring应用上下文
(2) AnnotaionConfigWebApplicationContext:从基于JAVA的配置类中加载Spring web应用上下文
(3) ClassPathXmlApplicationContext:从类路径下的XML配置文件中加载上下文定义
(4) FileSystemXmlApplicationContext:从文件系统的XML文件中加载上下文定义
(5) XmlWebApplicationContext:从web应用下的XML文件中加载上下文定义
第二章
装配bean
1. wiring:创建应用对象之间协作关系的行为
2. 配置Spring容器的三种方法:
(1) XML(least)
(2) JAVA
(3) 隐式的bean发现机制和自动装配
3. 自动化装配bean
(1) 自动扫描和自动装配 组件扫描默认不启动。@ComponentScan默认会扫描与配置类相同的包
(2) bean的ID默认为类名的第一个字母变小写
(3) 自动装配
(4) 自动装配中的歧义性
4. 通过JAVA装配bean
(1) 在显式配置时,JavaConfig是更好的方案。更为强大、类型安全且对重构友好。不应该包含任何业务逻辑。
(2) @bean:方法返回一个对象,该对象注册为Spring应用上下文中的bean。bean ID与方法的名字相同。Spring会拦截所有对对象的调用,确保直接返回该方法创建的bean。
(3) 在JavaConfig中装配bean:引用创建bean的方法
(4) 默认情况下,Spring中的bean都是单例的。
(5) 带有@bean注解的方法可以采用任何必要的Java功能来产生bean实例(构造器、Setter方法)。
5. 通过XML装配bean
(1) 创建XML配置规范
(2) 全限定类名
(3) bean ID
(4) <bean/>。Spring调用默认构造器来创建bean。
(5) Spring的XML配置并不能从编译期的类型检查中受益。
(6) XML中声明DI。构造器注入:<constructor-arg>;使用Spring3.0所引入的c-命名空间。
(7) bean引用。
<bean id=”” class=””>
<constructor-arg ref=””/>
</bean>
(8) bean引用。<bean id=”” class=”” c:cd-ref=””/>
(9) XML中不允许数字作为属性的第一个字符
(10) bean引用。
<bean id=”” class=””>
<constructor-arg value=””/>
</bean>
(11) c-命名空间。
<bean id=”” class=””
c:_title=””
c:_artist=””
/>
参数索引
<bean id=”” class=””
c_0=””
c_1=””
/>
(12) 装配集合。目前,使用c-命名空间的属性无法装配集合。
(13) 构造器注入;属性注入。对强依赖使用构造器注入。对可选性的依赖使用属性注入。
① 属性注入 setter
<bean id=”” class=””>
<property name=”” ref=””/>
</bean>
p-命名空间
<bean id=”” class=””
p:compactDisc-ref=””/>
2 literal
<bean id=”” class=””>
<property name=”” value=””/>
<property name=””>
<list>
<value></value>
</list>
</property>
</bean>
<bean id=”” class=””
p:title=””
p:artist=””>
<property name=””>
<list>
<value></value>
<value></value>
<value></value>
</list>
</property>
</bean>
(14) 不能使用p-命名空间来制定列表。
(15) Spring util-命名空间。
① <util:list id=””>
<value></value>
<value></value>
<value></value>
</util:list>
<bean id=”” class=””>
<property name=”” ref=””>
</bean>
<bean id=”” class=””
p:tracks-ref=””/>
6. 导入和混合配置
(1) 自动装配时,不在意要装配的bean来自哪里。会考虑Spring容器中所有的bean
(2) <import>元素只能导入其他的XML配置文件
<import resource=”cdplayer-config.xml” />
<bean class=”soundsystem.CDConfig” />
(3) 根配置。将装配类和XML文件组合起来。
第三章
高级装配
1. 跨环境部署:数据库配置、加密算法、与外部系统的集成等
2. 开发环境 EmbeddedDatabaseBuilder
生产环境 JNDI
QA环境 Commons DBCP连接池
3. Spring提供的解决方案并不需要重新构建。
4. 嵌入式数据库的DataSouce;生产环境
5. 在Spring3.1中,只能在类级别上使用@Profile注解
6. 没有指定profile的bean始终都会被创建。
7. 部署单元(WAR)
8. 激活profile
(1) spring.profiles.active(优先使用)
(2) spring.profiles.default
(3) 属性设置
① 作为DispatcherServlet的初始化参数
② 作为Web应用的上下文参数
③ 作为JNDI的条目
④ 作为环境变量
⑤ 作为JVM的系统属性
⑥ 在集成测试类上,使用@ActiveProfiles注解设置
(4) @ActiveProfiles(“dev”)
9. 条件化的bean
(1) @Conditional Spring4
(2) ConditionContext
① BeanDefinitionRegistry getRegistry()
② ConfigurableListableBeanFactory getBeanFactory()
③ Environment getEnvironment()
④ ResourceLoader getResourceLoader()
⑤ ClassLoader getClassLoader()
(3) AnnotatedTypeMetadata
10. 处理自动装配的歧义性
(1) 自动装配:构造器;setter方法;方法
(2) 将可选bean中的某一个设为首选(primary),或者使用qualifier
① 组件扫描:@Component @Primary
② JavaConfig:@Bean @Primary
(3) @Autowired @Qualifier(“bean ID”)
(4) 创建自定义的限定符
① 组件扫描 @Component @Qualifier(“”)
② JavaConfig: @Bean @Qualifier(“”)
(5) Java不允许在同一个条目上重复出现相同类型的多个注解。Java8允许出现重复的注解。@Repeatable
(6) 自定义的限定符注解。
(7) 相对于使用原始的@Qualifier并借助String类型来指定限定符,自定义的注解更为类型安全。
11. bean的作用域
(1) Spring应用上下文中所有bean都是以单例(singleton)的形式创建的。
(2) bean的作用域
① Singleton
② Prototype
③ Session
④ Request
(3) Singleton(默认)
(4) @Scope(ConfigurableBeanFactory.SCOPE_XX)
(5) 当StoreService调用ShoppingCart的方法时,代理会对其进行懒解析并将调用委托给会话作用域内真正的ShoppingCart bean。
(6) ProxyMode
① ScopeProxyMode:INTERFACES:表明这个代理要实现ShoppingCart接口,并调用代理
② ScopeProxyMode:TARGET_CLASS:表明要以生成目标类扩展的方式创建代理。必须使用CGLib来生成基于类的代理。
(7) 默认使用CGLib创建目标类的代理
<bean id=”” class=”” scope=”session”>
<aop:scoped-proxy/>
</bean>
要求生成基于接口的代理
<bean id=”” class=”” scope=”session”>
<aop:scoped-proxy proxy-target-class=”false”/>
</bean>
12. 运行时值注入
(1) 属性占位符
① 在Spring中,处理外部值的最简单方式是:声明属性源并通过Spring的Environment来检索属性。
② Environment.getProperty()
1) String getProperty(String key)
2) String getProperty(String key, String defaultValue)
3) T getProperty(String key, Class<T> type)
4) T getProperty(String key, Class<T> type, T defaultValue)
③ Environment.getRequiredProperty() 希望属性必须定义
④ Environment.containsProperty()
⑤ Environment.getPropertyAsClass() 将属性解析为类
⑥ 检查哪些profile处于激活状态
1) String[] getActiveProfiles()
2) String[] getDefaultProfiles()
3) boolean acceptsProfiles(String... profiles)
⑦ ${...}
1) PropertySourcesPlaceholderConfigurer
@Bean
public static PropertySourcesPlaceholderConfigurer palceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
⑧ <context:property-placeholder />
⑨ 解析外部属性能够将值得处理推迟到运行时,但其关注点在于根据名称解析来自于Spring Environment和属性源的属性。
(2) Spring表达式语言(SpEL)
① SpEL特性:使用bean的ID来应用bean;调用方法和访问对象的属性;对值进行算术、关系和逻辑运算;正则表达式匹配;集合操作
② #{...}
③ SpEL可以表示证书、浮点数、String以及Boolean
④ ?.
⑤ T() 访问类作用域的方法和常量
⑥ Elvis运算符:#{disc.title ?: ‘Rattle and Hum’}
⑦ 投影运算符 .![]
⑧ 查询运算符
1) .?[]
2) .^[] 查询第一个匹配项
3) .$[] 查询最后一个匹配项
⑨ public BlankDisc(
@Value(“#{(systemProperties[‘disc.title’])}”) String title,
@Value(“”) String artist) {
}
13. DI能够将组件及其协作的其他组件解耦;AOP能够将应用组件和跨多个组件的任务进行解耦
第四章
面向切面的Spring
1. 日志、安全、缓存、事务管理
2. Cross-cutting concern: 散布于应用中多处的功能
3. AOP:将横切关注点与业务逻辑相分离
4. AspectJ
5. AOP术语:
(1) Advice
(2) Join Point
(3) Pointcut
(4) Aspect
(5) Introduction
(6) Weaving
① 编译期:AspectJ
② 类加载期
③ 运行期:SpringAOP
6. AOP框架的基本功能:创建切点来定义切面所织入的连接点。
7. Spring提供了4中类型的AOP支持:
(1) 基于代理的经典SpringAOP
(2) 纯POJO切面
(3) @AspectJ注解驱动的切面
(4) 注入式AspectJ切面
8. SpringAOP构建在动态代理基础之上,Spring对AOP的支持局限于方法拦截
9. Spring通知是JAVA编写的
10. Spring在运行时通知对象,不需要特殊的编译器来织入SpringAOP的切面
(1) 代理类
11. Spring只支持方法级别的连接点。缺少对字段连接点的支持。不支持构造器连接点。
12. SpringAOP仅支持AspectJ的一个子集
13. &在XML中有特殊意义
14. 创建切面
(1) 声明式AOP
(2) 注解 AspectJ5
① @Aspect
② @Pointcut能够在一个@AspectJ切面内定义可重用的切点
@Pointcut(“execution(* concert.Performance.perform(..))”)
public void performance() {}
方法本身只是一个标识,供@Pointcut注解依附
@Before(“performance()”)
③ @EnableAspectJAutoProxy 启用自动代理功能
<context:component-scan base-package=””/>
<aop:aspectj-autoproxy />
④ AspectJ自动代理会为使用@Aspect的注解的bean创建一个代理,然后将调用委托给被代理的bean或被引入的实现。这个代理会围绕着所有该切面切点所匹配的bean。
⑤ Spring使用AspectJ注解来声明通知方法
1) @After
2) @AfterReturning
3) @AfterThrowing
4) @Before
5) @Around
⑥ 关注点
⑦ 处理通知中的参数
⑧ @Around
ProceedingJoinPoint
15. 通过切面为Spring bean添加新方法。借助AOP的引入功能。
16. @DeclareParents(value=”concert.Performace+”,
defaultImpl=DefaultEncoreable.class)
public static Encoreable encoreable;
17. 在XML中声明切面
(1) Spring的AOP配置元素能够以非侵入的方式声明切面
(2) <aop:config>/<aop:advisor>/<aop:after>/<aop:after-returning>/<aop:after-throwing>/<aop:around>/<aop:aspect>/<aop:pointcut>/<aop:declare-parents>/<aop:aspectj-autoproxy>
(3) 在XML中,”&”会被解析为实体的开始
(4) 通过切面引入新的功能
<aop:aspect>
<aop:declare-parents
type-matching=”concert.Performance+”
implement-interface=”concert.Encoreable”
default-impl=”concert.DefaultEncoreable”
/>
</aop:aspect>
第五章
Spring MVC起步
1. 配置DispatcherServlet
(1) DispatcherServlet加载包含Web组件的bean,如控制器、视图解析器、处理器映射;ContextLoaderListener加载应用中的其他bean,驱动应用后端的中间件及数据层组件。
2. 启用Spring MVC
(1) <mvc:annotation-driven>启动注解驱动的Spring MVC
(2) 基于Java:@EnbaleWebMVC
(3) 应用名称和领域类型
3. 编写基本的控制器
(1) 在Spring MVC中,控制器只是方法上添加了@RequestMapping注解的类
(2) Model实际上是一个Map,它会传递给视图,以便数据渲染到客户端。当视图是JSP时,模型数据会作为请求属性放到请求(request)之中。
4. 接受请求的输入
(1) 查询参数(Query parameter)
(2) 表单参数(Form parameter)
(3) 路径变量(Path variable)
5. 查询参数都是String类型的
6. 通过路径参数接受输入
(1) /spittles/show?spittle_id=1234 本质上是通过HTTP发起的RPC
(2) /spittles/1234
(3) 路径变量,占位符。{}
(4) 如果过方法的参数名与占位符的名称相同,可以去掉@PathVariable的value属性
@RequestMapping(value=”{spittleId}”, method=RequestMethod.GET)
public String spittle(
@PathVariable long spittleId, Model model
) {}
7. 处理表单
(1) <form>标签中没有设置action属性时,表单会提交到与展现时相同的URL路径上。
(2) 校验表单
① 限制输入域值的长度 Java校验API(JSPR-303) @Valid
② Errors参数要紧跟在带有@Valid注解的参数后面,@Valid注解所标注的就是要检验的参数。
第六章
渲染Web视图
1. 理解视图解析
2. 将控制器中请求处理的逻辑与视图中的渲染实现解耦时SpringMVC的一个重要特性。
3. Spring视图解析器
(1) Spring自带了13个视图解析器,能够将逻辑视图名转换为物理实现。
① BeanNameViewResolver
② ContentNegotiatingViewResolver
③ FreeMarkerViewResolver
④ InternalResourceViewResolver:将视图解析为Web应用的内部资源(一般为JSP)
⑤ JasperReportsViewResolver
⑥ ResourceBundleViewResolver:直接将逻辑视图名映射为特定的View接口实现
⑦ TitlesViewResolver
⑧ UrlBasedViewResolver:直接根据视图的名称解析视图,视图的名称会匹配一个物理试图的定义
⑨ VelocityLayoutViewResolver
⑩ VelocityViewResolver
⑪ XmlViewResolver
⑫ XsltViewResolver
⑬ Thymeleaf
(2) 在SpringMVC中使用JSP视图
① Spring提供了两种支持JSP视图的方式:
1) InternalResourceViewResolver
2) Spring提供了两个JSP标签库
② InternalResourceViewResolver:在视图名上添加前缀/后缀,进而确定一个Web应用中视图资源的物理途径。将逻辑视图名解析为JSP文件。
(3) JstlView
resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class)
(4) 使用Spring的JSP库
① 将表单绑定到模型上
1) <%@ taglib uri=”http://www.springframework.org/tags/form” prefix=”sf”%>
2) 14个相关的标签
② Spring通用标签库
<%@ taglib uri=”http://www.springframework.org/tags” prefix=”s” %>
③ 10个JSP标签
1) <s:bind>
2) <s:escapeBody>
3) <s:hasBindErrors>
4) <s:htmlEscape>
5) <s:message>
6) <s:nestedPath>
7) <s:theme>
8) <s:transform>
9) <s:url>
10) <s:eval>
④ <s:message>
⑤ <s:url>
1) 接受一个相对于Servlet上下文的URL,并在渲染的时候,预先添加上Servlet上下文路径。
2) 创建URL,提供模板
默认情况下,URL是在页面作用域内创建的。
<s:url href=”/spitter/spittr/register” var=”registerUrl” scope=”request”>
<s:param name=”max” value=”60”/>
<s:param name=”min” value=”20”/>
</s:url>
<a href=”${registerUrl}”>Register</a>
3) 创建带有路径(path)参数的URL
<s:url href=”/spitter/{username}” var=”spitterUrl”>
<s:param name=”username” value=”jbauer” />
</s:url>
如果<s:param>参数无法匹配href中的任何占位符,那么这个参数将会作为查询参数。
4) 添加参数
5) <s:url>还可以解决URL的转义需求。将渲染到的URL内容展现在Web页面上(而不是作为超链接)
<s:url value=”/spittles” htmlEscape=”true”>
<s:param name=”max” value=”60” />
</s:url>
在JS中使用URL
<s:url value=”/spittles” var=”spittlesJSUrl” javaScriptEscape=”true”>
<s:param name=”max” value=”60” />
</s:url>
⑥ <s:escapeBody> 渲染标签体内嵌的内容,并在必要时进行转义
<s:escapeBody htmlEscape=”true”>
<h1>Hello</h1>
</s:escapeBody>
<s:escapeBody javaScriptEscape=”true”>
<h1>Hello</h1>
</s:escapeBody>
与<s:url>不同,<s:escapeBody>只会渲染内容,不能将内容设置为变量。
4. 使用Apache Tiles视图定义布局
① 定义适用于所有页面的通用页面布局
② bean配置
1) TilesConfigurer:负责定位和加载Tile定义并协调生成Tiles
2) TilesViewResolver:将逻辑视图名称解析为Tile定义
5. Thymeleaf
(1) 标签库和JSP缺乏良好的格式。JSP规范与Servlet规范紧密耦合。
(2) Thymeleaf模板是原生的,不依赖于标签库。
(3) 配置Thymeleaf视图解析器
① ThymeleafViewResolver:将逻辑试图名称解析为Thymeleaf模板视图
② SpringTemplateEngine:处理模板并渲染结果
③ TemplateResolver:加载Thymeleaf模板
(4) Thymeleaf表达式 @{}
(5) 借助Thymeleaf实现表单绑定
第七章
Spring MVC的高级技术
1. Spring MVC配置的替代方案
(1) DispatcherServlet和ContextLoaderListener
(2) AbstractAnnotationConfigDispatcherServletInitializer
(3) WebApplicationInitializer注册Servlet/Filter/Listener
(4) CustomizeRegistration()
(5) 使用多种方式搭建Spring MVC
① 基于Java的Spring配置
1) <context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
② 在web.xml中声明DispatcherServlet
1) ContextLoaderListener和DispatcherServlet各自都会加载一个Spring应用上下文。
2) contextConfigLocation
2. 处理multipart形式的数据
(1) 配置multipart解析器
① MultipartResolver
1) CommonsMultipartResolver: 非Servlet3.0
2) StandardServletMultipartResolver:依赖于Servlet3.0对multipart请求的支持(优先)
② CommonsMultipartResolver
1) Spring内置了CommonsMultipartResolver
2) 默认情况下,路径为Servlet容器的临时目录。
3) setUploadTempDir(new FileSystemResource(“”))
4) 无法设定multipart请求整体的最大容量
③ StandardServletMultipartResolver
必须要在web.xml或Servlet初始化类中,将multipart的具体细节作为DispatcherServlet配置的一部分。强制设置临时文件路径。
1) Servlet初始化类
a. WebApplicationInitializer
b. AbstractAnnotationConfigDispatcherServletInitializer
customizeRegistration(Dynamic registration)
MultipartConfigElement参数:
临时路径的位置、上传文件的最大容量(字节)、整个multipart请求的最大容量(字节)
2) web.xml
<servlet>
<multipart-config>
<location/>
<max-file-size/>
<max-request-size/>
</multipart-config>
</servlet>
(2) 处理multipart请求
① @RequestPart
② 接受MultipartFile
③ 将文件保存到Amazon S3中
④ 以Part的形式接受上传的文件
1) javax.servlet.http.Part
2) 只有使用MultipartFile的时候,才需要MultipartResolver
3. 处理异常
(1) Servlet请求的输出都是一个Servlet响应。
(2) Spring提供了多种方式将异常转换为响应:
① 特定的Spring异常会自动映射为指定的HTTP状态码
② @ResponseStatus:将异常映射为HTTP状态码
③ @ExceptionHandler
@ExceptionHandler标注的方法能够处理同一个控制器类中所有处理器方法的异常
4. 为控制器添加通知
(1) Spring3.2
(2) 控制器通知@ControllerAdvice包含方法:
① @ExceptionHandler
② @InitBinder
③ @ModelAttribute
在带有@ControllerAdvice注解的类中,以上所有方法会运用到整个应用程序所有控制器中带有@RequestMapping注解的方法上。
5. 跨重定向请求传递数据
(1) 对于重定向来说,模型不能传递数据
(2) 使用URL模板以路径变量或查询参数的形式传递数据;通过flash属性发送数据
① 通过URL模板进行重定向
1) 当构建URL或SQL查询语句时,使用String连接时很危险的
2) 使用模板的方式定义重定向URL
② 使用flash属性 Spring3.1
1) session。需要负责在重定向后在会话中将其清理掉
2) flash属性会一直携带这些数据直到下一次请求
在重定向执行之前,所有的flash属性都会复制到session中。重定向后,存在会话中的flash属性会被取出到模型中。处理重定向的方法能从模型中访问数据。