SpringBoot进阶

@Schedule

在SpringBoot入口或配置类中增加@EnableScheduling注解

有三种调度器

1、Cron表达式

2、固定间隔任务 fixedDelay 单位ms

下一次的任务执行时间,是从方法最后一次任务执行结束时间开始计算。并以此规则开始周期性的执行任务。

3、固定频率任务 fixedRate 单位ms

设定一个频率,任务每隔一个频率时间执行一次,若上一个任务在这个频率时间内未执行完成,则等待上一个任务执行完成后立即执行下次任务。

@Schedule默认开启一个单线程池,可通过重写configureTasks方法设置自定义线程池。

@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }   
    
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(20);
    }
}

或者可以直接在properties文件中加入如下配置

spring.task.scheduling.pool.size=20

此时不同的Schedule会并行执行,但是单个任务仍然会被自己堵塞。
如果需要单个任务被堵塞的情况下,该任务在下一个触发时间仍然执行,则同时使用@Async
至于为什么单个任务仍然会被自己堵塞,而不使用Schedule线程池的其他线程来执行,有时间再看看源码。

@Async

启动加上@EnableAsync,需要执行的异步方法上加上@Async

可为@Async配置线程池

如果异步方法是当前类的方法,AOP会失效。需要经过代理类调用接口,所以需要将异步的代码单独抽取成一个类调用接口。

@Retry

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.3.0</version>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

启动加上 @EnableRetry

@Retryable(recover = "recover", value = Exception.class, maxAttempts = 5, backoff = @Backoff(delay = 3000, multiplier = 1, maxDelay = 5000))
public void retry(Integer userId, String message) {
    client.sendMessage(userId)
}
//value:触发重试的异常
//include:和value一样,默认空,当exclude也为空时,所有异常都重试
//exclude:指定异常不重试,默认空,当include也为空时,所有异常都重试 
//maxAttempts:重试次数(包括第一次调用)
//backoff:重试补偿机制,默认无
//delay:重试的间隔时间
//multiplier:每次延迟是上一次延迟的倍数
//maxDelay:重试次数之间的最大时间间隔,默认为0,如果小于delay的设置,则默认为30000L
//recover:指定补偿方法执行
    
@Recover
public void recover(Exception e, Integer userId, String message){
    MessageException message = new MessageException();
    message.setUserId(userId);
    message.setMessage(message);
    //异常消息插入异常表
    messageExceptionMapper.insert(noticeException);
}

@Slf4j

log.warn("code={},msg={}", 500, "异常", e);
//在log中用{}占位即可

@Autowired & @Resource

(1)提供方:@Autowired是由org.springframework.beans.factory.annotation.Autowired提供,换句话说就是由Spring提供;@Resource是由javax.annotation.Resource提供,即J2EE提供,需要JDK1.6及以上。

(2)注入方式:@Autowired只按照byType 注入;@Resource默认按byName自动注入,也提供按照byType 注入;

(3)属性:@Autowired按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。

@Resource装配顺序

  1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常

  2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常

  3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常

  4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

@RequestMapping中的params(请求参数映射限定)

@RequestMapping(value="/test",params= {"name"})  
//必须包含参数name,无论name有没有值
@RequestMapping(value="/test",params= {"!name"})  
//不可包含参数name
@RequestMapping(value="/test",params= {"name=yu"})  
//必须包含name=yu
@RequestMapping(value="/test",params= {"name!=yu"})  
//没有name或有name但name不为yu
@RequestMapping(value="/test",params= {"id", "name!=yu"})  
//多条件

FilterRegistrationBean

public class TestFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
        throws IOException, ServletException {
        // 相关拦截操作
        chain.doFilter(req,resp);
    }
}
@Configuration
public class filterConfiguration {
    @Bean(name = "xxx")
    public FilterRegistrationBean<TestFilter> filterTest(){
        FilterRegistrationBean<TestFilter> bean = new FilterRegistrationBean<TestFilter>();
        bean.setFilter(new TestFilter());//注册自定义过滤器
        bean.setName("myFilter");//过滤器名称
        bean.addUrlPatterns("/*");//过滤所有路径
        bean.addUrlPattern(".html")//过滤所有html文件
        bean.setOrder(1);//过滤优先级,最顶级
        return bean;
    }
}

Quartz

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
@Configuration
public class QuartzConfig {
    @Bean
    public JobDetail taskJobDetail() {
        return JobBuilder.newJob(Task.class)
                .withIdentity("task") //生成JobKey
                .storeDurably(true)
                .build();
    }
 
    @Bean
    public Trigger taskTrigger() {
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("*/4 * * * * ?");
        return TriggerBuilder.newTrigger()
                .forJob(taskJobDetail())
                .withIdentity("task") //生成triggerKey
                .withSchedule(scheduleBuilder)
                .build();
    }
}


@Component
@DisallowConcurrentExecution //使quartz的单任务串行执行,多任务并行执行
public class Task extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Quartz可以动态设置定时任务,也可持久化定时任务

@SuppressWarnings

抑制警告,让编译器编译完成后不提示相关警告。如果使用IDEA的话,最直观的一点就是可以把代码页右边的黄色小横线给去掉。
参考Intellij idea的抑制警告(SuppressWarnings)的使用方法

Google Guava

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>
// 缓存接口这里是LoadingCache,LoadingCache在缓存项不存在时可以自动加载缓存
LoadingCache<Integer, Student> studentCache
    // CacheBuilder的构造函数是私有的,只能通过其静态方法newBuilder()来获得CacheBuilder的实例
    = CacheBuilder.newBuilder()
    // 设置并发级别为8,并发级别是指可以同时写缓存的线程数
    .concurrencyLevel(8)
    // 设置写缓存后8秒钟过期
    .expireAfterWrite(8, TimeUnit.SECONDS)
    // 设置缓存容器的初始容量为10
    .initialCapacity(10)
    // 设置缓存最大容量为100,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
    .maximumSize(100)
    // 设置要统计缓存的命中率
    .recordStats()
    // 设置缓存的移除通知
    .removalListener(new RemovalListener<Object, Object>() {
        public void onRemoval(RemovalNotification<Object, Object> notification) {
            System.out.println(
                notification.getKey() + " was removed, cause is " + notification.getCause());
        }
    })

    // build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
    .build(new CacheLoader<Integer, Student>() {
        @Override
        public Student load(Integer key) throws Exception {
            Student student = new Student();
            student.setId(key);
            student.setName("name " + key);
            return student;
        }
    });

@Accessors

@Accessors(chain=true)

链式访问,生成setter方法返回this(*也就是返回的是对象*),代替了默认的返回void。

@Accessors(fluent = true)

区别在于getter和setter不带set和get前缀。

class student {
    String Name;
}
student.name("张三")

@Accessors(prefix = "f")

set方法忽略指定的前缀。

class student {
    String fName;
}
student.setName("张三")

Integer

Integer == 比较是比较地址,equals比较是比较值。
Integer 和 int == 比较,Integer自动拆箱
Integer 缓存策略 Integer cache[] 数组中创建了 -128至127的Integer对象,因此在这个范围内的Integer用 == 比较是 true
Integer 之间用 >,>=,<,<= 比较时是比较的值

...

可变长参数,这个位置可以传入任意个该类型参数,简单来说就是个数组。

void test(Integer... arr); 可看作 void test(Integer[] arr) 
test(1,2,3)
test(new Integer[]{1,2,3})

@PostConstruct

类初始化调用顺序:
(1)构造方法Constructor
(2)@Autowired
(3)@PostConstruct

@Data

@Data相当于@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode这5个注解的合集。

如果dto中没有重写toString, 且使用了@Data注解, 调用toString时只会打印子类本身的属性值, 如果想要打印父类的属性:
方式一: 重写tostring
方式二: 子类再加上@ToString(callSuper = true)两个注解, 父类也使用注解@Data

@EqualsAndHashCode(callSuper = true) 可使父类的equals方法考虑子类。
但是许多涉及比较的方法会调用equals方法,因此不建议使用这个注解。
建议重写equals以防造成比较血案。重写后lombok将不会自动生成相应方法。

@Mapper & @MapperScan

mapper的接口上使用@Mapper注解,在编译之后会生成相应的接口实现类
@MapperScan扫描包,包下面的所有接口在编译之后都会生成相应的实现类
@MapperScan(basePackages= {"com.example.project.mapper.mysql","com.example.project.mapper.clickhouse"})

@Repeatable

java中@Repeatable的理解

posted @ 2022-07-15 10:05  云轻YK  阅读(75)  评论(0编辑  收藏  举报