spring mvc asyncenableasync需要的导入哪些jar

spring(8)
这个注解用于标注某个方法或某个类里面的所有方法都是需要异步处理的。被注解的方法被调用的时候,会在新线程中执行,而调用它的方法会在原来的线程中执行。这样可以避免阻塞、以及保证任务的实时性。适用于处理log、发送邮件、短信……等。
注解的应用范围:
类:表示这个类中的所有方法都是异步的
方法:表示这个方法是异步的,如果类也注解了,则以这个方法的注解为准
&task:annotation-driven /&配置:
executor:指定一个缺省的executor给@Async使用。
例子:&task:annotation-driven executor="asyncExecutor" /&
配置参数:
- id:当配置多个executor时,被@Async(“id”)指定使用;也被作为线程名的前缀。
- pool-size:
core size:最小的线程数,缺省:1
max size:最大的线程数,缺省:Integer.MAX_VALUE
queue-capacity:当最小的线程数已经被占用满后,新的任务会被放进queue里面,当这个queue的capacity也被占满之后,pool里面会创建新线程处理这个任务,直到总线程数达到了max
size,这时系统会拒绝这个任务并抛出TaskRejectedException异常(缺省配置的情况下,可以通过rejection-policy来决定如何处理这种情况)。缺省值为:Integer.MAX_VALUE
keep-alive:超过core size的那些线程,任务完成后,再经过这个时长(秒)会被结束掉
rejection-policy:当pool已经达到max size的时候,如何处理新任务
ABORT(缺省):抛出TaskRejectedException异常,然后不执行
DISCARD:不执行,也不抛出异常
DISCARD_OLDEST:丢弃queue中最旧的那个任务
CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
配置例子:
&task:annotation-driven executor="asyncExecutor" /&
&task:executor id="asyncExecutor" pool-size="10-30" queue-capacity="100" rejection-policy="ABORT" /&
executor="asyncExecutor" /&
id="asyncExecutor" pool-size="100-10000" queue-capacity="10" /&
id="logExecutor" pool-size="15-1000" queue-capacity="5" keep-alive="5"/&
@Async("logExecutor")
public void saveUserOpLog(TabUserOpLog tabUserOpLog) {
userOpLogDAO.insertTabUserOpLog(tabUserOpLog);
(注意:如果在同一个类中调用的话,不会生效,原因请参考:)
通过log可以看到,已经分开两个线程执行:
线程的优先级和类型:
优先级:NORM_PRIORITY
类型:非守护线程
用户线程(User Thread):JVM会等待所有的用户线程结束后才退出;当系统中没有用户线程了,JVM也就退出了
守护线程(Daemon Thread):一般是为其他线程提供服务的线程,比如GC垃圾回收器;JVM退出时,不会管守护线程是否存在,而是直接退出
所以,对于文件、数据库的操作,不适宜使用守护线程,不然可能会丢失数据!
Web应用停止时,Spring容器会被关闭,调用者如果是Spring bean,就会停止生成新任务。然而,线程池中已经在运行的任务,由于缺省是用户线程,所以JVM会等待它们结束后才退出。
附:Java编程方式的配置方法:
@Configuration
@EnableAsync
public class SpringConfig {
/** Set the ThreadPoolExecutor's core pool size. */
private int corePoolSize = 10;
/** Set the ThreadPoolExecutor's maximum pool size. */
private int maxPoolSize = 200;
/** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */
private int queueCapacity = 10;
private String ThreadNamePrefix = "MyLogExecutor-";
public Executor logExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix(ThreadNamePrefix);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:61938次
积分:1075
积分:1075
排名:千里之外
原创:36篇
转载:58篇
(1)(3)(1)(2)(1)(4)(1)(6)(7)(6)(8)(12)(7)(34)(1)spring(87)
Spring环境搭建之:导入jar包、配置文件名称及放置位置
现在项目开发中Spring框架应用的还是比较多的,自己用的还不太熟练,每次用的时候总配置半天,总有些配置弄错,就找个时间总结以下,方便以后再搭建环境的时候直接拿来用。
以Spring4为例,这里就不提供Spring的下载地址了,官网上很容易下的到。
1、导入相关jar包
建好web项目以后,导入Spring自己的jar包
spring-beans-4.0.0.M2.jar
spring-context-4.0.0.M2.jar
spring-core-4.0.0.M2.jar
spring-expression-4.0.0.M2.jar
spring-jdbc-4.0.0.M2.jar
spring-tx-4.0.0.M2.jar
spring-web-4.0.0.M2.jar
spring-webmvc-4.0.0.M2.jar
导入Spring所依赖的jar包
commons-logging-1.1.1.jar
导入文件上传下载组件的jar包
commons-fileupload-1.3.jar
commons-io-2.4.jar
导入数据源jar包,这里用的是apache的dbcp
commons-dbcp-1.4.jar
commons-pool-1.6.jar
Spring MVC中使用JstlView时需要添加的包
jstl-1.1.2.jar
standard-1.1.2.jar
数据库驱动包,这里用的是mysql
mysql-connector-java-5.1.7-bin.jar
其他项目所需的jar包,导入jar包可以先自己尝试,在项目的相关配置完成以后,尝试部署启动web服务器,根据服务器启动过程中的提示添加缺少的jar包就行,直到服务器正常启动。
2、配置文件的名称及放置位置
2.1默认名称及位置
Spring框架默认会加载classpath(类路径)下的applicationContext.xml文件,
即项目的代码根目录src/applicationContext.xml,
项目部署后在服务器上的存储目录就是WEB-INF/classes/applicationContext.xml
2.2自定义名称及位置
当然我们可以更改配置文件的名称,也可以更改文件的放置位置
不过这样就需要在web.xml文件中配置相关信息,来告诉Spring框架去哪里加载配置文件。
在web.xml中配置ContextLoaderListener或ContextLoaderServlet指定加载路径方式。
它们两个有着同样的功能,都实现在了org.springframework.web.context.ContextLoader类,
都要定义contextConfigLocation参数。区别在于listener不能在Servlet 2.2兼容的容器中使用。
自从Servelt 2.4规范,listener被要求在web应用启动后初始化。web.xml初始化的时候,
listerner会检查contextConfigLocation参数。如果不存在的话,它将默认使用
/WEB-INF/classes/applicationContext.xml。
如果它存在,它就会用预先定义的分隔符(逗号,分号和空格)分开分割字符串(&param-value&&/param-value),
并将这些值作为应用上下文将要搜索的位置。
&context-param&
&&&&&param-name&contextConfigLocation&/param-name&
&&&&&param-value&/WEB-INF/conf/applicationContext.xml&/param-value&
&/context-param&
&listener&
&&&&&listener-class&org.springframework.web.context.ContextLoaderListener&/listener-class&
&/listener&
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:265446次
积分:4623
积分:4623
排名:第5031名
原创:42篇
转载:1055篇
(2)(55)(189)(166)(71)(80)(56)(125)(109)(4)(50)(122)(22)(4)(7)(25)(3)(8)在Spring中使用异步事件实现同步事务
& & & &&& & &
结合Scala+Spring,我们将采取一个很简单的场景:下订单,然后发送一封电子邮件。
编制一个服务:
class OrderService @Autowired() (orderDao:
OrderDao, mailNotifier: OrderMailNotifier) {
@Transactional
def placeOrder(order: Order) {
orderDao save order //保存订单
&&& &&&&mailNotifier sendMail order //发送邮件
上面代码是在保存订单和发送邮件两个同步执行,发送邮件需要连接邮件服务器,比较耗时,拖延了整个性能,我们采取异步发送电子邮件,利用Spring内置的自定义事件,与JMS或其他生产者 - 消费者类似。
case class OrderPlacedEvent(order: Order)
extends ApplicationEvent
class OrderService @Autowired() (orderDao:
OrderDao, eventPublisher: ApplicationEventPublisher) {
@Transactional
def placeOrder(order: Order) {
orderDao save order
eventPublisher publishEvent OrderPlacedEvent(order)
区别是继承了ApplicationEvent 之前是直接用&OrderMailNotifier&直接发送,而现在我们使用&发送发邮件事件了。
事件监听者代码如下:
class OrderMailNotifier extends
ApplicationListener[OrderPlacedEvent] {
def onApplicationEvent(event: OrderPlacedEvent) {
//sending e-mail...
在监听者方法中真正实现邮件发送。
但是Spring的ApplicationEvents是同步事件,意味着我们并没有真正实现异步,程序还会在这里堵塞,如果希望异步,我们需要重新定义一个ApplicationEventMulticaster,实现类型SimpleApplicationEventMulticaster和TaskExecutor:
def applicationEventMulticaster() = {
val multicaster = new SimpleApplicationEventMulticaster()
multicaster.setTaskExecutor(taskExecutor())
multicaster
def taskExecutor() = {
val pool = new ThreadPoolTaskExecutor()
pool.setMaxPoolSize(10)
pool.setCorePoolSize(10)
pool.setThreadNamePrefix(&Spring-Async-&)
Spring通过使用TaskExecutor已经支持广播事件了,对onApplicationEvent()&标注&
def onApplicationEvent(event: OrderPlacedEvent) {
如果你希望使用@Async,可以编制自己的异步执行器:
@Configuration
@EnableAsync
class ThreadingConfig extends
AsyncConfigurer {
def getAsyncExecutor = taskExecutor()
def taskExecutor() = {
val pool = new ThreadPoolTaskExecutor()
pool.setMaxPoolSize(10)
pool.setCorePoolSize(10)
pool.setThreadNamePrefix(&Spring-Async-&)
@ EnableAsync是足够了。,默认情况下,Spring使用SimpleAsyncTaskExecutor类创建新的线程。
以上所有设置暴露一个真正的问题。现在,我们虽然使用其他线程发送一个异步消息处理。不幸的是,我们引入竞争条件。
存储order到数据库
发送一个包装order的消息
异步线程获得OrderPlacedEvent并开始处理。现在的问题是,它发生(3)之后,还是(4)之前或者(4)之后?这有一个很大的区别!在前者的情况下,交易也尚未提交订单所以不存在于数据库中。另一方面,延迟加载可能已经在工作,致使订单对象仍然然绑定在 PersistenceContext(缺省我们使用JPA)。
解决办法是使用&.,可以注册很多监听者&,它对于事务的提交或回滚都有事件发送。
@Transactional
def placeOrder(order: Order) {
orderDao save order
afterCommit {
eventPublisher publishEvent OrderPlacedEvent(order)
private def afterCommit[T](fun: =& T) {
TransactionSynchronizationManager.registerSynchronization(new
TransactionSynchronizationAdapter {
override def afterCommit() {
&&&&&&&&&&&
当前事务提交后 afterCommit()接受调用,可以安全地调用registerSynchronization()多次 - 监听器存储在Set并且本地保存到当前事务中,事务提交后消失。
我们将afterCommit方法单独抽象成一个类,分离关注。
TransactionAwareApplicationEventPublisher(delegate: ApplicationEventPublisher)
extends ApplicationEventPublisher {
override def publishEvent(event: ApplicationEvent) {
if (TransactionSynchronizationManager.isActualTransactionActive) {
&&&&&&&&&&&
TransactionSynchronizationManager.registerSynchronization(
&&&&&&&&&&&&&&& new
TransactionSynchronizationAdapter {
&&&&&&&&&&&&&&&&&&& override def afterCommit()
&&&&&&&&&&&&&&&&&&&&&&& delegate publishEvent
&&&&&&&&&&&&&&&&&&& }
&& &&&&&&&&&&&&&})
&&&&&&&&&&&
delegate publishEvent event
TransactionAwareApplicationEventPublisher是实现Spring的ApplicationEventPublisher。
我们要将这个新的实现告诉Spring替换掉旧的,用@Primary:
val applicationContext: ApplicationContext
transactionAwareApplicationEventPublisher() =
new TransactionAwareApplicationEventPublisher(applicationContext)
再看看原来的订单服务:
class OrderService @Autowired() (orderDao:
OrderDao, eventPublisher: ApplicationEventPublisher) {
@Transactional
def placeOrder(order: Order) {
orderDao save order
eventPublisher publishEvent OrderPlacedEvent(order)
注意这里ApplicationEventPublisher已经是我们自己实现的TransactionAwareApplicationEventPublisher,将被自动注入这个服务。
最后,要在真正订单保存的业务代码上放置事务:
def placeOrder(order: Order) {
storeOrder(order)
eventPublisher publishEvent OrderPlacedEvent(order)
@Transactional
def storeOrder(order: Order) = orderDao
save order
当然这没有根本解决问题,如果placeOrder有一个更大的事务怎么办?
| 网站地图 | 设为首页

我要回帖

更多关于 导入spring jar包 的文章

 

随机推荐