基于Spring的项目启动

web.xml加载spring, struts2

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:/applicationContext.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> 

<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>struts2</filter-name>
        <url-pattern>*.action</url-pattern>
</filter-mapping>

spring-farmework-4.2.4 整合 struts 2.3.24.1

  • @Results( { @Result(name = ActionSupport.SUCCESS, type = "json", params = { "root", "bannerResult", "excludeNullProperties", "true", "enableGZIP", "true" }) })

  • 最少所需依赖包

    • spring-core-4.2.4.RELEASE.jar
    • spring-web-4.2.4.RELEASE.jar
    • spring-context-4.2.4.RELEASE.jar
    • spring-beans-4.2.4.RELEASE.jar
    • spring-aop-4.2.4.RELEASE.jar
    • spring-expression-4.2.4.RELEASE.jar
    • commons-logging-1.2.jar
  • 整合struts 2.3.24.1

    • struts2-spring-plugin-2.3.24.1.jar
    • xwork-core-2.3.24.1.jar
    • struts2-core-2.3.24.1.jar
    • ognl-3.0.6.jar
    • javassist-3.11.0.GA.jar
    • commons-io-2.2.jar
    • commons-fileupload-1.3.1.jar
    • freemarker-2.3.22.jar
    • commons-lang3-3.2.jar
    • struts2-convention-plugin-2.3.24.1.jar Struts2 Annotation
    • asm-3.3.jar
    • struts2-json-plugin-2.3.24.1.jar Use json-default package
    • asm-commons-3.3.jar 需要但有时候不报错
    • struts2-config-browser-plugin-2.3.24.1.jar /config-browser/actionNames.action
  • applicationContext.xml

      <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
              xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
              xmlns:p="http://www.springframework.org/schema/p" xmlns:jee="http://www.springframework.org/schema/jee"
              xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
              xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
              http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
              http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
              http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
              http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring
              http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd">
          
              <context:annotation-config />
              <context:component-scan base-package="" />
              
              <task:annotation-driven /> 
          
              <import resource="classpath:/applicationContext_datasource.xml" />
          
              <ehcache:annotation-driven cache-manager="ehCacheManager" />
          
              <bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
          
              <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                  <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
                  <property name="ignoreResourceNotFound" value="true" />
                  <property name="locations">
                      <list>
                          <value>classpath:global.properties</value>
                          <value>classpath:query.properties</value>
                      </list>
                  </property>
              </bean>
      
      </beans>
    

Spring3.2.9 整合 Hibernate4.2.2

  • spring jar

    • spring-core-3.2.9.RELEASE.jar
    • spring-context-3.2.9.RELEASE.jar
    • spring-beans-3.2.9.RELEASE.jar
    • spring-orm-3.2.9.RELEASE.jar
    • spring-tx-3.2.9.RELEASE.jar
    • spring-jdbc-3.2.9.RELEASE.jar
    • spring-expression-3.2.9.RELEASE.jar
    • spring-aop-3.2.9.RELEASE.jar
  • hibernate jar

    • hibernate-core-4.2.2.Final.jar
    • hibernate-commons-annotations-4.0.2.Final.jar
    • hibernate-jpa-2.0-api-1.0.1.Final.jar
  • other jar

    • dom4j-1.6.1.jar
    • javassist-3.11.0.GA.jar
    • jboss-logging-3.1.0.GA.jar
    • aopalliance-1.0.jar
  • and maybe there are smoe other jars not know because they are in project already

  • applicationContext.xml

    1. dataSource

       <bean id="orcaleDS" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
           <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
           <property name="url" value="${xxx.url}"></property>
           <property name="username" value="${xxx.user}"></property>
           <property name="password" value="${xxx.DB.password}"></property>
       </bean>
      
    2. sessionFactory
      packagesToScan 需要spring3,2.5不支持

       <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
           <property name="dataSource" ref="orcaleDS" />
           <property name="hibernateProperties">
               <props>
                   <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
                   <prop key="hibernate.show_sql">false</prop>
                   <prop key="hibernate.format_sql">true</prop>
                   <prop key="javax.persistence.validation.mode">none</prop>
               </props>
           </property>
           <property name="packagesToScan">  
               <list>  
                   <value>com.xxx.pojo</value>  
               </list>  
           </property>  
       </bean>
      
    3. transactionManager
      @Transcation 需要annotation-driven才会生效

       <tx:annotation-driven/>
      
       <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
           <property name="sessionFactory" ref="sessionFactory">
           </property>
       </bean>
      

Junit4 and Mokito 与Spring整合

Junit4 和 Spring整合,用Spring IOC来管理Test Case,从而实现Test Case可利用Spring强大的事物管理等功能,实现Test Case对数据库操作回滚的功能,保持数据库的完整性。

Mockito能有效的mock那些测试类中的不可控的对象,比如Request和Response

注解的方式整合Spring : extends AbstractTransactionalJUnit4SpringContextTests

@ContextConfiguration(locations={
    "config/applicationContext-datasource-test.xml",
    "config/applicationContext-Freedom-test.xml",
    "classpath:applicationContext-grid.xml",
    "classpath:applicationContext-Freedom-legacy.xml"
})

实现事物回滚

@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)

Mockito

  • MockitoAnnotations.initMocks(this);
    • 使Mockito的注解生效,如果不用SpringTest跑test case,可以用@RunWith(MockitoJUnitRunner.class)代替
  • @Mock 和 @InjectMocks
    1. @mock为一个interface提供一个虚拟的实现,成为一个mock对象。
    2. @InjectMocks将本test类中的mock(或@mock)注入到被标注的对象中去,也就是说被标注的对象中需要使用标注了mock(或@mock)的对象。但是被标注的对象不是一个mock对象
  • @Spy:可用于实现部分mock
    • @Mock的对象只有在调用了Mockito.when(obj.doSomething()).thenCallRealMethod()的时候才会调用真实方法
    • 而@Spy注解的对象只有在调用了Mockito.when(obj.doSomething()).thenReturn(rtnValue)的时候才返回mock的值,但是真实方法还是会运行
    • 直接返回mock后的值而运行原方法:Mockito.doReturn(true).when(obj).doSomething();

mock Request和Response

protected HttpServletResponse getReponseWithPrintWriter() throws IOException {
    PrintWriter writer = org.mockito.Mockito.mock(PrintWriter.class);
    HttpServletResponse response = org.mockito.Mockito.mock(HttpServletResponse.class);
    org.mockito.Mockito.when(response.getWriter()).thenReturn(writer);
    return response;
}

protected HttpServletResponse getReponseWithOutputStream() throws IOException {
    ServletOutputStream outputStream = org.mockito.Mockito.mock(ServletOutputStream.class);
    HttpServletResponse response = org.mockito.Mockito.mock(HttpServletResponse.class);
    org.mockito.Mockito.when(response.getOutputStream()).thenReturn(outputStream);
    return response;
}    

protected HttpServletRequest getUserIdFromPortalWithMockedRequest() {
    HttpServletRequest request = org.mockito.Mockito.mock(HttpServletRequest.class);
    
    org.mockito.Mockito.when(request.getHeader("user")).thenReturn("sxq");
    return request;
}

其他

  • @Autowired注入Action
  • System.setProperty("SERVER_ENV", "DEV");设置环境变量

Spring AOP

  • Maven dependency

    1. aspectjrt.jar
    2. aspectjtools.jar
  • @Aspect [切面]

    1. 一个切面包括了代理类和目标类
    2. 无法被扫描,需要加上@Component,或者把@Aspect加入到扫描列表中
    3. Aspect 类上面除了@Aspect和@Component注解外,不能添加某些其他spring annonation,比如@RefreshScope,否则会造成@Around通知的point.proceed();方法也被代理,代理方法执行两次
  • @Pointcut [切入点]

    1. spring的所有切入点都是方法
    2. execution : 声明切入点为某些方法
      1. pointcut="(execution * com.*.service..*.fetch(..))"
      2. 第1个星 : 任意返回值类型
      3. 第2个星 : 任意包
      4. 第3个星 : 任意类
      5. .. : 第一个点表示目录分隔,第二个点表示类
    3. within : 声明切入点为某些类的所有方法
    4. @annotation : 声明切入点为某些annonation
      1. Annotation需要被扫描
    5. bean
      1. spring bean的名字
  • Advice [通知]: 代理方法

    1. @Before/@After
    2. @AfterReturning
      1. returnning="result" : 定义返回值为参数
    3. @AfterThrowing
      1. throwing="e" : 定义异常为参数
    4. @Around
      1. this="thisBean" : 定义代理类为参数,并且也起到声明切入点的作用
      2. target="targetBean" : 定义目标类为参数,就是被代理类,并且也起到声明切入点的作用
      3. args="(arg0,arg1)" : 定义参数,并且也起到声明切入点的作用
    5. @Orderd(1)
      1. 多个通知的顺序,默认0
  • 引入(Introduction)

    1. @DeclareParents :将代理方法实现某个接口

Spring Data JPA

Created and LastUpdated

  • @CreatedDate
  • @LastModifiedDate
  • @EnableJpaAuditing

Spring JPA 乐观锁

  • @Version
  • 必须是javax.persistence包下的
  • 数据类型是Long, Postgresql里是bigint
  • 不支持Update操作,只能save entity

去除save方法的select

  • select的作用
    1. 用于判断是否已经存在唯一约束,如果存在update,否则执行inster
    2. 用于JPA乐观锁 去除后自己判断乐观锁,单需要与update做成一个事务从而增加性能
  • 去除select
    1. class InboundRequest : Persistable
    2. override fun getId(): String? = inboundRequestId
    3. override fun isNew(): Boolean = true

其他

  1. 对JPA规范的封装,可以使用Hibernate的JPA实现,还可以切换到其他JPA实现
  2. public interface BondLevelsLiveRepository extends JpaRepository < BondLevelsLivePojo, BondLevelsLivePojoId >
  3. @Modifying : 完成修改操作(注意:不支持新增)
  4. @Query("delete from BondLevelsLivePojo pojo where pojo.lastUpdated < :date")
  5. void deleteStaleEntities(@Param("date") Date date);
  6. 在不同package下的repo,entity
    1. @EnableJpaRepositories(basePackages = ["org.springframework.statemachine.data.jpa"])
    2. @EntityScan(basePackages = ["org.springframework.statemachine.data.jpa"])

Spring Scheduler

  • @Scheduled与@Async合用的时候,不管前一个任务又没有完成,都会再起一个线程开始新的任务

  • @Scheduled默认单线程,可以通过设置线程池的个数来达到多现成的需求

      @Configuration
      public class SchedulerConfiguration implements SchedulingConfigurer {
          @Override
          public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
              ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
              taskScheduler.setPoolSize(20);
              taskScheduler.initialize();
              taskRegistrar.setTaskScheduler(taskScheduler);
          }
      }
    

Spring Cache

Getting Start

Spring MVC

常用Annonation

  • @RestController或者使用@Controller+@ResponseBody
  • @RequestMapping(value = "/springboot/webapi/price/get", method = RequestMethod.GET)
    1. PostMapping/GetMapping
    2. consumes: 限制接受请求的数据类型(Content-Type),MediaType
    3. produces: 限制返回的数据类型(accept)
  • @PathVariable
    1. 一般把key放在请求的path里{key}
      @RequestParam(required=false) String ccy
      @ModelAttribute
    2. 默认,可以忽略不写
    3. 自动寻找path/param里的参数
      @ResponseStatus
    4. 定义返回的状态码
      @ControllerAdvice
    5. @ExceptionHandler: 相关的Controller的特定Exception会被拦截,又切面同一处理
  • ModelMap可以用于返回多个stiring

9种Http Method

  • GET : 获取
  • POST : 添加
  • PUT/PATCH : 修改/部分修改
  • DELETE : 删除
  • OPTIONS : 获取可用的协议有哪些
  • HEAD : 只获取head
  • CONNECT : 维护一次心跳
  • TRACE : 跟踪

Reactive 非阻塞式编程

  • Spring MVC 使用java nio实现
  • 直接释放请求链接,等到结果完成后返回Response响应
    1. DeferredResult : 返回单个对象
    2. ResponseBodyEmitter : 返回一个列表
    3. SseEmitter : 支持持续响应Response
  • Spring Web Flex也支持这种操作
  • Spring 很多框架支持Reactive编程,比如Redis等
  • Reactive 编程与java流一起使用

RestTemplate

基础

Request Header

    val httpHeaders = HttpHeaders()
    httpHeaders.contentType = MediaType.APPLICATION_JSON 
    httpHeaders.setBasicAuth("usr","pwd")
    httpHeaders.accept = listOf(MediaType.ALL) // 接受任何形式的返回值类型

    val httpEntity = HttpEntity(request, httpHeaders)

    val response = restTemplate.postForObject(url, httpEntity, String::class.java)

Spring Annonation

  • @ConditionalOnMissingBean
    1. 注解里的参数的类型如果已经存在一个Bean,那么被此注解修饰的类的方法上面有此注解的方法将不再执行
  • @ConfigurationProperties
    1. 将properties或者yml配置直接转成对象
    2. 自定义的配置,对象可以自定义
    3. spring为很多模块提供了对象
      1. spring cloud zuul : ZuulProperties

Spring Integration Test

  • 限定profile和指定profile
    1. @ActiveProfiles("integration-mock")
    2. @Profile("integration-mock")
  • 使用随机端口启动服务,并发送http请求进行集成测试
    1. @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    2. @Autowired var testRestTemplate: TestRestTemplate? = null
  • EmbeddedDatabase
    1. @AutoConfigureEmbeddedDatabase
    2. testImplementation("io.zonky.test:embedded-database-spring-test:1.5.0")
  • EmbeddedKafka
    1. @EmbeddedKafka(partitions = 1, topics = [PAYMENT_CORE_EVENT_TOPIC])
    2. testImplementation("org.springframework.kafka:spring-kafka-test")
    3. spring.cloud.stream.kafka.binder.brokers.kafka=9092

Spring statusmachine

factory与service创建StateMachine对比

  • factory
    1. 自动持久化
    2. 不会缓存state machine
    3. 自动读取数据库
  • service
    1. 自动持久化
    2. 会缓存state machine, 所以需要在complate时候release
    3. 自动读取数据库 : autoStart = false and acquireStateMachine: start=false