栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

12-2107课上问题分析及总结

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

12-2107课上问题分析及总结

文章目录
  • Day01~微服务架构入门
    • 核心知识点
    • 常见问题分析
    • 常见Bug分析
    • 课后作业
    • 作业答案
  • Day02~Nacos 注册中心入门
    • 核心知识点
    • 常见问题分析
    • 常见Bug分析
    • 课后作业
  • Day03~服务发现及调用
    • 核心知识点
    • 常见问题分析
    • 常见Bug分析
    • 课后作业
    • 作业答案
  • Day04~Nacos 配置中心入门
    • 核心知识点
    • 常见问题分析
    • 常见Bug分析
    • 课后作业
  • Day05~Nacos配置管理模型
    • 核心知识点
    • 常见问题分析
    • 常见Bug分析
    • 课后作业
    • 作业答案
  • Day06~Sentinel应用入门
    • 核心知识点
    • 常见问题分析
    • 常见Bug分析
    • 课后作业
    • 作业答案
  • Day07~Sentinel应用进阶
    • 核心知识点
    • 常见问题分析
    • 常见Bug分析
    • 课后作业
    • 作业答案

Day01~微服务架构入门 核心知识点
  • 微服务架构诞生的背景(分而治之~北京一个火车站到多个火车站)
  • 微服务架构解决方案(大厂自研,Spring Cloud ~Netflix,Alibaba,…)
  • 微服务架构下Maven项目的创建方式?(Maven聚合项目~资源复用,简化编译,打包,部署方式)
  • 微服务架构入门聚合项目创建?(01-sca,sca-consumer,sca-provider,sca-gateway,sca-common)
常见问题分析
  • 为什么需要微服务?(对系统分而治,解决因并发访问过大带来的系统复杂性(例如:业务,开发,测试,升级,可靠性等)
  • 微服务设计的特点?(单一职责,独立进程,开发测试效率高,可靠性高,升级难度小,但会带来一定的维护成本)
  • 微服务解决方案有哪些?(大厂自研,中小企业采用开源Spring Cloud Alibaba,Spring Cloud Netfix等 )
  • 微服务设计中需要哪些关键组件(服务的注册,发现,配置,限流降级,访问入口管理,分布式事务管理等)
  • 创建聚合工程的目的?(实现工程之间资源的的共享)
  • 如何修改聚合工程中项目的编译和运行版本?(build->plugins->plugin->maven-compiler-plugin)
  • maven工程中build元素的作用?(定义项目的编译,打包方式)
  • maven父工程的packaging元素内的值是什么?(pom)
  • maven父工程中dependencyManagement元素的作用是什么?(定义项目的版本)
常见Bug分析
  • 依赖或插件无法下载或加载?(本地库冲突,网络不好,maven镜像配置,指定版本在远程服务器不存在,清idea缓存后重启)
  • 项目的pom.xml文件有删除线?(idea/setting/build,Execution,Deployment/build Tools/maven/ignore Files)
课后作业
  • 基于原有工程结构,在01-sca工程下创建sca-common工程.
  • 在sca-provider工程中引入sca-common工程依赖.
  • 在sca-provider工程中使用sca-common工程中的一些公共类(例如StringUtils.java)
  • 检查自己电脑环境是否配置了JAVA_HOME环境变量?(set JAVA_HOME)
  • 检查自己电脑环境中的JVM虚拟机是否为64位的?(java -version)
  • 检查自己电脑环境中mysql的版本是否为5.7以上?(假如是MariaDB ,建议10.5以上)
  • 预习Nacos服务注册中心相关内容.
作业答案
  • sca-common 工程创建,例如:
  • sca-provider 工程引入sca-common工程依赖
   
        
        
            com.jt
            sca-common
            1.0-SNAPSHOT
        
    
  • sca-provider工程中使用sca-common工程公共类StringUtils.java
    第一步:在sca-common工程中创建StringUtil.java工具类,例如:
package com.jt.common.util;

public class StringUtils {
    
    public static boolean isEmpty(String str){
        return str==null||"".equals(str);
    }
}

第二步:在sca-provider工程中添加spring-boot-start依赖,例如:


    org.springframework.boot
    spring-boot-starter

第三步:在sca-provider工程中的test目录下定义单元测试类,并进行测试,例如:

package com.example;
import com.jt.common.util.StringUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootConfiguration //(假如工程中有启动类,注解就不需要加了)
@SpringBootTest
public class StringTests {
    
    @Test
    void testStringEmpty(){
        String content="helloworld";
        boolean flag= StringUtils.isEmpty(content);
        System.out.println(flag);
    }
}
  • 检查自己电脑的JAVA_HOME环境变量?
    方式1:打开电脑的命令行窗口,输入set JAVA_HOME 指令,例如:

    方式2:假如是window平台还可以通过,如下方式进行检查,例如:

  • 检查自己电脑环境中的JVM虚拟机是否为64位的,例如:

  • 登录mysq,检查mysql或maridb的版本,例如:

Day02~Nacos 注册中心入门 核心知识点
  • 注册中心诞生的背景? (所有公司需要在工商局进行备案)
  • 注册中心的选型?(社区活跃度,稳定性,功能,性能,学习成本)
  • Nacos下载,安装,配置,启动,访问(http://ip:port/nacos)
  • 服务向Nacos的注册?(添加依赖,服务配置,启动服务并检查)
  • Nacos进行服务监控的方式?(心跳包)
  • 服务(进程)之间的调用?(借助RestTemplate.思考Spring中的JdbcTemplate,SqlSessionTemplate等对象的作用)
常见问题分析
  • 注册中心诞生的背景? (服务多了,需要对服务进行更好管理)
  • 市场上常用的注册中心?(Zookeeper,Eureka,Nacos,Consul)
  • 如何对注册中心进行选型?(社区活跃度,稳定性,功能,性能,学习成本)
  • Nacos 是什么?(是Alibaba公司基于SpringBoo技术t实现的一个注册中心,本质上也是一个服务)
  • Nacos 的基本架构?(Client/Server架构)
  • Nacos 主要提供了什么核心功能?(服务的注册,发现,配置)
  • Nacos 服务启动需要什么前置条件?(配置JDK的JAVA_HOME目录,安装MySQL5.7以上版本,配置连接的数据库)
  • Nacos 服务单机模式,window平台下启动时的指令是什么?(startup.cmd -m standalone)
  • 实现Nacos服务注册需要添加什么依赖?(两个)
  • 实现Nacos服务注册时,必须做哪些配置?(服务名,假如是本机服务注册可以省略服务地址)
  • Nacos如何检查服务状态?(通过心跳包实现)
  • 服务之间进行服务调用时,使用了什么API?(RestTemplate)
常见Bug分析
  • JAVA_HOME环境变量定义错误,例如:

    说明,这里一定要注意JAVA_HOME单词的拼写,JAVA_HOME中定义的JDK是存在的.

  • MySQL版本比较低,例如:
    当执行nacos-mysql.sql文件时,出现如下错误:

  • SQL文件应用错误,例如:

  • Nacos的application.properties配置文件中,连接数据库的配置错误.

  • 服务注册时,服务名不正确,例如:

  • Nacos 服务注册失败,例如

  • 客户端500异常,例如

  • 服务调用时,连接异常,例如:

  • 服务调用时底层404问题,例如:

课后作业
  • 重新创建新的聚合项目(例如10-sca)
  • 重新实现服务的注册和调用(ca-consumer调用ca-provider)
  • 尝试完成负载均衡方式的服务调用(参考博客文档)
Day03~服务发现及调用 核心知识点
  • 基于LoadBalancerClient 实现服务发现和负载均衡
  • @Loadbalanced注解的作用以及应用分析
  • Feign方式的服务调用实践
常见问题分析
  • 何为服务发现?(从nacos获取服务实例)
  • LoadBalancerClient的作用?(从nacos获取服务实例列表,然后本地基于负载均衡算法获取服务实例)
  • @Loadbalanced作用?(描述RestTemplate对象,让系统底层为RestTemplate对象赋能)
  • Feign是什么?(Spring Cloud微服务规范中的一组远程调用API)
  • 为什么使用Feign?(优化服务调用结构)
  • 如何使用Feign实现服务调用?(依赖,@EnableFeignClients,@FeignClient)
  • Feign方式的服务调用原理是怎样的?(底层基于代理对象实现)
常见Bug分析
  • 服务启动时端口被占用,例如:
  • RestTemplate对象应用错误,例如:
  • @Autowired描述的属性有红色下划波浪线,例如:
  • 依赖注入(DI)问题,例如

  • 服务名应用问题,例如:

  • Feign 接口方法中@PathVariable注解应用问题.
课后作业
  • 总结微服务中的服务发现及调用方式.
  • 构建一个简易的Browser/Tomcat对象,实现两个对象的网络通讯(了解).
  • 预习@FeignClient中fallbackFactory注解的应用.
  • 预习Nacos配置中心.
作业答案
  • 服务调用方式总结,例如:
  • 简易Browser/Tomcat对象实现?(Java中的网络通讯需要借助Socket/ServerSocket对象)
    第一步:构建Tomcat对象,例如:
package com.jt.common.net;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Tomcat {//企业规范
    public static void main(String[] args) throws IOException {
        //1.创建服务(例如:启动nacos,启动....),并在9999端口进行监听
        //网络中计算机的唯一标识是什么?ip
        //计算机中应用程序的唯一标识是什么?port
        ServerSocket server=new ServerSocket(9999);
        System.out.println("server start ...");
        //2.启动服务监听
        while(true){
            //监听客户端的链接(这里的socket代码客户端对象)
            Socket socket=server.accept();//阻塞方法
            //在这里可以将socket对象的信息记录一下.(服务注册)
            //创建输出流对象,向客户端输出hello client
            OutputStream out =
                    socket.getOutputStream();
            //byte[] responseContent="hello client".getBytes();
            byte[] responseContent=("HTTP/1.1 200 ok rn" +
                    "Content-Type: text/html;charset=utf-8 rn" +
                    "rn" +
                    "hello client").getBytes();
            out.write(responseContent);
            out.flush();
        }
    }
}

第二步:构建Browser对象,例如:

package com.jt.common.net;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

public class Browser {
    public static void main(String[] args) throws IOException {
        //1.创建网络编程中的客户端对象(Socket)
        //构建Socket对象时要执行连接个计算机(ip),访问计算机中的哪个应用(port)
        Socket socket=new Socket("127.0.0.1",9999);//TCP
        //2.创建一个输入流对象,读取服务端写到客户端的数据
        InputStream in = socket.getInputStream();
        byte[] buf=new byte[1024];
        int len=in.read(buf);
        String content=new String(buf,0,len);
        System.out.println(content);
        //3.释放资源
        socket.close();
    }
}

第三步:运行tomcat和Browser,检测Browser输出.
也可以打开,浏览器直接访问http://localhost:9999

Day04~Nacos 配置中心入门 核心知识点
  • 配置中心诞生的背景(分布式架构下如何动态发布和更新配置)
  • 市场上主流的配置中心(Nacos,…)
  • Nacos配置中心的基本应用(添加依赖,修改配置文件名以及内容,新建配置,应用配置)
    *@RefreshScope注解的应用(描述类,实现类中属性值@Value与配置中心中内容的同步)
常见问题分析
  • 为什么要使用配置中心?(项目上线后实现配置的动态发布和更新)
  • 你知道哪些主流配置中心?
  • Nacos配置中心如何应用?
  • Java项目中你用的日志API是什么?(org.slf4j.Logger)
  • 你项目中为什么使用org.slf4j.Logger对象记录日志?此对象是日志规范,是对外面的门面,可以更好降低耦合
  • @Slf4j注解的作用是什么?(此注解属于lombok,用于描述类,在类中创建org.slf4j.Logger对象)
  • 你知道Java中有哪些常用日志级别?(debug
  • Java日志在设计时为什么要设计日志级别?(方便根据级别调整日志输出)
  • Java中日志级别的配置通常要写到哪里?(配置中心)
  • 你觉得Nacos配置中心通常会配置哪些内容?(可能经常变化的数据)
  • Nacos配置中心依赖对项目中配置文件的名字有要求吗?(bootstrap.yml)
  • Nacos中@RefreshScope注解的应用场景以及作用.
  • 如何在初始化对象属性时从配置中心读取配置内容?(@Value注解对属性进行描述)
常见Bug分析
  • idea连接database,例如mysql.(可以baidu,然后输入idea database进行复合查询)



  • 配置文件或配置文件格式不正确,例如:

  • @Value注解包引入错误,例如:

    *@Value配置读取不到,例如:

课后作业
  • 总结课上知识点,并尝试重新构建项目进行配置实践.
  • 将Nacos配置入门章节的小节节面试仔细读一遍.
  • 预习Nacos的配置模型.
Day05~Nacos配置管理模型 核心知识点
  • 配置管理模型存在的意义
  • 配置管理模型三要素及其要素关系
  • Nacos中读取指定命名空间和分组下的配置
  • Naocs中的共享配置的设计(对很多配置文件中的共性的一种提取方式)
常见问题分析
  • 如何理解配置的命名空间(Namesapce)?(定义一些配置的作用域,做配置的分类管理,不同环境不同配置)
  • 为什么要进行配置分组?(一个命名空间可以有多个分组,同一个生产环境下的不同活动会有不同配置)
  • 配置中心运行有共享配置吗,如何引用?(可以,基于shared-configs元素进行引用)
  • Java程序中读取不到配置?(依赖,配置文件,命名空间,分组,data-id,空格,缩进,重启,放大招)
常见Bug分析
  • @Value("${logging.level.com.jt}") 读取不到值?(先检查你是否有这个配置,假如没有可以给定一个默认值)
  • 线程(Thread)安全问题?(多个线程,共享数据集,原子操作)
  • 如何理解线程并发中的双重校验?(既要保证安全,又要保证效率)
  • 如何理解定时任务?(让线程对象在规定的时间范围内自动去执行任务,例如配置信息的定时刷新)
课后作业
  • 总结课上内容(命名空间,分组,共享配置)
  • 基于Timer对象实现定时任务调度(单线程有顺序的任务调度)
  • 基于ScheduledExecutorService实现一个任务调度(课后拓展,Nacos中的定时心跳,配置长轮询都是基于这个对象)
  • 在ProviderCacheController类中添加一个本地Cache(基于CopyOnWriteArrayList对象实现)
  • 基于双重校验机制,实现类的单实例设计(拓展,自己尝试实现).
  • 预习Sentinel章节的限流操作(北京市为什么要限号)
作业答案
  • 基于Timer对象实现定时任务调度,例如:
package com.jt.common.util;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;


public class TimerUtils {
    public static void main(String[] args) {
        //1.构建执行任务的对象(这里选择java中的Timer对象)
        //Timer对象创建时会创建一个线程,并且为线程分配一个任务队列
        Timer timer=new Timer();
        //2.构建任务对象
        TimerTask task1=new TimerTask() {
            @Override
            public void run() {
                System.out.println(System.currentTimeMillis());
                //timer.cancel(); 结束任务调度
            }
        };
        //3.定时执行任务
        timer.schedule(task1,//要执行的任务
                1000,//1秒以后开始执行
                1000);//每隔1秒执行1次
        //基于Timer类执行定时任务时,最大的缺陷是多个任务不能并发执行.
    }
}
  • 基于ScheduledExecutorService实现一个任务调度,例如:
package com.jt.common.util;

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


public class ScheduledExecutorServiceTests {
    public static void main(String[] args) {
        //构建一个负责任务调度的线程池对象,池中最多有三个核心线程
        ScheduledExecutorService ses=
                Executors.newScheduledThreadPool(3);
        //构建任务对象
        Runnable task=new Runnable() {
            @Override
            public void run() {
                String tName=Thread.currentThread().getName();
                System.out.println(tName+"->"+System.currentTimeMillis());
            }
        };
        //执行任务对象(定时任务调度):1秒以后开始执行,每隔1秒执行1次
        ses.scheduleAtFixedRate(task,
                    1,//初始延迟
                    5,//每隔1秒启动1次(与任务是否执行结束无关)
                    TimeUnit.SECONDS);//时间单位
    }
}
  • 在ProviderCacheController类中添加一个本地Cache对象,在保证其线程安全的前提下,提高其性能.
   //构建一个本地(Local)缓存对象(基于jvm中的一个对象存储从数据库获取的数据).
    private List cache=new CopyOnWriteArrayList<>();
    @RequestMapping("/provider/cache02")
    public  List doUseLocalCache02(){
        if(!useLocalCache){//假如没有打开本地Cache,则直接访问数据库
            System.out.println("==Get data from database==");
            return Arrays.asList("Category-A", "Category-B", "Category-C");
        }
        if(cache.isEmpty()) {
            synchronized (cache) {
                if (cache.isEmpty()) {//Thread-A,Thread-B,...
                    System.out.println("==Get data from database==");
                    //假设这部分分类信息是从数据库获取的,但是,我不希望每次获取分类信息都要从数据库查
                    List cates = Arrays.asList("Category-A", "Category-B", "Category-C");
                    cache.addAll(cates);
                }
            }
        }
        return cache;
    }//生产层面
  • 基于双重校验机制,实现类的单实例设计,例如:
package com.jt.common.thread;


class Singleton{
    private Singleton(){}
    private static Singleton instance;
    public static Singleton getInstance(){
        if(instance==null) {
            synchronized (Singleton.class) {
                if (instance == null) {//双重校验
                    instance = new Singleton();
                }
            }
        }
        return  instance;
    }
}

public class SingleTests {
    public static void main(String[] args) {
        Thread t1=new Thread(){
            @Override
            public void run() {
                System.out.println(Singleton.getInstance());
            }
        };
        Thread t2=new Thread(){
            @Override
            public void run() {
                System.out.println(Singleton.getInstance());
            }
        };
        Thread t3=new Thread(){
            @Override
            public void run() {
                System.out.println(Singleton.getInstance());
            }
        };
        t1.start();
        t2.start();
        t3.start();
    }
}
Day06~Sentinel应用入门 核心知识点
  • 限流的背景
  • Sentinel限流入门(控制台8180-定义规则,客户端服务应用规则:依赖,配置)
  • Sentinel常用限流模式(直接,关联,链路)
  • Sentinel降级入门实现(暂停对服务的访问)
常见问题分析
  • 为什么要进行限流? (系统处理能力有限,可以通过限流方式,保证系统可靠运行)
  • Sentinel限流的基本原理?(底层对请求进行拦截,然后通过流控规则限定对资源访问)
  • Sentinel限流有哪些算法? (计数器,令牌桶,漏桶,滑动窗口算法~sentinel默认)
  • Sentinel常用限流效果有哪些?(快速失败,预热,排队)
常见Bug分析
  • sentinel 服务启动不起来?(要使用JDK8)
  • sentinel 面板不显示我们的服务?(依赖,配置,访问,大招)
课后作业
  • 总结课上知识点.
  • 了解常用限流算法.
  • 尝试基于@SentinelResource注解描述的方法进行限流结果的定义?
  • 预习sentinel降级异常处理,Sentinel热点规则设计,授权设计.
作业答案
  • 基于@SentinelResource注解描述的方法进行限流结果的定义.

第一步:定义blockHandlerClass,例如:

package com.jt.provider.service;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class ResourceBlockHandler {
    
    public static String call(BlockException ex){
        log.error("block exception {}", ex.getMessage());
        return "访问太频繁了,稍等片刻再访问";
    }
}

第二步:修改@SentinelResource注解中的属性定义,例如:

@SentinelResource(value="doGetResource",
        blockHandlerClass = ResourceBlockHandler.class,
        blockHandler = "call")
public String doGetResource(){
    return "do get resource";
}

第三步:在controller方法中,调用@Sentinel注解描述的方法,例如:

@GetMapping("/sentinel03")
public String doSentinel03(){
   return resourceService.doGetResource();
   //return "sentinel 03 test";
}
Day07~Sentinel应用进阶 核心知识点
  • Sentinel 异常处理
  • Sentinel 热点数据限流
  • Sentinel 系统规则应用实践
  • Sentinel 授权规则应用实践
  • Sentinel 拦截器应用原理分析
常见问题分析
  • 为什么要进行异常处理?(提高用户体验)
  • Sentinel中限流,降级的父类异常类型是什么?(BlockException)
  • Sentinel中默认的BlockException处理对象是谁?(DefaultBlockException)
  • 如何自己定义Sentinel的异常处理对象?(直接或间接继承BlockExceptionHandler)
  • 如何理解热点数据以及限流的方式是什么?(经常访问的数据,基于参数或参数值进行限流)
  • 如何理解sentinel中的系统规则?(全局限流规则,基于QPS,CPU,…)
  • 如何理解Sentinel中的授权规则?(黑白名单)
常见Bug分析
  • 请求被限流时出现500异常?
  • 异常处理对象没有交给Spring管理(例如类使用@Common修饰)
课后作业
  • 总结课上sentinel应用规则
  • 实践Spring MVC中的拦截器应用(重点)
  • 手写一个简易的框架执行链(了解)
  • 预习微服务中的Gateway组件.
作业答案
  • 基于Spring MVC中的拦截器实现对控制方法进行时间访问控制?
package com.jt.provider.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalTime;

public class TimeInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("===preHandle===");
        //业务:允许在8点之后,晚9点之前可访问
        LocalTime now = LocalTime.now();//获取当前时间,
        int hour = now.getHour();//获取当前时间的小时单位
        if(hour<8||hour>=21)
            throw new RuntimeException("请在规定时间访问8~21");
        return true;
    }
}

第二步:配置拦截器,例如:

package com.jt;
import com.jt.provider.interceptor.TimeInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class SpringWebConfig implements WebMvcConfigurer {
    //注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TimeInterceptor())
                .addPathPatterns("/provider/sentinel01");
    }
}

第三步:对/provider/sentinel01路径按时间段进行访问,检测拦截器的执行.

  • 手写一个简易的框架执行链(了解),模拟框架中执行链的设计,例如:
package com.jt.common.interceptor;

import javax.xml.transform.Source;
import java.time.LocalTime;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;


//拦截器接口
interface HandlerInterceptor{
    default void before(){}//定义在目标handler方法执行之前执行
    default void after(){}//定义在目标handler方法之后执行
}
//处理器接口
interface Handler{
    void processed();//处理业务的方法
}
//定义一个执行链
class ExecutionChain{//我是执行链的设计者
    //一些拦截器
    private List interceptors=
            new CopyOnWriteArrayList<>();
    //业务处理器
    private Handler handler;
    public ExecutionChain(List interceptors,Handler handler){
           this.handler=handler;
           this.interceptors.addAll(interceptors);
    }
    public void execute(){//负责执行业务的方法(例如处理请求)
        //1.before
        for(int i=0;i=0;i--){
            interceptors.get(i).after();
        }
    }
}
public class frameworkTests {//框架应用者
    public static void main(String[] args) {
        //应用执行链
        //1.创建拦截器
        List interceptors=new CopyOnWriteArrayList<>();
        HandlerInterceptor interceptor=new HandlerInterceptor() {
            @Override
            public void before() {
                System.out.println("记录考试开始时间:"+ LocalTime.now());
            }
            @Override
            public void after() {
                System.out.println("记录考试结束时间:"+ LocalTime.now());
            }
        };
        interceptors.add(interceptor);
        //2.创建处理
        Handler handler=new Handler() {
            @Override
            public void processed() {
                System.out.println("同学们开始考试");
            }
        };
        //3.创建执行链
        ExecutionChain chain=
        new ExecutionChain(interceptors,handler);
        //4.执行执行链
        chain.execute();
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/354270.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号