一 Spring框架多线程调用服务类的方法
我们在开发Web的项目时,有时候我们想在线程的环境下使用@Service或@Component 注解的服务类方法,多线程下是不能直接调用,以下总结一些常用的技巧转换成可调用的形式。
二 Spring框架下多线程下调用动态服务类实现
1 使服务类转静态化
使服务类静态化,让服务类变成静态可调用的,这样从而可以使多线程调用相应的方法
方式一:使用@PostConstruct注解(推荐使用)
@PostConstruct注解是javax.annotation包下的一个注解,它用于标记一个方法,在框架扫描所有的类实例化装入容器,且依赖注入完成后,执行该方法。代码如下:
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
/***
* 本地缓存
* @author hua
* @date 2024-05-23 09:10
*/
@Service
public class LocalCacheServiceImpl implements CacheService {
public static LocalCacheServiceImpl localCacheServiceImpl;
@PostConstruct // 初始化
public void init() {
localCacheServiceImpl = this;
}
private static Cache<String, String> cache = CacheBuilder.newBuilder()
.initialCapacity(3000)
.concurrencyLevel(5)
.expireAfterWrite(30, TimeUnit.MINUTES)
.build();
@Override
public void put(String key, String value) {
cache.put(key,value);
}
@Override
public String get(String key) {
return cache.getIfPresent(key);
}
}
方式二: 使用@Autowired注解
@Autowired注解同样可以把实例化对象注入到当前的静态字段值,与之关联。代码如下:
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
/***
* 本地缓存
* @author hua
* @date 2024-05-23 09:10
*/
@Service
public class LocalCacheServiceImpl implements CacheService {
public static LocalCacheServiceImpl localCacheServiceImpl;
@Autowired
public void setLocalCacheServiceImpl(LocalCacheServiceImpl localCacheServiceImpl) {
LocalCacheServiceImpl.localCacheServiceImpl = localCacheServiceImpl;
}
private static Cache<String, String> cache = CacheBuilder.newBuilder()
.initialCapacity(3000)
.concurrencyLevel(5)
.expireAfterWrite(30, TimeUnit.MINUTES)
.build();
@Override
public void put(String key, String value) {
cache.put(key,value);
}
@Override
public String get(String key) {
return cache.getIfPresent(key);
}
}
2 使用ApplicationContexAware
获取Bean
在线程类实现ApplicationContextAware
接口,这样可以获取到Spring的ApplicationContext,进而从中获取到需要的服务Bean,实现代码如下:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class MyTask implements Runnable, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void run() {
MyService myService = applicationContext.getBean(MyService.class);
myService.serviceMethod();
}
}
3 通过构造函数注入
直接在创建线程的地方,将Service Bean作为构造参数或者通过setter方法传给线程。
@Service
public class MyService {
public void serviceMethod() {
}
}
public class MyTask implements Runnable {
private final MyService myService;
//通过构造函数把服务对像传进行去
public MyTask(MyService myService) {
this.myService = myService;
}
@Override
public void run() {
myService.serviceMethod();
}
}
// 在启动线程的地方
@Autowired
private MyService myService;
public void startMyTask() {
Thread thread = new MyTask(myService);
thread.start();
}
三 总结:
上述方法中,第1种实现最简单方便,第2种较为常见,第3 种容易理解。选择哪种方法取决于你的具体需求和项目的现有架构。在大多数情况下,项目使用第1种方式一,有时候选则传递Bean实例(第3种方法)。