Spring实用功能–Profile、WebService、缓存、消息、ORM

最后更新于:2022-04-01 20:11:59

本篇介绍一些Spring与其他框架结合的实用功能,包括:Apache CXF WebService框架、Redis缓存、RabbitMQ消息、MyBatis框架。 另外对于Profile,也是Spring3.0开始新加的功能,对于开发测试环境、和生产环境分别采用不同的配置,有一定用处。 # Profile Spring3.1新属性管理API:PropertySource、Environment、Profile。 Environment:环境,本身是一个PropertyResolver,但是提供了Profile特性,即可以根据环境得到相应数据(即激活不同的Profile,可以得到不同的属性数据,比如用于多环境场景的配置(正式机、测试机、开发机DataSource配置))。 Profile:剖面,只有激活的剖面的组件/配置才会注册到Spring容器,类似于maven中profile,Spring 3.1增加了一个在不同环境之间简单切换的profile概念, 可以在不修改任何文件的情况下让工程分别在 dev/test/production 等环境下运行。 为了减小部署维护,可以让工程会默认运行在dev模式,而测试环境和生产环境通过增加jvm参数激活 production的profile. 比如,对于如下的一个例子,由于测试环境和生产环境,连接数据库的方式不一样,可以有如下的解决办法: 1、首先ApplicationContext.xml中,xsi:schemaLocation需要引用3.2的xsd 2、ApplicationContext.xml配置如下: ~~~ ~~~ 3、开发环境配置,在web.xml中,如下配置: ~~~ spring.profiles.default dev ~~~ 4、生产环境配置 比如,对于Jboss,在bin/run.conf里面,增加启动参数:-Dspring.profiles.active=production JAVA_OPTS="-Xms2048m -Xmx2048m -XX:MaxPermSize=1024m -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Dsun.lang.ClassLoader.allowArraySyntax=true -Dorg.terracotta.quartz.skipUpdateCheck=true -Dspring.profiles.active=production" 以上是对于Web项目中如何利用profile的一种演示,如果是maven项目,也可以在maven打包时采用不同的profile,命令如下: mvn clean package -Dmaven.test.skip=true -Ponline 通过P参数采用不同的profile,这样可以实现为开发、测试、生产打出不同的包。 不过,不推荐这种打包方式,应该是对于开发、测试、生产打出一样的包,然后根据机器本身的环境,来决定程序是按照那种环境来运行。 如果公司有根据环境变量的自动化部署方式(比如dev/test/stage/online),则这个profile是非常管用的。 # WebService Java生态下的WebService框架非常多,apache cxf 是与spring结合最好的一种。配置步骤如下: 1、pom.xml,增加依赖: ~~~ org.apache.cxf cxf-rt-frontend-jaxws 2.7.5 org.apache.cxf cxf-rt-transports-http 2.7.5 ~~~ 2、web.xml,增加servlet:    ~~~ cxf org.apache.cxf.transport.servlet.CXFServlet 2 cxf /* ~~~ 3、resources目录下,增加applicationContext-cxf.xml,内容如下: ~~~ ~~~ 4、BasicWebService来的内容大致如下: ~~~ @WebService(name = "BasicWebService", serviceName = "BasicWebService", portName = "BasicWebServicePort", targetNamespace = "http://api.domain.com/ws") @Service public class BasicWebService { @WebMethod public void sendHtmlMail(@WebParam(name = "headName") String headName, @WebParam(name = "sendHtml") String sendHtml) { sendMail.doSendHtmlEmail(headName, sendHtml); } } ~~~ 使用Apache CXF框架,是被Spring容器管理的,也就是说,BasicWebService本身可以设置@Service标记,也可以在BasicWebService中使用@Autowired进行注入。 而其他框架的WebService,比如Jboss直接通过Servlet方式暴露的WebService就不能这样,只能通过一个SpringContextHolder手动从Spring容器中拿,大致如下: 1、首先在web.xml中增加WebService类的servlet,如下: ~~~ BasicWebService com.xx.BasisWebService BasicWebService /BasicWebService ~~~ 2、BasicWebService的内容大致如下: ~~~ @WebService(name = "BasicWebService", serviceName = "BasicWebService", portName = "BasicWebServicePort", targetNamespace = "http://api.sina.com/ws") public class BasicWebService { //这是从Spring容器中拿对象,SpringContextHolder是一个实现了org.springframework.context.ApplicationContextAware的类 private ISystemConfigService systemConfigService = SpringContextHolder.getBean(ISystemConfigService.class); @WebMethod public String test(@WebParam(name = "inputpara") String inputpara) { return inputpara + "_100"; } } ~~~ # Redis Spring可以简化调用Redis的操作,配置大致如下: 1、pom.xml增加依赖: ~~~ org.springframework.data spring-data-redis 1.0.6.RELEASE ~~~ 2、resources目录下,增加applicationContext-redis.xml,内容如下: ~~~ Spring-cache ~~~ 3、缓存写入参考实现: ~~~ @Service public class BrandBaseServiceImpl implements IBrandBaseService { @Override @Cacheable(value = CacheClientConstant.COMMODITY_BRAND_REDIS_CACHE, key = "'commodity:webservice:all:brand:list'") public List getAllBrands() { try { List brands = brandMapper.getAllBrands(); return brands; } catch (Exception ex) { logger.error(ex.toString()); return null; } } @Override @Cacheable(value = CacheClientConstant.COMMODITY_BRAND_REDIS_CACHE, key = "'commodity:webservice:brand:no:'+#brandNo") public Brand getBrandByNo(String brandNo) { if (StringUtils.isBlank(brandNo)) return null; return brandMapper.getBrandByNo(brandNo); } } ~~~ 4、缓存清除参考实现: ~~~ @Service public class RedisCacheUtil { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private RedisTemplate redisTemplate; @Autowired private JedisConnectionFactory jedisConnectionFactory; @CacheEvict(value = CacheClientConstant.COMMODITY_CATEGORY_REDIS_CACHE, key = "'commodity:webservice:category:no:'+#categoryNo") public void cleanCatCacheByNo(String categoryNo) { List keys = new ArrayList(); logger.info("[商品服务端]清理分类categoryNo:{}缓存,REDIS SERVER地址:{}", categoryNo, jedisConnectionFactory.getHostName() + ":" + jedisConnectionFactory.getPort()); if (StringUtils.hasText(categoryNo)) { keys.add("commodity:webservice:category:no:" + categoryNo); cleanAgain(keys); } } @CacheEvict(value = CacheClientConstant.COMMODITY_SYSTEMCONFIG_REDIS_CACHE, allEntries = true) public void cleanSystemConfigAll() { logger.info("[商品服务端]清楚SystemConfig缓存"); } /** * 考虑到主从延迟可能会导致缓存更新失效,延迟再清理一次缓存 * @param keys 需要清除缓存的KEY */ private void cleanAgain(List keys) { if (CollectionUtils.isEmpty(keys)) { return; } for (String key : keys) { logger.info("清理缓存,KEY:{}", key); redisTemplate.delete(key); } } } ~~~ # RabbitMQ Spring也可以简化使用RabbitMQ的操作,配置大致如下: 1、pom.xml增加依赖: ~~~ org.springframework.amqp spring-amqp ${spring.amqp.version} org.springframework.amqp spring-rabbit ${spring.amqp.version} ~~~ 2、发送消息代码例子: ~~~ @Service public class MessageSendServiceImpl implements IMessageSendService { private static final String EXCHANGE = "amq.topic"; @Autowired private volatile RabbitTemplate rabbitTemplate; private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public Boolean sendMessage(String commodityNo) { Commodity c = getCommodity(commodityNo); // 发送rabbitMQ消息(topic) rabbitTemplate.convertAndSend(EXCHANGE, "commodity.update.topic", c); logger.info("发送消息成功(topic):商品编号:" + commodityNo); return true; } } ~~~ 3、resources目录下,增加applicationContext-rabbitmq.xml,用来配置接收消息,内容如下: ~~~ ~~~ 4、接收消息代码例子: ~~~ @Component public class CommodityUpdateListener { public void handleMessage(Commodity commodity) { if(commodity==null) { logger.info("XXX"); return; } //处理逻辑 } } ~~~ 5、处理消息错误代码例子: ~~~ @Component public class RabbitMqErrorHandler implements ErrorHandler { private static Logger logger = LoggerFactory.getLogger(RabbitMqErrorHandler.class); @Override public void handleError(Throwable t) { logger.error("Receive rabbitmq message error:{}", t); } } ~~~ # MyBatis Spring可以大大简化使用MyBatis这种ORM框架,定义出接口和Mapper文件之后,Spring可以自动帮我们生成实现类。我曾经在DotNet框架下使用过MyBatis.Net,所有的Mapper的实现类都需要手工写代码,而Spring帮我节省了很多编码工作量。 大致配置步骤如下: 1、pom.xml增加依赖: ~~~ org.mybatis mybatis-spring 1.1.1 org.mybatis.caches mybatis-ehcache 1.0.1 ~~~ 2、resources目录下,applicationContext.xml中,一般放置关于mybatis的配置,内容如下: ~~~ Spring公共配置 classpath*:/application.properties classpath*:/config.properties file:/d:/conf/pcconf/*.properties file:/etc/conf/pcconf/*.properties ~~~ 3、定义接口,及在src/main/resource对应接口的包路径下定义同名的xml配置文件即可。 Spring初始化完毕后,会自动帮我们生成Mapper的实现类。
';