Java多线程中调用Spring的Bean三种实现方式

  • 作者: 凯哥Java(公众号:凯哥Java)
  • 工作小总结
  • 时间:2023-05-17 15:37
  • 2617人已阅读
简介 一、背景  工作中我们想写个线程是很简单的,方式也很多,我在之前的文章Java实现多线程方式详解也介绍过,就不多讲了,但是实际工作中,尤其是采用spirng注解的方式的情况下,有时我们就要在线程中调用Spring的Bean,很多小伙伴还不知道怎么处理,我们今天就来聊聊Java多线程中调用Spring的Bean的几种方式,本文中SpringBoot版本为2.5.2,JDK环境为1.8,本文中使用到的

🔔🔔🔔好消息!好消息!🔔🔔🔔

有需要的朋友👉:联系凯哥 微信号 kaigejava2022

一、背景

  工作中我们想写个线程是很简单的,方式也很多,我在之前的文章Java实现多线程方式详解也介绍过,就不多讲了,但是实际工作中,尤其是采用spirng注解的方式的情况下,有时我们就要在线程中调用Spring的Bean,很多小伙伴还不知道怎么处理,我们今天就来聊聊Java多线程中调用Spring的Bean的几种方式,本文中Spring Boot版本为2.5.2,JDK环境为 1.8,本文中使用到的依赖如下:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.5.2</version>
    </dependency>
    
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.14</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>compile</scope>
    </dependency>

本文使用@PostConstruct 进行测试,@PostConstruct 是一个java的注解,它修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。


二、方式一:实现ApplicationContextAware接口

  当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean。前提是该类上有IOC相关注解才会生效,例如@Component(当然使用xml配置的bean信息也可以)


2.1、工具类

SpringBeanUtil.java

package com.alian.multithread.common;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringBeanUtil implements ApplicationContextAware {

    //定义静态ApplicationContext
    private static ApplicationContext applicationContext;

    //重写接口的方法,该方法在启动项目的时候会自动执行
    //该类上有IOC相关注解才会生效,例如@Component
    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        applicationContext = context;
    }

    //通过beanName获取Bean
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanName) {
        return (T) applicationContext.getBean(beanName);
    }

    //通过beanClass获取Bean
    public static <T> T getBean(Class<T> beanClass) {
        return applicationContext.getBean(beanClass);
    }

}

2.2、发送短信服务类

我们简单写个发送短信的服务类

PushSmsService.java

package com.alian.multithread.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class PushSmsService {

    public void pushSms() {
        log.info("推送短信服务子线程【{}】执行", Thread.currentThread().getName());
    }
}

2.3、发送短信线程类

我们再写一个发送短信的线程类

PushSmsRunnable.java

package com.alian.multithread.thread;

import com.alian.multithread.common.SpringBeanUtil;
import com.alian.multithread.service.PushSmsService;

public class PushSmsRunnable implements Runnable{

    @Override
    public void run() {
    	//获取到我们需要的bean
        PushSmsService pushSmsService = SpringBeanUtil.getBean(PushSmsService.class);
        pushSmsService.pushSms();
    }

}

2.4、发送短信测试

写个简单的测试方法

TestPushSmsService .java

package com.alian.multithread.service;

import com.alian.multithread.thread.PushSmsRunnable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

@Slf4j
@Service
public class TestPushSmsService {

    @PostConstruct
    public void testPushSms() {
        for (int i = 0; i < 3; i++) {
            Thread thread = new Thread(new PushSmsRunnable());
            thread.start();
        }
    }

}


运行结果:

25881e3fa62436c29322526d5653f980.png

三、方式二:线程内部构造方法

3.1、发送邮件服务类

我们还可以在线程类中通过构造方法注入所需要的bean,我们先写一个发送邮件的服务类

SendEmailService.java

package com.alian.multithread.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class SendEmailService {

    public void sendEmail() {
        log.info("发送邮件服务子线程【{}】执行", Thread.currentThread().getName());
    }

}

3.2、发送邮件线程类

我们写一个发送邮件的线程类

SendEmailRunnable.java

package com.alian.multithread.thread;

import com.alian.multithread.service.SendEmailService;

public class SendEmailRunnable implements Runnable{

    private SendEmailService sendEmailService;

    public SendEmailRunnable(SendEmailService sendEmailService){
        this.sendEmailService=sendEmailService;
    }

    @Override
    public void run() {
        sendEmailService.sendEmail();
    }
}

3.3、发送邮件测试

TestSendEmailService.java

package com.alian.multithread.service;

import com.alian.multithread.thread.SendEmailRunnable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

@Slf4j
@Service
public class TestSendEmailService {

    @Autowired
    private SendEmailService sendEmailService;

    @PostConstruct
    public void testSendEmail() {
        for (int i = 0; i < 4; i++) {
            Thread thread = new Thread(new SendEmailRunnable(sendEmailService));
            thread.start();
        }
    }
}

运行结果:

911a31c7af6d28a681906edde0712650.png

四、方式三:内部类(推荐

4.1、个性化服务类

我们先一个个性化服务类

PersonalService.java

package com.alian.multithread.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class PersonalService {

    public void personalBuss() {
        log.info("个性化服务子线程【{}】执行", Thread.currentThread().getName());
    }

}

4.2、个性化服务类测试

TestPersonalService.java

package com.alian.multithread.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

@Slf4j
@Service
public class TestPersonalService {

    @Autowired
    private PersonalService personalService;

    @PostConstruct
    public void execute() {
        for (int i = 0; i < 5; i++) {
            new PersonalThread().start();
        }
    }

    private class PersonalThread extends Thread {

        @Override
        public void run() {
            TestPersonalService.this.personalService.personalBuss();
        }

    }

}

运行结果:

d813732a12455f13ef3b207e5e249f42.png

结语

  关于线程参数的传递:这三种方式,如果是最终的业务类需要传入参数,则可以通过线程类的有参构造方法传递到线程内。


TopTop