创建带参数的构造函数
1 2 3 4 5 6 7 8 9 10 11
| ***************************
APPLICATION FAILED TO START ***************************
Description: Parameter 0 of constructor in com.deng.service.impl.ImageServiceImpl required a bean of type 'java.lang.String' that could not be found.
Action: Consider defining a bean of type 'java.lang.String' in your configuration.
|
- 创建带参数的构造函数方法
- 创建带参数的
Bean,然后@Autowired该Bean即可
JAVA
1 2 3 4 5 6 7
| @Configuration public class BeanConfig { @Bean ImageService imageService(){ return new ImageServiceImpl("test"); } }
|
参考
异步任务
mian方法添加@EnableAsync注解
JAVA
1 2 3 4 5 6 7 8 9 10
| import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication @EnableAsync public class Application{ public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
|
异步任务执行类添加@Async注解
JAVA
1 2 3 4 5 6 7 8 9 10 11
| import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component;
@Component public class DataExecutor { @Async(value = "publishExecutor") public void executeSth() { } }
|
异步线程池配置
JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import java.util.concurrent.Executor;
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration public class PublishAsynExecutor { @Value("${tk.pe.corePoolSize}") private int corePoolSize; @Value("${tk.pe.maxPoolSize}") private int maxPoolSize; @Value("${tk.pe.queueCapacity}") private int queueCapacity; @Value("${tk.pe.keepAliveSeconds}") private int keepAliveSeconds; @Value("${tk.pe.threadNamePrefix}") private String threadNamePrefix;
@Bean public Executor publishExecutor() { ThreadPoolTaskExecutor publishExecutor = new ThreadPoolTaskExecutor(); publishExecutor.setCorePoolSize(corePoolSize); publishExecutor.setMaxPoolSize(maxPoolSize); publishExecutor.setQueueCapacity(queueCapacity); publishExecutor.setKeepAliveSeconds(keepAliveSeconds); publishExecutor.setThreadNamePrefix(threadNamePrefix); publishExecutor.initialize();
return publishExecutor; } }
|
调用时调用异步任务的方法即可.
如下方式会使@Async失效
- 异步方法使用
static修饰
- 异步类没有使用
@Component注解(或其他注解)导致spring无法扫描到异步类
- 异步方法不能与调用异步方法的方法在同一个类中
- 类中需要使用
@Autowired或@Resource等注解自动注入,不能自己手动new对象
- 如果使用SpringBoot框架必须在启动类中增加
@EnableAsync注解
- 在
Async方法上标注@Transactional是没用的.在Async方法调用的方法上标注@Transactional有效。
参考
定时任务
main方法添加@EnableScheduling注解
JAVA
1 2 3 4 5 6 7 8 9 10
| import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication @EnableScheduling public class Application{ public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
|
添加定时任务
JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.Scheduled;
@Configuration public class ScheduleTask{
@Scheduled(fixedDelay = 180000) public static void myTask() { } }
|
如果执行的时间间隔需要从配置文件读取,则使用如下 方法(时间需要使用corn表达式)
JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import java.util.Date;
import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.TriggerContext; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.scheduling.support.CronTrigger;
@Configuration @EnableScheduling public class ScheduleTask implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { String timeStr = "配置文件的时间获取"; Runnable task = new Runnable() { @Override public void run() { } };
Trigger trigger = new Trigger() { @Override public Date nextExecutionTime(TriggerContext triggerContext) { CronTrigger cronTrigger = new CronTrigger(timeStr); return cronTrigger.nextExecutionTime(triggerContext); } };
scheduledTaskRegistrar.addTriggerTask(task, trigger); } }
|
参考
corn表达式
1 2 3 4 5 6 7 8
| 每隔5秒执行一次:*/5 * * * * ? 每隔1分钟执行一次:0 */1 * * * ? 每天23点执行一次:0 0 23 * * ? 每月1号凌晨1点执行一次:0 0 1 1 * ? 每月最后一天23点执行一次:0 0 23 L * ? 每周星期天凌晨1点实行一次:0 0 1 ? * L 在26分、29分、33分执行一次:0 26,29,33 * * * ? 每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?
|
参考
springboot动态编译class
可以参考, 这里边参考了这篇博客
springboot打包jar再动态编译的方法
因为需要动态生成class文件, 所以必然要在jar外边创建一些文件夹, 故可以将jar先解压, 然后运行
然后在动态生成class的时候加入依赖的jar包到-classpath
参考
springboot的war包放到tomcat动态编译无法找到相关依赖jar或调用类
在测试动态编译的时候,本地可能因为有maven仓库, 不会有依赖jar或调用类找不到的情况
但部署到tomcat服务器, 由于动态编译的时候没有显式的指明依赖的jar包路径, 所以可能出现调用的jar包找不到的情况
可参考如下进行操作
JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.StringJoiner;
import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.SimpleJavaFileObject; import javax.tools.ToolProvider;
private void codeCompiler(String className, String classCode) throws URISyntaxException, IOException { String dest = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath(); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null,null,null); StringObject stringObject = new StringObject(new URI(className + ".java"), JavaFileObject.Kind.SOURCE, classCode); List<String> options = new ArrayList<String>(); options.add("-d"); options.add(dest); options.add("-g"); options.add("-classpath"); options.add(getClasspath(dest)); CompilationTask task = compiler.getTask(null, standardFileManager, null, options, null, Arrays.asList(stringObject)); task.call(); standardFileManager.close(); } private static class StringObject extends SimpleJavaFileObject{
private String content;
public StringObject(URI uri, Kind kind, String content) { super(uri, kind); this.content = content; }
@Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { return this.content; } } private String getClasspath(String dest) { String libProvidedPath = dest.replaceAll("classes", "lib-provided"); String libPath = dest.replaceAll("classes", "lib"); String pathSeparator = File.pathSeparator; StringJoiner classpathStr = new StringJoiner(pathSeparator); classpathStr.add(getAllFilePathInCurrentDir(libProvidedPath)) .add(getAllFilePathInCurrentDir(libPath)) .add(dest);
return classpathStr.toString(); } private String getAllFilePathInCurrentDir(String dirStr) { String pathSeparator = File.pathSeparator; StringJoiner filePathStr = new StringJoiner(pathSeparator); File dir = new File(dirStr); if (dir.isDirectory()) { File[] allFiles = dir.listFiles(); for (File file: allFiles) { filePathStr.add(file.getAbsolutePath()); } }
return filePathStr.toString(); }
|
参考1
参考2
springboot启动完成后执行某个代码
通过实现ApplicationRunner接口
JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component;
@Component public class ApplicationRunnerImpl implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("通过实现ApplicationRunner接口,在spring boot项目启动后打印参数"); String[] sourceArgs = args.getSourceArgs(); for (String arg : sourceArgs) { System.out.print(arg + " "); } System.out.println(); } }
|
或者可以实现CommandLineRunner接口
JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component;
@Component public class CommandLineRunnerImpl implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("通过实现CommandLineRunner接口,在spring boot项目启动后打印参数"); for (String arg : args) { System.out.print(arg + " "); } System.out.println(); } }
|
区别在于run()方法的参数类型不同
参考
获取springboot的jar包中的jar的class方法
重写classloader加载jar包
直接获取class的路径
springboot的异常邮件提醒
依赖jar包
XML
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
|
PROPERTIES
1 2 3 4
| spring.mail.host=smtp.qq.com spring.mail.username=发送邮箱 spring.mail.password=SMTP授权码 spring.mail.default-encoding=UTF-8
|
JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender;
public class Test { @Autowired private JavaMailSender javaMailSender;
public void sendEmail() { SimpleMailMessage message = new SimpleMailMessage(); message.setFrom("from@qq.com"); message.setTo("to@qq.com"); message.setSubject("异常通知"); message.setText("异常"); javaMailSender.send(message); } }
|
参考
springboot自动重启
在pom.xml添加如下依赖jar, 是springboot的开发者工具
XML
1 2 3 4 5 6
| <dependencys> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencys>
|
classpath的任何更新都会触发程序启动, 但会排除下边的目录
- /META-INF/resources
- /resources
- /static
- /public
- /templates
常用配置文件属性
PROPERTIES
1 2 3 4 5 6 7 8 9
| spring.devtools.restart.exclude=WEB-INF/**
spring.devtools.restart.enable=false
spring.devtools.restart.trigger-file=restart-trigger.properties
|
当生成war包后放到tomcat无法自动重启可[参考](/article/tools/tomcat/some-questions#springboot开启自启动工具, tomcat无法自启动)
参考
使用代码重启
使用代码重启的时候, 需要把热部署(自启动)的pom中的jar注释掉
某些情况下, 如在tomcat, 可能下边的context仍旧会有空指针异常
JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class MyApplication { private static String[] args; private static ConfigurableApplicationContext context;
public static void main(String[] args){ MyApplication.args = args; MyApplication.context = SpringApplication.run(MyApplication.class, args); } public static void restart() { context.close(); MyApplication.context = SpringApplication.run(MyApplication.class, args); } }
public void startProject () { Thread restartThread = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); MyApplication.restart(); } catch (InterruptedException ignored) {} } }); restartThread.setDaemon(false); restartThread.start(); }
|
参考
利用反射动态修改注解值
参考