在开发中经常会使用 Spring 的@Autowired 来实现对象的自动注入,但是在最近的开发中在多线程中用 Spring 的@Autowired 来自动注入时总是注入不进去,代码如下:Java 代码
- package com.common.base.utils.SpringUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import java.util.concurrent.atomic.AtomicInteger;
- public class ThreadRunner implements Runnable{
- @Autowired
- private ServiceBean serviceBean;
- private static AtomicInteger count = new AtomicInteger(0);
- @Override
- public void run(){
- if (serviceBean ==null){
- return;
- }
- serviceBean.log();
- count.addAndGet(1);
- System.out.println(“当前线程为:” + Thread.currentThread().getName() + “count:” + count);
- }
- public ServiceBean getServiceBean() {
- return serviceBean;
- }
- public void setServiceBean(ServiceBean serviceBean) {
- this.serviceBean = serviceBean;
- }
- }
其中,ServiceBean 定义如下:Java 代码
- package com.common.base.utils.SpringUtils;
- import org.springframework.stereotype.Service;
- @Service(“serviceBean”)
- public class ServiceBean{
- public void log(){
- System.out.println(“this is service bean.”);
- }
- }
只是简单的输出语句。然后在主线程中,启动线程,如下:Java 代码
- package com.common.base.utils.SpringUtils;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration(locations = {“classpath*:Service-*.xml”})
- public class SpringMultiThreadTest{
- @Test
- public void testSpringBean(){
- for (int i=0; i<10000000; i++){
- new Thread(new ThreadRunner()).start();
- }
- try {
- Thread.sleep(1000);
- }catch (InterruptedException e){
- e.printStackTrace();
- }
- }
- }
此时,不会有打印信息,serviceBean 为空。
原因:在主线程中使用了:Java 代码
- new ThreadRunner()
新建了一个实例,并不在 Spring 容器中,也就没法获得 Spring 中的 bean。
解决办法:
1、将 ThreadRunner 类也作为一个 bean 注入到 spring 容器中,如下:Java 代码
- package com.common.base.utils.SpringUtils;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration(locations = {“classpath*:Service-*.xml”})
- public class SpringMultiThreadTest{
- @Autowired
- private ThreadRunner threadRunner;
- @Test
- public void testSpringBean(){
- for (int i=0; i<10000000; i++){
- new Thread(threadRunner).start();
- }
- try {
- Thread.sleep(1000);
- }catch (InterruptedException e){
- e.printStackTrace();
- }
- }
- }
问题解决。
2、使用 Spring 手动获得 ServiceBean,首先写一个手动获得 Spring bean 的工具类:Java 代码
- package com.common.base.utils.SpringUtils;
- import org.springframework.beans.BeansException;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- /**
- * 直接通过 Spring 上下文获取 SpringBean,用于多线程环境
- * by jingquan @20160405
- */
- public class SpringBeanUtil implements ApplicationContextAware{
- private static ApplicationContext applicationContext = null;
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- SpringBeanUtil.applicationContext = applicationContext;
- }
- public static Object getBeanByName(String beanName) {
- if (applicationContext == null){
- return null;
- }
- return applicationContext.getBean(beanName);
- }
- public static <T> T getBean(Class<T> type) {
- return applicationContext.getBean(type);
- }
- }
然后在 ThreadRunner 类中不自动获取,而是手动获取,代码如下:Java 代码
- package com.common.base.utils.SpringUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import java.util.concurrent.atomic.AtomicInteger;
- public class ThreadRunner implements Runnable{
- private ServiceBean serviceBean;
- private static AtomicInteger count = new AtomicInteger(0);
- public ThreadRunner(){
- this.serviceBean = (ServiceBean)SpringBeanUtil.getBeanByName(“serviceBean”);
- }
- @Override
- public void run(){
- if (serviceBean ==null){
- return;
- }
- serviceBean.log();
- count.addAndGet(1);
- System.out.println(“当前线程为:” + Thread.currentThread().getName() + “count:” + count);
- }
- public ServiceBean getServiceBean() {
- return serviceBean;
- }
- public void setServiceBean(ServiceBean serviceBean) {
- this.serviceBean = serviceBean;
- }
- }
问题解决。