Another post: Spring Boot tutorial 16: implementing multithreading with Spring Boot injection class
SpringBoot injection multi instance, multi thread processing
Seeing this title, I'm sure many people will be puzzled. Looking back on your own scenarios, we will find that in Spring projects, multithreading is rarely used to process tasks. Yes, most of the time we use Spring The scope of the default Controller, Service and Dao components of the web project developed by MVC is single instance, stateless, and then called by concurrent multithreading. What should I do if I want to use multithreading to process tasks?
For example, the following scenarios:
Using spring boot to develop a monitored project, each monitored business (maybe a database table or a pid process) will run in a thread separately, with its own configuration parameters. The summary is as follows:
(1) Multiple instances (multiple services, each of which is isolated from each other and does not affect each other)
(2) Stateful (each business has its own configuration parameters)
If it is a non spring boot project, it may be relatively simple to implement. In the spring project, the bean object is managed by the spring container, and the object you directly new can't be used, which means you can succeed in new. However, other components in the bean, such as Dao, can't be initialized, Because you bypass spring, when the default spring initializes a class, its dependent components will be initialized, but the class from new does not have this function, so we need to get our own thread class through spring, so how to get the class instance through spring, we need to define the following class to get the spring context context:
/** * Created by Administrator on 2016/8/18. * Set the context of spring */ @Component public class ApplicationContextProvider implements ApplicationContextAware { private static ApplicationContext context; private ApplicationContextProvider(){} @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; } public static <T> T getBean(String name,Class<T> aClass){ return context.getBean(name,aClass); } }
Then define our own thread class. Note that this class is a prototype scope, not a default single example:
@Component("mTask") @Scope("prototype") public class MoniotrTask extends Thread { final static Logger logger= LoggerFactory.getLogger(MoniotrTask.class); //Parameter encapsulation private Monitor monitor; public void setMonitor(Monitor monitor) { this.monitor = monitor; } @Resource(name = "greaterDaoImpl") private RuleDao greaterDaoImpl; @Override public void run() { logger.info("thread :"+Thread.currentThread().getName()+"In operation....."); } }
Write a test example. Under the test, use SpringContext to get the Bean and check whether it is multi instance:
/** * Created by Administrator on 2016/8/18. */ @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes =ApplicationMain.class) public class SpingContextTest { @Test public void show()throws Exception{ MoniotrTask m1= ApplicationContextProvider.getBean("mTask", MoniotrTask.class); MoniotrTask m2=ApplicationContextProvider.getBean("mTask", MoniotrTask.class); MoniotrTask m3=ApplicationContextProvider.getBean("mTask", MoniotrTask.class); System.out.println(m1+" => "+m1.greaterDaoImpl); System.out.println(m2+" => "+m2.greaterDaoImpl); System.out.println(m3+" => "+m3.greaterDaoImpl); } }
The operation results are as follows:
[ INFO ] [2016-08-25 17:36:34] com.test.tools.SpingContextTest [57] - Started SpingContextTest in 2.902 seconds (JVM running for 4.196) 2016-08-25 17:36:34.842 INFO 8312 --- [ main] com.test.tools.SpingContextTest : Started SpingContextTest in 2.902 seconds (JVM running for 4.196) Thread[Thread-2,5,main] => com.xuele.bigdata.xalert.dao.rule.impl.GreaterDaoImpl@285f38f6 Thread[Thread-3,5,main] => com.xuele.bigdata.xalert.dao.rule.impl.GreaterDaoImpl@285f38f6 Thread[Thread-4,5,main] => com.xuele.bigdata.xalert.dao.rule.impl.GreaterDaoImpl@285f38f6
We can see that our monitoring class is multi instance, and the Dao in it is single instance, so that we can use multithreading to process our tasks in spring.
How to start our multithreaded task class? You can define a component class to start, or you can start it in the main method to start Spring. Here's how to define component startup:
@Component public class StartTask { final static Logger logger= LoggerFactory.getLogger(StartTask.class); //Define to execute this initialization method after the method is constructed @PostConstruct public void init(){ final List<Monitor> list = ParseRuleUtils.parseRules(); logger.info("Total of monitoring tasks Task Number:{}",list.size()); for(int i=0;i<list.size();i++) { MoniotrTask moniotrTask= ApplicationContextProvider.getBean("mTask", MoniotrTask.class); moniotrTask.setMonitor(list.get(i)); moniotrTask.start(); logger.info("The first{}Monitors task: {}start-up !",(i+1),list.get(i).getName()); } } }
Last note logback.xml In which you can configure the relative and absolute log file paths:
<!-- Logback configuration. See http://logback.qos.ch/manual/index.html --> <configuration scan="true" scanPeriod="10 seconds"> <!-- Simple file output --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">--> <!-- encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <encoder> <pattern> [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n </pattern> <charset>UTF-8</charset> <!-- Set character set here --> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily Configure the directory generated by logs and the rules for generating file names. The default is relative path --> <fileNamePattern>logs/xalert-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!--<property name="logDir" value="E:/testlog" />--> <!--Absolute path definition--> <!--<fileNamePattern>${logDir}/logs/xalert-%d{yyyy-MM-dd}.%i.log</fileNamePattern>--> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!-- or whenever the file size reaches 64 MB --> <maxFileSize>64 MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <!-- Safely log to the same file from multiple JVMs. Degrades performance! --> <prudent>true</prudent> </appender> <!-- Console output --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <encoder> <pattern> [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n </pattern> <charset>UTF-8</charset> <!-- Set character set here --> </encoder> <!-- Only log level WARN and above --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> </appender> <!-- Enable FILE and STDOUT appenders for all log messages. By default, only log at level INFO and above. --> <root level="INFO"> <appender-ref ref="STDOUT" /> <appender-ref ref="FILE" /> </root> <!-- For loggers in the these namespaces, log at all levels. --> <logger name="pedestal" level="ALL" /> <logger name="hammock-cafe" level="ALL" /> <logger name="user" level="ALL" /> <include resource="org/springframework/boot/logging/logback/base.xml"/> <jmxConfigurator/> </configuration