SPRING IN ACTION 4整书内容包括有:
Spring基础,Springmvc基础,Spring处理和持久化数据,Spring应用程序与其他系统集成;总结中并不包含Spring web flow和Spring security,websocket和jmx相关部分
一、Spring基础
Spring 4初窥:
Spring的4种基本策略:
基于POJO的轻量级和最小侵入性编程
依赖注入和面向接口的松耦合
基于切面和惯例声明式编程
切面模板减少样板式代码
Spring应用中,对象由Spring容器创建和装配,并存在窗口之中
Spring容器可归为2种类型:bean工厂和应用上下文
应用上下文:
AnnotationConfigApplicationContext
AnnotationConfigWebApplicationContext
ClassPathXmlApplicationContext
FileSystemXmlApplicationContext
XmlWebApplicationContext
bean生命周期
1、Spring对bean进行实例化
2、Spring将值和bean引用注入bean对应属性中
3、如bean实现了BeanNameAware接口,Spring将bean的ID传递给setBeanName()方法
4、如bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
5、如bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext方法,将bean所在应用上下文的引用传入进来
6、如bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessBeforeInitialization()方法
7、如bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet()方法,类似,如bean使用init-methon声明初始方法,该方法会被调用
8、如bean实现BeanPostProcessor接口,Spring将调用它们的postProcessAfterInitialization()方法
9、bean装配完毕,直到应用上下文被销毁
10、如bean实现了DisposableBean接口,Spring将调用其destory()方法,如有指定destroy-method,该方法也会被调用
Spring模块:数据访问与集成,web与远程调用,面向切面编程,Instrumentation,Spring核心容器,测试
Bean装配:
1、在XML中显式装配
1、Bean声明
2、Bean注入
1、构造器注入:
1、<constructor-arg>按先后顺序依次装配
2、c-命名空间前缀
2、属性注入:
1、<property>
2、p-命名空间前缀
3、字面量注入:
<value>、<list>、<set>
2、在Java中进行显式配置
1、配置类@Configuration
2、@Bean
3、隐式的Bean发现机制和自动装配
Spring从2个角度实现自动化装配
组件扫描:在配置类@Configuration上使用@ComponentScan
@ConponentScan默认以配置类所在包作为基础包来扫描组件:basePackages={"asd", "qwe "}或basePackageClass={}
自动装配:@Autowired,直接用在属性,方法上
4、导入和混合配置
1、JavaConfig组件扫描和自动装配
创建根配置类,利用@Import,@ImportResource引入其他配置类或文件
@Configuration
@Import(AConfig.class)
@ImportResource("classpath:B.xml")
public class RootConfig{}
2、根配置中
<bean class="AConfig"/>
<import resource="B.xml">
高级装配
Profile
1、 在配置类中的@Bean中使用@Profile(‘XX’),没有指定Profile的Bean始终被创建
2、 XML中给beans标签设置profile属性
Profile激活(spring.profiles.active和spring.profiles.default)
1、 作为DispatcherServlet初始化参数
2、 Web应用上下文参数
3、 JDNI条目
4、 环境变量
5、 JVM系统属性
6、 测试中使用@ActiveProfiles
条件化装配:在@Bean类上使用@Conditional注解,提供实现Condition接口的类
Bean命名冲突
1、@Autowried会根据类型自动装配
2、使用@Primary设定首选
3、使用@Qualifier指定装配的bean
1、为bean设置自定义限定符@Qualifier,并在装配中使用
2、利用@Qualifier创建自定义注解使用
Bean作用域:单例,原型,会话,请求(在会话和请求作用域中,由于作用域不同,要使用代理模式注入)
运行时值注入
1、 属性占位符(${})
a) 为使用占位符,必须配置PropertySourcesPlaceholderConfigurer,形式:@Value(“${}”)
b) 在配置类中使用@PropertySource()为Environment引入资源
2、 Spring表达式(#{})
a) 使用bean id引用bean
b) 调用方法和访问对象属性
c) 对值进行算术,关系和逻辑运算
d) 正则表达式匹配
e) 集合操作
面向切面
切面:具体业务处理和切点的结合
切面:引入和织入
AOP:
1、 声明式AOP
a) XML中<aop:aspectj-autoproxy>
2、 基于注解的AOP
a) JavaConfig在配置类上使用@EnableAspectJAutoProxy
通知:@Before @After @AfterReturn @AfterThrowing @Around
环绕通知接收ProcceedingJoinPoint函数,调用process方法调用
切面方法如有参数传递,需要额外处理
@Aspect
Public class EncoreableIntroducer {
@DeclareParents(value=”concert.Performance+”哪种类型bean要引入该接口 defaultImpl=DefaultEncoreable.class为引入功能提供实现的bean)
Public static Encorable encorable;引入的接口
}
二、SpringMVC基础
搭建SpringMVC
继承AbstractAnnotationConfigDispatcherServletInitializer
重写getServletMappimgs方法,配置DispatcherServlet映射
重写getRootConfigClasses方法,对应ContextLoaderListener创建应用上下文bean
重写getServletConfigclasses方法,创建DispatcherServlet应用上下文bean
@Configguration
@EnableWebMVC
@ComponentScan(“package”)
Public class WebConfig extends WebMvcConfigurerAdapter{}
传递模型数据到视图
接受请求输入:
查询参数
在控制器方法的形参前使用@RequestParam(value=””, defaultValue=””)
路径变量
在@RequestMapping中映射路径添加占位符${xx}表示路径参数,控制器方法使用@PathVariable(‘xx’)
表单参数
表单校验表单数据对应的POJO添加@Valid Errors处理
校验注解:AssertFalse AssertTrue DecimalMax DecimalMin Digits Feture Max Min NotNull Null Past Pattern Size
视图渲染,SpringMVC提供了ViewResolver接口用于解析逻辑视图,该接口方法返回View实例完成具体渲染
JSP:InternalResourceViewResolver
@Bean
Public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
Resolver.setPrefix(“/WEB-INF/views/”);
Resolver.setsuffix(“.jsp”);
Resolver.setViewClass(org.springfamework.web.servlet.view.JstlView.class);
Return resolver;
}
配置Thymeleaf视图解析器
ThymeleafViewResolver:将逻辑视图名解析为Thymeleaf模板视图
SpringTemplateEngine:处理模板并渲染视图
TemplateResolver:加载Thymeleaf模板,模板引擎
重写AnnotationConfigDispatcherServletInitializer方法实现其他功能
重写customizeRegistration方法借助ServletRegistration.Dynamic对DispatcherServlet进行额外配置,如setMultipartConfig,setInitParameter,setLoadOnStartup
实现Spring的WebApplicationInitializer接口,创建新初始化器就可以添加其他组件
Spring提供多种方法异常转换为响应
1、 特定Spring异常会自动映射为指定的HTTP状态码
2、 异常上添加@responseStatus注解,从而将其映射一个状态码
3、 在方法上可以添加@ExceptionHandler注解
为控制器添加通知(@ControllerAdvice注解的类)
@ExceptionHandler
@InitBinder
@ModelAttribute
跨域重定向中使用flash保存信息
Flash属性保存会话中,然后放到模型中,因此能够在重定向中存活(model.addFlashAttribute)
三、Spring处理和持久化数据
Spring提供了非检查型异常
数据源连接池示例:
@Profile(“qa”)
@Bean
Public DataSource Data() {
BasicDataSource ds = new BasicDataSource();
Ds.setDriverClassName(“org.he.Driver”);
Ds.setUrl(“jdbc:h2:tcp://localhost/~/spitter”);
Ds.setUsername(“ab”);
Ds.setPassword(“”);
Ds.setInitialSize(5);
Ds.setMaxActive(10);
Return ds;
}
@Profile(“dev”)
@Bean
Public DataSource embeddedDataSource() {
Return new EmbeddedDatabas…().setType(EmbeddedDatabaseType.H2).addScript(“classpath:schema.sql”).addScript(“classpath:test-data.sql”).build();
}
Spring将数据访问过程分为固定和不固定2个不同类:模板,回调
模板管理过程中固定部分,而回调处理自定义数据访问代码(语句,参数绑定和整理结果集)
JdbcOperations是一个接口,定义了JdbcTemplate所有实现操作,其他类似
对象持久化JPA
基于JPA的应用程序 要使用EntityManagerFactory的实现类获取EntityManager实例
EntityManagerFactory:
1 LocalEntityManagerFactoryBean,在persistemce.xml中定义一个或多个持久化单元,持久化单元是同一个数据源下的一个或多个持久化类
2 LocalContainerEntityManagerFactoryBean,在Java配置中设置数据源,JpaVendorAdapter和扫描包
使用Spring会统一管理EntityManager
编写基于JPA的Respository(@Respository, @Transaction)
在Repository中注入EntityManagerFactory(@PesistenceUnti)或EntityManager(@PersistenceContext)处理数据持久化
配置PersistenceAnnotationBeanPostProccessorBean注册Respository
配置PersistenceExceptionTranslationPostProcessor转换异常
借助SpringData实现自动化JPA(JpaRepository, PagingAndSortingRepository, CrudRepository)
在配置类中添加@EnableJpaRespositories(basePackages=””)
SpringData方法名中包含有动作,主题,断言(有多少个限制条件就有多少属性参数)
自定义查询@Query(“sql”)
混合定义
当SpringData JPA为Respository接口生成实现时,会查找名字与接口相同,并且添加Impl后缀的一个类,将类中方法与其生成方法合并一起
使用Redis操作key-value数据
Redis连接工厂会生成Redis数据库服务器的连接:JedisConnectionFactory
Spring Data Redis提供了2个模板:RedisTemplate StringRedisTemplate
Redis连接工厂和Redis模板要在配置类中提供
当某个条目保存在Redis key-value时,key和value都会使用Redis序列化器进行序列化
缓存数据(caching)
Spring对缓存支持有2种方式:
注解驱动的缓存
1、 配置类中@EnableCaching,创建一个切面并触发Spring注解的切点
2、 配置缓存管理器
a) 配置Redis缓存管理器bean: RedisCacheManager
b) Redis连接工厂
c) RedisTemplate
3、 为方法添加注解以支持缓存(Cacheable CachePut CacheEvict Caching)
4、 自定义缓存key(默认缓存key基于方法参数)
#root.args/caches/target/targetClass/method/methodName/result/Argument
5、条件化缓存 unless condition
XML声明的缓存
<cache:annotation-driven>
<cache:advice>
<cache:caching>
<cache:cacheable>
<cache:cache-put>
<cache:cache-evit>
<aop:config>
<aop:advisor advice-ref=””
pointcut=”..”>
</acop:config>
<cache:advice id=””>
<cache:caching>
<cache:cacheable>
…
</cache:advice>
四、Spring应用程序和其他系统集成
使用远程服务
远程调用RPC(两者都是同步操作,阻塞调用代码的执行)
远程方法调用RMI
Hessian或Burlap
Http invoker
JAC-RPC或JAX-WS
在所有的模型中服务都作为Spring所管理的bean配置到应用中,这是通过一个代理工厂bean实现的
服务器端
RMI
RmiServiceExporter把POJO包装到服务适配器中,并把服务适配器绑定到RMI注册表中,从而将POJO转换为RMI服务
@Bean
Public RmiServiceExporter rmiExporter(SpitterService spitterService) {
RmiServiceExporter rmiExporter = new RmiServiceExporter();
rmiExporter.setServiceName(‘SpitterService’);
rmiExporter.setServiceInterface(SpitterService.class);
return rmiExporter;
}
默认使用本地机1099端口注册,使用registeryPort和registryHost属性可指定端口和主机
客户端
@Bean
Punblic RmiProxyFactoryBean spitterService() {
RmiProxyFactoryBean rmiProxy = new RmiProxyFactoryBean();
rmiProxy.setServiceUrl(“rmi://localhost/spitterService”);
rmiProxy.setServiceInterface(SpitterService.class);
return rmiProxy;
}
缺点:RMI端口协商,难穿透防火墙;基于JAVA;序列化机制要求JAVA版本一致
Hession(二进制,RMI也是基于二进制消息), Burlap(XML)基于HTTP
HessionServiceExporter是一个SpringMVC控制器,它可以接收Hessian请求,并把这些请求转换成对POJO调用,从而将POJO导出为一个Hessian服务
导出Hessian服务
@Bean
Public HessianServiceExporter hessianExportedSpitterService(SpitterService service){
HessianServiceExporter exporter = new HessianServiceExporter();
exporter.setService(service);
exporter.setServiceInterface(SpitterService.class);
return exporter;
}
配置Hessian控制器
1、 在web.xml中配置Spring的DispatcherServlet,并把应用部署为web应用
2、 在Spring配置文件中配置一个URL处理器,把Hession服务给URL分发给对应Hessian服务bean
导出Burlap服务类似,使用BurlapServiceExporter
访问Hessian/Burlap服务
@Bean
HessianProxyFactoryBean spitterService(){
HessianProxyFactoryBean proxy = new HessianProxyFactoryBean ();
Proxy.setServiceUrl(“??”);
Proxy.setServiceInterface(Spittervice.class);
Return proxy;
}
类似burlap使用BurlapProxyFactory
HTTP invoke基于HTTP远程调用,并使用Java序列化机制
HttpInvokerServiceExporter、HttpInvokerProxyFactoryBean
使用和发布web服务
@WebService web服务端点
@WebMethod 操作
对象生命周期不是由Spring管理,而对象又需要注入Spring管理bean时,使用SpringBeanAutoWiringSuport
使用SimpleJaxWsServiceServiceExporter导出服务
客户端代理JAX-WS服务 JaxWsPortProxyFactoryBean
@Bean
Public JaxWsPortProxyFactoryBean spitterService(){
JaxWsPortFactoryBean proxy = new JaxWsPortProxyFactoryBean();
Proxy.setServiceName(“spitterService”);
Proxy.setPortName(“spitterService”);
Proxy.setServiceInterface(SpitterService.class);
Proxy.setNamespaceUri(“http://spitter.com”);
Return proxy;
}
使用SpringMVC创建REST API
RPC是面向服务的,并关注于行为和动作,而REST面向资源,强调描述应用程序的事物和行为
REST是将资源的状态心最合适客户端或服务端的形式从对端转换到另一则
行为描述:
Post create
Get read
Put update
Delete delete
Spring REST支持
1、 控制器对HTTP方法支持
2、 参数化URL处理(@PathVariable)
3、 Spring视图和视图解析器处理返回结果
4、 ContentNegotiatingViewResolver选择最合适客户端的表述
5、 @ResponseBody,HttpMethodConverter替换基于视图的渲染方式
6、 @RequestBody,HttpMethodConverter传入参数处理
7、 RestTemplate
Spring提供2种方法将资源的Java表述形式转换为发送给客户端的表述方式
1、 内容协商(不建议使用)
a) ContentNegotiationViewResolve
i. 确定请求媒体类型
ii. 找到合适请求媒体类型的最佳视图
b) ContentNegotiatoinManager(注入ContentNegotiationViewResolve)
i. 默认内容类型
ii. 由请求参数指定内容类型
iii. 忽视请求的Accept头部信息
iv. 将请求扩展名映射为类型
v. JVF
2、 消息转换器
没有模型没有视图,只有控制器产生的数据,以及消息转换器转换数据后产生的资源表述(@ResponseBody)
@RequestMapping(method=RequestMethod.POST consumes=”application/json”)
Public @ResponseBody Spittle save(@RequestBody Spittle spittle) {
Return spittleRepository.save(spittle);
}
使用@RestController为控制器默认设置消息转换器
Spring处理异常
1、 使用@ResponseStatus注解指定状态码
2、 控制器方法可以返回ResponseEntity对象,该对象此时不要使用@ResponseBody标识
3、 异常处理器@ExceptionHandler
此外利用ResponseEntity可在响应头中设置头部信息
REST客户端:RestTemplate
Delete
getForEntity getForObject
postForEntity postForLocation postForObject
put
exchange 使用exchange方法可以设定请求头部
Spring消息
异常消息中2个主要概念,消息代理和目的地
消息代理确保消息被投递到指定目的地
目的地(队列,主题)从何取得,不关注谁取
JMS(Java消息服务) activemq
1、 创建连接工厂<amq:connectionFactory id=”connectionFactory” brokerURL=”tcp://localhost:61616”/>
2、 声明ActiveMQ消息目的地
<amq:queue id=”spittleQueue” physicalName=”spittle.alert.queue”/>
<amq:topic id=”spittleTopic” physicalName=”spittle.alert.topic”/>
3、 JmsTemplate
a) 使用convertAndSend在发送时,完成消息转换
b) 类似有receiveAndConvert
JmsTemplate接收信息是同步的,有MDP,消息驱动POJO
消息监听监控JMS目的地并等待消息到达,消息到达时,取出消息传给感兴趣的监听器
<jms:listener-container connection-factory=”connectionFactory”>
<jms:listener destination=”spitter.alert.queue” ref=”spittleHandler” method=”handlerSpittleAlert” />
</jms:listener-container>
使用基于消息的RPC
1、 JmsInvokerServiceExporter
2、 JmsInvokerProxyFactoryBean
服务器端
<jms:listener-container connection-factory=”connectionFactory”>
<jms:listener destination=”spitter.alert.queue” ref=”alertServiceExporter”/>
</jms:listener-container>
<bean id=”alertServiceExport” class=”….JmsInvokerServiceExporter” p:service-ref=”alertService” p:serviceInterface=”…”/>
客户端
<bean id=”alertService” class=”….JmsInvokerProxyFactoryBean” p:connectionFactory-ref=”connectiontory” p:queueName=”spittle.alert.queue” prop:serviceInterface=”…”/>
使用AMQP实现消息功能
消息产生者将消息发布到一个Exchange,Exchange会绑定到一个或多个队列去,将信息路由到队列上,信息的消费者从队列中提取数据并进行处理
AMQP Exchange(将routing key和队列bingding(与exchange))
Direct:
Topic:
Headers:
Fanout:
生产者将信息发送给Exchange,并带有一个routing key,消费者从队列中取消息
<connection-factory id=”connectionFactory”/>
在<admin>下
<queue>
<fanout-exchange>
<header-exchange>
<topic-exchange>
<direct-exchange>
<bidings>
<biding/>
<bidings>
RabbitTemplate
ConverAndSend(“exchange”, “key”, obj)
receiveAndConvert(“queue”)
目标可以设置POJO消息驱动
<jms:listener-container connection-factory=”connectionFactory”>
<jms:listener ref=”spittleHandler” method=”handlerSpittleAlert” queuenames=””/>
</jms:listener-container>
或可以queues=”,”
<queue id=”xx” name=”xx”/>