Spring学习(下)

Spring学习(下)

专题三:JavaMail邮件发送
API与环境配置

JavaMail是一套收发电子邮件的API,未包含在JDK中,而是作为JavaEE的一部分。

厂商可以提供自己的实现类,有选择地实现某些邮件协议:

SMTP(Simple Mail Transport Protocal):简单邮件传输协议 POP3:接收电子邮件的标准协议 IMAP:互联网消息协议,是POP3的替代协议 都有对应SSL加密传输的协议,SMTPS,POP3S,IMAPS。

除javamail服务提供程序外,

还需要JAF(JavaBeans Activation Framework)来处理不是纯文本的邮件内容,
这包括MIME(多用途互联网邮件扩展Multipurpose Internet Mail Extensions),URL页面和文件附件等内容。JAF在java6之后已经合并到JDK中。

流程:邮件发送投递到邮箱服务器(163,126,139等)–> 对方登录到客户端之后,下载邮件到本地

JavaMail的关键对象

1:Properties属性对象

javamail通过properties对象封装诸多属性信息比如:服务器地址,端口,用户名,密码等。

2:Session会话对象

这里的session只是一对配置信息的集合,不是httpsession。作用是:<1>接收各种配置属性信息。<2>初始化javamail环境,根据javamail的配置文件。

3:Transport和Store:传输与存储

邮件操作只有发送与接收两种处理方式,传输对应邮件的发送,存储对应邮件的接收。

4:Message消息对象

此为一个抽象类,必须使用一个子类,通常为MimeMessage;

5:Address:地址

也是一个抽象类,用InternetAddress类。

6:Authenticator:认证者

访问邮箱服务器用这个进行用户名与密码进行认证,也是抽象类,有默认实现类。

代码实现
//普通邮件发送
public static void mail01(){
    Message message = null;
    Session session = null;
    Properties properties = null;
    try {
        properties = new Properties();
        //设置邮箱服务器域名
        properties.put("mail.smtp.host","smtp.126.com");
        //设置邮箱端口号,一般为25
        properties.put("mail.smtp.port","25");
        //设置邮箱认证的标识
        properties.put("mail.smtp.auth",true);

        session = Session.getDefaultInstance(properties,new MyAuthenticator("linghe***n@126.com","**"));
        message = new MimeMessage(session);
        //补全message
        /*1,邮件消息发送人,接收人
        2,消息主题
        3,邮件内容*/
        Address address = new InternetAddress("linghefei**@126.com");
        //设置发送人
        message.setFrom(address);
        //设置接收人
        message.setRecipients(Message.RecipientType.TO,new InternetAddress[]{new InternetAddress("*****")});
        //设置主题
        message.setSubject("java mail待你查收!");
        //设置内容
        message.setText("你好吗?!");

        Transport.send(message);
    } catch (Exception e) {
        e.printStackTrace();
    }

}

class MyAuthenticator extends Authenticator{

    private String userName;
    private String password;

    public MyAuthenticator(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }

    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(userName, password);
    }
}
//html邮件发送
public static void mail02(){
    Message message = null;
    Session session = null;
    Properties properties = null;
    Multipart multipart = null;
    BodyPart bodyPart = null;

    try {
        properties = new Properties();
        //设置邮箱服务器域名
        properties.put("mail.smtp.host","smtp.126.com");
        //设置邮箱端口号,一般为25
        properties.put("mail.smtp.port","25");
        //设置邮箱认证的标识
        properties.put("mail.smtp.auth",true);

        session = Session.getDefaultInstance(properties,new MyAuthenticator("lingh*****@126.com","***"));
        message = new MimeMessage(session);
        //补全message
        /*1,邮件消息发送人,接收人
        2,消息主题
        3,邮件内容html*/
        Address address = new InternetAddress("ling***@126.com");
        //设置发送人
        message.setFrom(address);
        //设置接收人
        message.setRecipients(Message.RecipientType.TO,new InternetAddress[]{new InternetAddress("*******")});
        //设置主题
        message.setSubject("java mail待你查收!");
        //设置内容
        multipart = new MimeMultipart();
        bodyPart = new MimeBodyPart();
        bodyPart.setContent("<image src='https://www.baidu.com/img/dong_8f1d47bcb77d74a1e029d8cbb3b33854.gif'/><a herf='https://www.baidu.com'>百度</a>",
                "text/html;charset=utf-8");
        multipart.addBodyPart(bodyPart);
        message.setContent(multipart);

        Transport.send(message);
    } catch (Exception e) {
        e.printStackTrace();
    }

}
//html邮件+附件
    public static void mail03(){
        Message message = null;
        Session session = null;
        Properties properties = null;
        Multipart multipart = null;
        BodyPart bodyPart = null;

        try {
            properties = new Properties();
            //设置邮箱服务器域名
            properties.put("mail.smtp.host","smtp.126.com");
            //设置邮箱端口号,一般为25
            properties.put("mail.smtp.port","25");
            //设置邮箱认证的标识
            properties.put("mail.smtp.auth",true);

            session = Session.getDefaultInstance(properties,new MyAuthenticator("l***@126.com","***50"));
            message = new MimeMessage(session);
            //补全message
            /*1,邮件消息发送人,接收人
            2,消息主题
            3,邮件内容html*/
            Address address = new InternetAddress("li***@126.com");
            //设置发送人
            message.setFrom(address);
            //设置接收人
            message.setRecipients(Message.RecipientType.TO,new InternetAddress[]{new InternetAddress("h****")});
            //设置主题
            message.setSubject("java mail待你查收!");
            //设置内容
            multipart = new MimeMultipart();
            bodyPart = new MimeBodyPart();
            bodyPart.setContent("<image src='https://www.baidu.com/img/dong_8f1d47bcb77d74a1e029d8cbb3b33854.gif'/><a herf='https://www.baidu.com'>百度</a>",
                    "text/html;charset=utf-8");
            multipart.addBodyPart(bodyPart);//html内容添加

            //添加附件:
            bodyPart = new MimeBodyPart();//重新将变量调整下指向
            bodyPart.setDataHandler(new DataHandler(new FileDataSource(new File("what.txt"))));
            bodyPart.setFileName("what.txt");
            //防止中文名称下客户端服务端编码不统一而乱码:
//            bodyPart.setFileName(MimeUtility.encodeText("what.txt"));
            multipart.addBodyPart(bodyPart);//附件添加



            message.setContent(multipart);

            Transport.send(message);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

代码封装:

@SuppressWarnings("all")
@Component
public class MailSender {
    public void sendMail(String from, String[] to, String subject, String content, String[] files) {

        //参数校验
        /*from邮箱格式的合法性
        to非空 邮箱格式合法
        subject非空
        content非空*/

        Message message = null;
        Session session = null;
        Properties properties = null;
        Multipart multipart = null;
        BodyPart bodyPart = null;

        try {
            properties = new Properties();
            //设置邮箱服务器域名
            properties.put("mail.smtp.host", "smtp.126.com");
            //设置邮箱端口号,一般为25
            properties.put("mail.smtp.port", "25");
            //设置邮箱认证的标识
            properties.put("mail.smtp.auth", true);

            session = Session.getDefaultInstance(properties, new MyAuthenticator("lingh***com", "**"));
            message = new MimeMessage(session);
            //补全message
            /*1,邮件消息发送人,接收人
            2,消息主题
            3,邮件内容html*/
            Address address = new InternetAddress(from);
            //设置发送人
            message.setFrom(address);
            //设置接收人

            //构建接收方
            InternetAddress[] receivers = new InternetAddress[to.length];
            for (int i = 0; i < to.length; i++) {
                receivers[i] = new InternetAddress(to[i]);
            }
            message.setRecipients(Message.RecipientType.TO, receivers);

            //设置主题
            String subjectAfter = MimeUtility.encodeWord(subject, "UTF-8", "Q");
            message.setSubject(subjectAfter);


            //设置内容
            multipart = new MimeMultipart();
            bodyPart = new MimeBodyPart();
//            "<image src='https://www.baidu.com/img/dong_8f1d47bcb77d74a1e029d8cbb3b33854.gif'/><a herf='https://www.baidu.com'>百度</a>"
            bodyPart.setContent(content, "text/html;charset=utf-8");
            multipart.addBodyPart(bodyPart);//html内容添加

            //因为附件可添加可不添加:
            if (null != files && files.length > 0) {
                for (String file : files) {

                    File temp = new File(file);
                    //添加附件:
                    bodyPart = new MimeBodyPart();//重新将变量调整下指向
                    bodyPart.setDataHandler(new DataHandler(new FileDataSource(temp)));
                    bodyPart.setFileName(temp.getName());
                    //防止中文名称下客户端服务端编码不统一而乱码:
//            bodyPart.setFileName(MimeUtility.encodeText("what.txt"));
                    multipart.addBodyPart(bodyPart);//附件添加
                }
            }
            message.setContent(multipart);

            Transport.send(message);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

main函数:

public class Mail {

    public static void main(String[] args) {

        BeanFactory ad = new ClassPathXmlApplicationContext("spring.xml");
        MailSender mailSender = (MailSender) ad.getBean("mailSender");
        mailSender.sendMail("lingh***com",new String[]{"****cn"},
                "java mail待你查收!",
                "<image src='https://www.baidu.com/img/dong_8f1d47bcb77d74a1e029d8cbb3b33854.gif'/><a herf='https://www.baidu.com'>百度</a>",
                null);
    }
 }
<?xml version='1.0' encoding='UTF-8' ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!--
      引入扫描器 base-package为扫描范围
      并不会全部实例化,需使用注解@Repository(注解在类级别上)
    -->

    <context:component-scan base-package="org.example"/>

</beans>
专题四:AOP
aop概念特点

主要用于日志记录,性能统计,安全控制,事务处理等方面,实现公共功能性的重复使用。
带来的好处:
1:解耦,降低模块间的耦合度(高内聚,低耦合)
2:提高代码的复用性。
3:提高系统的扩展性。

基本概念:

Joinpoint(连接点)
被拦截到的每个点,spring中指被拦截到的每个方法。一个连接点代表一个方法的执行。
Pointcut(切入点)
对连接点进行拦截的定义(匹配规则定义 规定拦截哪些方法。对哪些方法进行处理。)
Advice(通知)
拦截到每一个连接点即(每一个方法)后所要做的操作。
1,前置通知(前置增强)–before()执行方法前通知。
2,返回通知(返回增强)–afterReturn()方法正常结束返回后的通知。
3,异常抛出通知(异常抛出增强)–afterThrow()
4,最终通知–after 无论方法是否发生异常,均会执行该通知
5,环绕通知–around 包围一个连接点的通知,如方法调用。

环绕通知可以在方法调用前后完成自定义的行为。
Aspect(切面)
切入点与通知的结合,决定了切面的定义。切入点定义了要拦截哪些类的哪些方法。
通知则定义了拦截方法后要做什么,切面则是横切关注点的抽象。
Target(目标对象)
被代理的目标对象
Weave(织入)
将切面应用到目标对象并生成代理对象的这个过程。
Introduction(引入)
在不修改原有应用程序代码的情况下,在程序运行期为类动态添加方法或字段的过程。

aop注解实现

因为spring-context引入了aop,还需要在环境中引入aspect-jweaver。

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.9</version>
</dependency>

引用命名空间与xsd

xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"

开启aop环境

<!--
    开启aop环境
-->
<aop:aspectj-autoproxy/>
/**定义切面类
   * 切入点
   * 通知
    */
@Component
@Aspect
public class LogAspect {
    /**定义切入点
     * execution 执行匹配
     * 第一个* public|private|protected这三个访问符修饰的方法
     * ..*代表包以及子包下的所有类  *为通配符,可以为具体值
     * .*(..)代表包以及子包下的所有类的所有方法
     */
    @Pointcut("execution(* org.example..*.myWife(..))")
    public void cut(){}

    @Before(value = "cut()")
    public void before(){
        System.out.println("今天来的人好多,请耐心等待。。");
    }

    @AfterReturning(value = "cut()")
    public void afterReturning(){
        System.out.println("婚礼结束,散场。。");
    }

    @After(value = "cut()")
    public void after(){
        System.out.println("虽然仪器坏了,照样进行。");
    }

    @AfterThrowing(value = "cut()",throwing = "e")
    public void afterThrowing(Exception e){
    System.out.println("仪器坏了,师傅快来修。"+e);
}

    @Around(value="cut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
    Object result = null;
    System.out.println("round方法开始执行。");
    result = pjp.proceed();
    System.out.println("round方法执行结束。");
    Object[] args = pjp.getArgs();
    for (Object arg : args) {
        System.out.println(arg);
    }
    System.out.println(pjp.getSignature());
    System.out.println(pjp.getTarget());

    return result;
    }
}
/**
 * 目标类
 */
@Component
public class MyWedding {

    public void myWife(String prince,String princess){
        System.out.println(String.format("今天的新人婚礼,新郎是%s,新娘是%s。", prince,princess));
    }
}
public class AspectTest {
    public static void main(String[] args) {

        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        MyWedding wedding = (MyWedding) ac.getBean("myWedding");
//        MyWedding wedding = new MyWedding();
        wedding.myWife("张三","李四");
    }
}

在上面程序中,要使用xml加载的bean才可以使用切面。
执行任意公共方法:
execution(public (…))
执行任意的set方法(set开头的):
execution(
set*(…))
执行com.xyz.service包下任意类的任意方法:
execution(* com.xyz.service..(…))
执行com.xyz.service包 以及子包下任意类的任意方法:
execution(* com.xyz.service….(…))

另外一种匹配方式:
匹配注解:
“@annotation(定义注解的路径)”

可以直接标注对哪些方法进行增强。不需要艰难地过滤。

//自定义一个注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
    String name() default "";
}

//切面类
@Pointcut("@annotation(org.example.aspect.MyAnno)")
public void cut(){}

@Around(value="cut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
    Object result = null;
    System.out.println("round方法开始执行。");
    result = pjp.proceed();
    System.out.println("round方法执行结束。");
    Object[] args = pjp.getArgs();
    for (Object arg : args) {
        System.out.println(arg);
    }
    System.out.println(pjp.getSignature());
    System.out.println(pjp.getTarget());

    //展示了如何获取自定义注解的属性:通过Signature的实现类接口
    //调用getMethod获取方法,再获取注解。
    //注解也是对象!
    MethodSignature siture = (MethodSignature) pjp.getSignature();
    Method method = siture.getMethod();
    MyAnno myAnno = method.getAnnotation(MyAnno.class);
    if(null != myAnno){
        System.out.println(myAnno.name());
    }

    return result;


}

//测试方法
public class AspectTest {
    public static void main(String[] args) {

        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        MyWedding wedding = (MyWedding) ac.getBean("myWedding");
//        MyWedding wedding = new MyWedding();
        wedding.myWife("张三","李四");
    }
}

注解属性的使用可以简化编程,比如可以设置权限码之类的。

代理–静态代理实现

代理设计模式
目的:增强目标类的行为
静态代理实现的三要素:
1,接口(共同的行为)
2,目标类(被代理的角色)
3,代理类
与目标类实现共同的行为(与目标类实现同一接口)
增强目标类的行为
持有目标类的引用

例子:Marry为共同接口,下面一个toMarry的方法。
You是目标类,Marry接口的实现类。
MarryCompany是代理类,也实现了Marry这个接口,而且
此代理类持有You对象的引用,因此在MarryCompany的toMarry方法中
可以调用You的toMarry方法,增强You的行为。

public interface IMarry {
    void toMarry();
}
/**
 目标类
 */
public class You implements IMarry{
    @Override
    public void toMarry() {
        System.out.println("等了这么久,终于等到你。。。");
    }
}
/**
 代理类,代理目标类行为
 增强目标类的方法。
 */
public class MarryCompany implements IMarry{

    private IMarry target;

    public MarryCompany(IMarry target) {
        this.target = target;
    }

    public void before(){
        System.out.println("婚礼庆典即将开始。");
    }

    public void after(){
        System.out.println("结婚快乐,早生贵子。");
    }


    @Override
    public void toMarry() {
        //行为增强
        before();
        target.toMarry();
        //行为增强
        after();
    }
}
public class TestStaticProxy {
    public static void main(String[] args) {
        MarryCompany marryCompany = new MarryCompany(new You());

        marryCompany.toMarry();
    }
}

静态代理的特点:

1,程序运行前,需要应用程序制作代理角色
2,代理的目标类 类型固定。
3,缺陷:对于每一类接口,如果需要作代理,应用程序需要提供大量的代理类
随着应用程序的复杂度上升,代理类的数据越来越大,维护比较麻烦。

多线程是静态代理的应用

代理–动态代理实现–JDK实现

动态代理最明显特点:在程序运行期为目标类动态地创建代理角色。

实现方式:

1,JDK内部

要求目标类必须存在接口实现。目标类不存在接口实现,无法创建代理对象。

(代理类是跟目标类平级的,不能用目标类来转换对象)

public static Object newProxyInstance(ClassLoader loader, //因为是动态代理,需要加载器

                                      Class<?>[] interfaces,        //目标类所有实现的接口

                                      InvocationHandler h)   //一个接口,值钱的就是下面这个准重写方法。

invoke(Object proxy,Method method,Object[] args)

返回指定接口的代理实例,该代理实例将方法调用分派给指定的调用处理程序。

二合一写法:

/**
 * 仅仅用于产生动态代理类并且实现InvokeHandler
 */
public class JdkHandler implements InvocationHandler {
    //目标类
    private Object target;

    public JdkHandler(Object target) {
        this.target = target;
    }

    public Object getProxy(){
        /*1,类加载器
        2,目标类实现的所有接口数组
        3,实现类InvocationHandler接口的类实例*/
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    public void before(){
        System.out.println("婚礼庆典即将开始。");
    }

    public void after(){
        System.out.println("结婚快乐,早生贵子。");
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        before();
        Object result = null;
        //执行目标类的方法:
        result = method.invoke(target,args);
        after();
        return result;
    }
}

用接口来接收代理类。

public class TestDynamicProxyJdk {

    public static void main(String[] args) {
        JdkHandler jdkHandler = new JdkHandler(new You());
        //采用父类来接收参数
        IMarry dynamicProxy = (IMarry) jdkHandler.getProxy();
        dynamicProxy.toMarry();
    }
}
/**

 目标类
 */
public class You implements IMarry{
    @Override
    public void toMarry() {
        System.out.println("等了这么久,终于等到你。。。");
    }
}

目标类必须实现了接口。

public interface IMarry {
    void toMarry();
}

代理类与目标类不能相互转换。 因此JDK无法满足给没有接口实现的目标类做代理的需求。

代理–动态代理–CGLIB实现

对于目标类是否存在接口实现没有要求(继承思想)
代理类属于目标类的子类。因此目标类可以引用代理类。
引用环境

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib-nodep</artifactId>
  <version>3.3.0</version>
</dependency>

通过Enhancer这个类来实现:
此类有个create方法,需要设置两个参数(superclass以及callback)
callback为一个接口,使用其实现接口MethodInterceptor。

public class CGLibHandler implements MethodInterceptor {

    private Object target;

    public CGLibHandler(Object target) {
        this.target = target;
    }

    public Object getProxy(){
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        //返回代理类
        return enhancer.create();
    }

    public void before(){
        System.out.println("婚礼庆典即将开始。");
    }

    public void after(){
        System.out.println("结婚快乐,早生贵子。");
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object result = null;
        before();
        result = methodProxy.invoke(target, objects);
        after();
        return result;
    }
}

用目标类You来接收动态代理。

public class TestDynamicProxyJdk {

    public static void main(String[] args) {
        CGLibHandler cgLibHandler = new CGLibHandler(new You());
        //获取动态代理
        You youproxy = (You) cgLibHandler.getProxy();
        //多态,执行子类方法
        youproxy.toMarry();
    }
}

JDK制作动态代理时,制作效率较高。
AOP内部实现原理是JDK+CGLib。如果目标类有接口实现,采用JDK,如果没有,使用CGLib。

专题五:定时任务
1:概述

二叉树:有多种类型,分为满二叉树与完全二叉树。完全二叉树是指除了最后一层,其他层都是满节点,且最后一层节点靠左。
堆:堆是一种完全二叉树,且任何一个节点都不大于(或者不小于)父节点的值。
小顶堆:完全二叉树且每一节点都不小于父节点的值。
堆的存取:存在数组里面,第一个数组元素不放值,这样下标除二得到父节点位置。存的时候存在最后面,然后上浮。取的时候取最上面的,然后将最后一个值填充到第一个,然后下沉。
定时任务用到小顶堆,每个节点存放一个任务,当任务量巨大时会耗性能。
时间轮:round型时间轮,依然会遍历每个数组。分层时间轮将月轮与天轮分开,方便简洁。
实现定时器的大概有几种方式,一个是JDK自带的timer。
Timer的使用:(单线程+小顶堆)

package com.hxh.timer;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 *
 * 问题是由单线程的任务阻塞引起的。
 * task.run()方法导致的,单线程任务阻塞导致。
 * 在run方法中使用多线程,另起线程,线程池即可。
 *
 * 对系统时间比较敏感,任务调度基于绝对时间。
 *
 * TaskQueue小顶堆
 */
public class TimerTest {

    public static void main(String[] args) {

        Timer timer = new Timer();//任务启动
        for (int i=0;i<2;i++){
            TimerTask timerTask =new FooTimerTask("foo"+i);
            //中间参数,立即启动
//            timer.schedule(timerTask,new Date(),2000);//任务添加,真正的执行时间取决于上一个任务执行的时间。
            //任务超时时,schecule存在丢任务的风险,执行周期小于(时间推迟了就是丢任务了。)

            //任务超时时,scheduleAtFixedRate严格按照period执行。但是会导致任务执行混乱掉。
            timer.schedule(timerTask,new Date(),8000);//优先使用这个函数,多个任务执行时间小于period

        }
    }
}
class FooTimerTask extends TimerTask{

    private String name;

    public FooTimerTask(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        try {
            System.out.println("name ---> "+name+" ,startTime"+new Date());
            Thread.sleep(3000);
            System.out.println("name ---> "+name+" ,endTime"+new Date());

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

线程池的使用(多线程+小顶堆)

package com.hxh.pool;

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 定时任务线程池
 * 在timer的基础上做了优化
 *
 *小顶堆
 * leader-follower模式:只有leader线程执行任务,
 * 其他follower线程等待变为leader线程,避免没必要的唤醒与阻塞操作。
 *
 * 任务同时启动,如果任务超时间隔周期,则任务结束后会立即启动。
 *
 */
public class ScheduleThreadPoolTest {

    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorPool = Executors.newScheduledThreadPool(5);
        for (int i=0;i<2;i++){
            //需要一个Runnable command
            //.schedule未传间隔时间,只执行一次,需要用到
            //.scheduleAtFixedRate可设置间隔时间
            scheduledExecutorPool.scheduleAtFixedRate(new Task("masaka--"+i),0,4, TimeUnit.SECONDS);
        }


    }

}

class Task implements Runnable{

    private String name;

    public Task(String name) {
        this.name = name;
    }
    @Override
    public void run() {
        try {
            System.out.println("name ---> "+name+" ,startTime"+new Date());
            Thread.sleep(3000);
            System.out.println("name ---> "+name+" ,endTime"+new Date());

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
2:quartz

并发任务,且每次创建一个新的job实例。可以规避并发访问的问题。

@DisallowConcurrentExecution

这个注解无视执行触发时间间隔,只有j每次的job执行完毕后,下一个才开始。

@PersistJobDataAfterExecution

让JobData持久化,可以递增一些data,这两个注解标注在Job任务上,但是后者只对jobDetail里的.usingJobData有效。如果一个任务不是持久化的,则当没有触发器关联它的时候,Quartz会从schedule中删除它。

trigger里的usingJobData会覆盖jobDetail里的同key值data。

trigger的其他内容:

同时触发的trigger之间才会比较优先级,如果trigger是可恢复的,在恢复后再调度时,优先级不变。

misfire错过触发:判断misfire的条件:1,job达到触发时间没有被执行;2,被执行的延迟时间超过了Quartz配置的misfire Threshold。

3:时间解析
//如何将UTC统一时间规范化。
String timmi = "2020-12-22T06:18:55.592Z";
SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

Date date1 = df1.parse(timmi);
String date2 = df2.format(date1);
System.out.println(date1);//Tue Dec 22 06:18:55 CST 2020
System.out.println(date2);//2020-12-22 06:18:55
System.out.println(date1.getTime());//long 1608589135592
Timestamp timestamp = new Timestamp(date1.getTime());//根据long类型建立实例
System.out.println(timestamp.getTime());//输出1608589135592
System.out.println(timestamp.toLocalDateTime());//2020-12-22T06:18:55.592
System.out.println(timestamp);//2020-12-22 06:18:55.592
System.out.println(timestamp.toString());//自身toString长这个样子。2020-12-22 06:18:55.592

String hxh1 = Long.toString(1608589135592L);
String hxh2 = String.valueOf(1608589135592L);

//*******************************************
//项目使用:
String timmi = "2020-12-22T06:18:55.592Z";
SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
Date date1 = df1.parse(timmi);
Timestamp timestamp = new Timestamp(date1.getTime());
//再把timestamp插入到数据库。
//将时间的日期插入到sql中。
java.sql.Date sql_date = new java.sql.Date(date1.getTime());
System.out.println(sql_date);//输出2020-12-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值