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公共配置
~~~
3、定义接口,及在src/main/resource对应接口的包路径下定义同名的xml配置文件即可。
Spring初始化完毕后,会自动帮我们生成Mapper的实现类。
';