Java多线程中调用Spring的Bean

目录

    • 一、背景
    • 二、方式一:实现ApplicationContextAware接口
      • 2.1、工具类
      • 2.2、发送短信服务类
      • 2.3、发送短信线程类
      • 2.4、发送短信测试
    • 三、方式二:线程内部构造方法
      • 3.1、发送邮件服务类
      • 3.2、发送邮件线程类
      • 3.3、发送邮件测试
    • 四、方式三:内部类(推荐
      • 4.1、个性化服务类
      • 4.2、个性化服务类测试
    • 结语

一、背景

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

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starterartifactId>
        <version>2.5.2version>
    dependency>
    
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <version>1.16.14version>
    dependency>

    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.12version>
        <scope>compilescope>
    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();
        }
    }

}

运行结果:

2021-11-14 09:38:41 363 [Thread-4] INFO pushSms 11:推送短信服务子线程【Thread-4】执行
2021-11-14 09:38:41 363 [Thread-3] INFO pushSms 11:推送短信服务子线程【Thread-3】执行
2021-11-14 09:38:41 363 [Thread-5] INFO pushSms 11:推送短信服务子线程【Thread-5】执行

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

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();
        }
    }
}

运行结果:
2021-11-14 09:50:37 991 [Thread-4] INFO sendEmail 11:发送邮件服务子线程【Thread-4】执行
2021-11-14 09:50:37 991 [Thread-5] INFO sendEmail 11:发送邮件服务子线程【Thread-5】执行
2021-11-14 09:50:37 991 [Thread-3] INFO sendEmail 11:发送邮件服务子线程【Thread-3】执行
2021-11-14 09:50:37 991 [Thread-6] INFO sendEmail 11:发送邮件服务子线程【Thread-6】执行

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

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();
        }

    }

}

运行结果:

2021-11-14 09:46:55 457 [Thread-3] INFO personalBuss 11:个性化服务子线程【Thread-3】执行
2021-11-14 09:46:55 457 [Thread-6] INFO personalBuss 11:个性化服务子线程【Thread-6】执行
2021-11-14 09:46:55 457 [Thread-7] INFO personalBuss 11:个性化服务子线程【Thread-7】执行
2021-11-14 09:46:55 457 [Thread-5] INFO personalBuss 11:个性化服务子线程【Thread-5】执行
2021-11-14 09:46:55 457 [Thread-4] INFO personalBuss 11:个性化服务子线程【Thread-4】执行

结语

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

你可能感兴趣的:(Java基础实战,spring,bean,多线程)