精华内容
下载资源
问答
  • 专业的数据库存储解决方案,线程安全,高性能的模型对象存储Sqlite开源库,实现一行代码的数据库操作,简单的数据库存储 专业的数据库存储解决方案,线程安全,高性能模型对象存储Sqlite开源库,真正实现一行代码...
  • 一、申请对象存储OSS 为了解决海量数据存储与弹性扩容,项目中我们采用云存储的解决方案- 阿里云OSS。 1、开通“对象存储OSS”服务 (1)申请阿里云账号 (2)实名认证 (3)开通“对象存储OSS”服务 (4)进入管理...

    一、申请对象存储OSS

    为了解决海量数据存储与弹性扩容,项目中我们采用云存储的解决方案- 阿里云OSS。
    1、开通“对象存储OSS”服务
    (1)申请阿里云账号
    (2)实名认证
    (3)开通“对象存储OSS”服务
    (4)进入管理控制台
    2、创建Bucket
    选择:标准存储或低频访问存储(根据实际需要)、公共读、其余功能一律不开通(开通要收费)
    在这里插入图片描述
    在这里插入图片描述
    3、生成自己专属的访问权限的Access key,点击进入创建即可;后面当需要上传文件到OSS需要bucket名称、keyId和keySecret
    在这里插入图片描述

    二、Java后端集成OSS(SpringBoot工程)

    1、引入依赖
    在工程依赖中添加下面两个核心依赖

    	<dependencies>
            <!-- 阿里云oss依赖 -->
            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>3.1.0</version>
            </dependency>
    
            <!-- 日期工具栏依赖 -->
            <dependency>
                <groupId>joda-time</groupId>
                <artifactId>joda-time</artifactId>
                <version>2.10.1</version>
            </dependency>
        </dependencies>
    

    2、配置application.properties

    #服务端口
    server.port=8002
    #服务名
    spring.application.name=service-oss
    
    #环境设置:dev、test、prod
    spring.profiles.active=dev
    
    #阿里云 OSS
    #不同的服务器,地址不同
    aliyun.oss.file.endpoint=你的OSS地域(例:oss-cn-shanghai.aliyuncs.com)
    aliyun.oss.file.keyid=你的keyId
    aliyun.oss.file.keysecret=你的KeySecret
    #bucket可以在控制台创建,也可以使用java代码创建
    aliyun.oss.file.bucketname=你的bucket名
    

    3、SpringBoot启动类
    本次是用不到数据库配置所以将DataSourceAutoConfiguration移除,否则可能会报错

    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
    @ComponentScan(basePackages = {"com.atguigu"})
    public class OssApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OssApplication.class, args);
        }
    }
    

    4、从配置文件读取常量

    /**
     * 常量类,读取配置文件application.properties中的配置
     *
     * @author chengw
     * @since 2020-12-7
     */
    @Component
    public class ConstantPropertiesUtil implements InitializingBean {
    
        //当项目一启动,属性读取配置文件获得值后会执行重写的InitializingBean接口的方法
        //读取配置文件中的内容
        @Value("${aliyun.oss.file.endpoint}")
        private String endpoint;
    
        @Value("${aliyun.oss.file.keyid}")
        private String keyId;
    
        @Value("${aliyun.oss.file.keysecret}")
        private String keySecret;
    
        @Value("${aliyun.oss.file.bucketname}")
        private String bucketName;
    
        //类ConstantPropertiesUtil的属性均为私有,所以再类中定义一些常量供  类之外使用
        public static String END_POINT;
        public static String ACCESS_KEY_ID;
        public static String ACCESS_KEY_SECRET;
        public static String BUCKET_NAME;
    
        @Override
        public void afterPropertiesSet() throws Exception {
            END_POINT = endpoint;
            ACCESS_KEY_ID = keyId;
            ACCESS_KEY_SECRET =keySecret;
            BUCKET_NAME = bucketName;
        }
    }
    

    5、实现文件上传的Service实现类

    @Service
    public class OssServiceImpl implements OssService {
    
        @Override
        public String uploadFileAvatar(MultipartFile file) {
            String endPoint = ConstantPropertiesUtil.END_POINT;
            // 云账号AccessKey有所有API访问权限
            String accessKeyId = ConstantPropertiesUtil.ACCESS_KEY_ID;
            String accessKeySecret = ConstantPropertiesUtil.ACCESS_KEY_SECRET;
            String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
    
            String uploadUrl = null;
    
            try {
                // 创建OSSClient实例
                OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
                if (!ossClient.doesBucketExist(bucketName)) {   判断oss实例是否存在:如果不存在则创建
                    //创建bucket
                    ossClient.createBucket(bucketName);
                    //设置oss实例的访问权限:公共读
                    ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
                }
    
                // 获取上传文件输入流
                InputStream inputStream = file.getInputStream();
    
                //构建日期层级文件夹:2020/12/07
                String filePath = new DateTime().toString("yyyy/MM/dd");
    
                //文件名:uuid.扩展名
                String original = file.getOriginalFilename();
                String fileName = UUID.randomUUID().toString();
                String fileType = original.substring(original.lastIndexOf("."));
                String newName = fileName + fileType;
                //上传文件在OSS中存储位置:2020/12/07/uuid随机数.扩展名
                String fileUrl = filePath + "/" + newName;
    
                //调用OSS方法实现上传
                ossClient.putObject(bucketName, fileUrl, inputStream);
    
                // 关闭OSSClient
                ossClient.shutdown();
    
                //获取url地址:https://chengw-guli.oss-cn-shanghai.aliyuncs.com/wangzai.jpg
                uploadUrl = "https://" + bucketName + "." + endPoint + "/" + fileUrl;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return uploadUrl;
        }
    }
    

    5、实现文件上传的Controller实现类

    @RestController
    @RequestMapping("/eduoss/fileupload")
    @CrossOrigin
    public class OssController {
    
        @Autowired
        private OssService ossService;
    
        //上传头像
        @PostMapping
        public Result uploadOssFile(MultipartFile file){    //获取上传文件: MultipartFile
            //返回上传到oss上的存储路径
            String url = ossService.uploadFileAvatar(file);
            return Result.ok().data("url",url);
        }
    }
    
    展开全文
  • 本文将利用阿里云容器服务在几分钟内轻松搭建一个基于Docker的ownCloud专属网盘,并使用阿里云提供的OSS(Object Storage Service,对象存储服务)作为高可靠、低成本的云存储后端,需要的朋友可以参考下
  • 近日,中科曙光在北京发布了基于区块链存储应用打造的一款智能高效的专属存储系统——区块链存储系统ChainStor。ChainStor沿用了曙光多年技术积累的分布式存储架构,底层核心是基于裸设备的数据对象管理系统,不仅...

    近日,中科曙光在北京发布了基于区块链存储应用打造的一款智能高效的专属存储系统——区块链存储系统ChainStor。ChainStor沿用了曙光多年技术积累的分布式存储架构,底层核心是基于裸设备的数据对象管理系统,不仅继承了曙光原有分布式存储系统EB级扩展、高可靠和易管理的优势,更是针对区块链存储应用进行了包括核心部件、数据IO通道及模式适配等在内的多方面深度优化,功能设计精简聚焦,性能表现更出色。

    0c60f780e7ad05747695474f7a7d06fc.png

    把握趋势,曙光赋能区块链存储创新应用

    伴随5G、人工智能、互联网、大数据等新技术、新应用的广泛普及和快速发展,数据规模继续呈现爆发式增长,数据已经成为最核心的生产要素。如何解决各行业数据拥有者和使用者之间的信任关系,实现数据价值的高效传输和充分利用,成为困扰各行业客户产业升级和数字化转型的难关。区块链技术的出现与快速发展为解决上述问题提供了可行的解决方案。

    对数据存储和应用而言,区块链拥有去中心化、共识机制、分布式记账等核心技术和特性,保证了数据的不可篡改性,从而有效减低数据确权和交易成本,实现数据更畅通的交易与价值新生。区块链技术与多个行业结合形成的颠覆性创新,引起了国内外一致的关注和重视,国家发改委正式将区块链纳入新基建范围,国外也陆续推出了去中心化的区块链存储项目如基于IPFS的F项目等。

    区块链存储项目作为区块链技术和分布式存储技术结合的落地,通过安全、高效的去中心化存储平台以及可持续发展的商业模式,吸引众多存储服务供应商、区块链应用开发者、数据提供者参与。为了让拥有高性能、高可靠、低成本的存储服务商参与提供服务,一些商业化的区块链项目提供了奖励和惩罚机制。存储服务商提供的存储节点(存储系统)是否能实现数据的快速落盘以及数据是否能在时效范围内被及时抽取出来,将成为其快速发展和获得长期收益的关键。因此,区块链存储项目对底层存储系统的性能、可靠性、扩展性和运维效率都有着严苛的要求。

    SPEC准则,专业视角定义区块链存储

    基于多年超大规模存储系统的自主研发和部署运维经验,曙光开创性地提出SPEC准则,从专业视角定义了构建区块链存储的四个要素,帮助用户实现建设价值存储的愿景。

    首先是Security,即存储系统是否安全可靠。为了确保区块链存储服务商提供的存储空间稳定可靠,一些区块链存储项目会设置质押及惩罚措施。如果承接的有效数据存储空间发生异常造成数据丢失、无法恢复,该存储节点提供者将面临高额处罚,影响其发展和收益。因此,区块链存储需要具有更高可靠性的企业级存储产品。ChainStor提供了从部件、网络、节点、数据冗余等多层面的保护机制,充分保障数据的安全性及系统的稳健性。企业级的可靠性保障,让存储系统保持7*24小时连续运行,无任何宕机风险。

    其次是Performance,存储系统的性能。区块链存储将对高性能存储服务商提供奖励。前端数据存储响应越快、核查耗时越短,其获得认可的有效存储空间就越大,收益也会越高。以业界常规要求9分钟以内完成检查的某项目为例, ChainStor通过对缓存、访问优先级、IO路径等技术的深度优化,已把该指标缩短到1分钟以内,远超业界同类产品可达到的最高水平。

    第三要考量的是Capacity,即存储系统的可扩展能力。区块链存储旨在为各行业客户提供分布式的海量数据存储空间。在推广阶段,对于提供更大存储空间的服务商有更多的激励。对于单个的存储服务商来说,其存储系统的扩展能力越大,单位构建成本越低,竞争优势越显著。结合调研情况来看,区块链存储项目的主要存储服务商日均存储增长规模超过PB级,有些服务商构建的存储空间更是超过数百PB。如此规模,分布式存储系统是必然选择。ChainStor可轻松构建EB级海量存储空间,实现业务无感知在线扩容,即扩即用。曙光公司多年来积累的数百PB超大规模系统部署和运维经验,有效保障百PB容量小时级上线。

    最后要考量的是Efficiency,即存储系统的运维效率。大型的区块链存储服务商拥有多套超大规模存储集群,这些设备多分布在不同区域的多个机房中。传统的运维模式下,每套系统都需要大量的专业运维人员,将耗费极大的物力和财力。ChainStor可进行多维度的资源管理,多重故障预警机制,数十种亚健康状态自动探测与处理,更好地保障系统运行无忧。通过可视化的运维和多达64套集群统一管理,降低运维压力,减少运维成本。

    作为国内分布式存储市场的领军企业,曙光公司经过二十年的耕耘,凭借自主研发的技术优势、可靠的产品品质和专业的本地化服务支持,连续7年在IDC排名中位居国内NAS存储市场前两位。由曙光公司打造的分布式文件存储系统,更是代表着业界顶尖的技术水平。区块链存储蕴含着庞大的分布式存储生态,曙光公司将以专业的技术和优质的产品,为区块链相关生态应用构建坚实底座,帮助区块链从业者能够更好的致力于业务创新和更高效地成长。

    展开全文
  • 2、这些对象使用链式存储结构,形成一个链,每个对象知道自己的下一个对象。 3、一个对象对任务进行处理,可以添加一些操作后将对象传递个下一个任务。也可以在此对象上结束任务的处理,并结束任务。 4、客户端负责...

    什么是责任链模式

    客户端发出一个请求,链上的对象都有机会来处理这一请求,而客户端不需要知道谁是具体的处理对象。这样就实现了请求者和接受者之间的解耦,并且在客户端可以实现动态的组合职责链。使编程更有灵活性。

    关键点

    1、有多个对象共同对一个任务进行处理。
    2、这些对象使用链式存储结构,形成一个链,每个对象知道自己的下一个对象。
    3、一个对象对任务进行处理,可以添加一些操作后将对象传递个下一个任务。也可以在此对象上结束任务的处理,并结束任务。
    4、客户端负责组装链式结构,但是客户端不需要关心最终是谁来处理了任务。
    
    

    责任链模式环境

    如何给网关设计一款专属的权限控制「责任链设计模式」

     

    1.抽象处理者(Handler)角色:定义出一个处理请求的接口
    2.具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。

    责任链模式优缺点

    优点:
    职责链模式的最主要功能就是:动态组合,请求者和接受者解耦。
    请求者和接受者松散耦合:请求者不需要知道接受者,也不需要知道如何处理。每个职责对象只负责自己的职责范围,其他的交给后继者。各个组件间完全解耦。
    动态组合职责:职责链模式会把功能分散到单独的职责对象中,然后在使用时动态的组合形成链,从而可以灵活的分配职责对象,也可以灵活的添加改变对象职责。
    
    缺点:
    产生很多细粒度的对象:因为功能处理都分散到了单独的职责对象中,每个对象功能单一,要把整个流程处理完,需要很多的职责对象,会产生大量的细粒度职责对象。
    不一定能处理:每个职责对象都只负责自己的部分,这样就可以出现某个请求,即使把整个链走完,都没有职责对象处理它。这就需要提供默认处理,并且注意构造链的有效性。
    

    责任链模式应用场景

    1.多条件流程判断 权限控制
    2.ERP系统 流程审批 总经理、人事经理、项目经理
    3.Java过滤器的底层实现Filter 
    比如:在Java过滤器中客户端发送请求到服务器端,过滤会经过参数过滤、session过滤、表单过滤、隐藏过滤、检测请求头过滤
    

    网关权限控制责任链模式

    在网关作为微服务程序的入口,拦截客户端所有的请求实现权限控制 ,比如先判断Api接口限流、黑名单、用户会话信息拦截。

    Api接口限流→黑名单拦截→用户会话信息拦截

    GatewayHandler抽象角色

    /**
     * @title: GatewayHandler
     */
    public abstract class GatewayHandler {
        /**
         * 执行下一个handler
         */
        protected GatewayHandler nextGatewayHandler;
        public void setNextGatewayHandler(GatewayHandler nextGatewayHandler) {
            this.nextGatewayHandler = nextGatewayHandler;
        }
    
        //实现的handler 处理方案 强制必须实现
        public abstract void service();
    
        protected void nextService() {
            if (nextGatewayHandler != null)
                // 指向下一关
                nextGatewayHandler.service();
        }
    }
    

    具体Handler实现

    @Slf4j
    @Component
    public class CurrentLimitHandler extends GatewayHandler {
        @Override
        public void service() {
            log.info("第一关 API接口限流操作.....");
            //指向下一关
            nextService();
        }
    }
    @Component
    @Slf4j
    public class BlacklistHandler extends GatewayHandler {
        @Override
        public void service() {
            log.info("第二关 黑名单拦截.......");
            //指向下一关
            nextService();
        }
    }
    @Component
    @Slf4j
    public class ConversationHandler extends GatewayHandler {
        @Override
        public void service() {
            log.info("第三关 用户的会话信息拦截.......");
            }
    }

    基于数据库实现

    如何给网关设计一款专属的权限控制「责任链设计模式」

     

    相关SQL语句

    CREATE TABLE `gateway_handler` (
      `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `handler_name` varchar(32) DEFAULT NULL COMMENT 'handler名称',
      `handler_id` varchar(32) DEFAULT NULL COMMENT 'handler主键id',
      `prev_handler_id` varchar(32) DEFAULT NULL,
      `next_handler_id` varchar(32) DEFAULT NULL COMMENT '下一个handler',
      PRIMARY KEY (`ID`)
    ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COMMENT='权限表';
    
    -- ----------------------------
    -- Records of gateway_handler
    -- ----------------------------
    INSERT INTO `gateway_handler` VALUES ('16', 'Api接口限流', 'currentLimitHandler', null, 'blacklistHandler');
    INSERT INTO `gateway_handler` VALUES ('17', '黑名单拦截', 'blacklistHandler', 'currentLimitHandler', 'conversationHandler');
    INSERT INTO `gateway_handler` VALUES ('18', '会话验证', 'conversationHandler', 'blacklistHandler', null);
    

    Utils

    @Component
    public class SpringUtils implements ApplicationContextAware {
    
        private static ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    
        //获取applicationContext
        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }
    
        //通过name获取 Bean.
        public static Object getBean(String name){
            return getApplicationContext().getBean(name);
        }
    
        //通过class获取Bean.
        public static <T> T getBean(Class<T> clazz){
            return getApplicationContext().getBean(clazz);
        }
    
        //通过name,以及Clazz返回指定的Bean
        public static <T> T getBean(String name,Class<T> clazz){
            return getApplicationContext().getBean(name, clazz);
        }
    
    }

    GatewayHandlerService

    /**
     * @title: GatewayHandlerService
     */
    @Service
    public class GatewayHandlerService {
        @Autowired
        private GatewayHandlerMapper gatewayHandlerMapper;
        private GatewayHandler firstGatewayHandler;
        /**
         * 获取数据库第一个handeler封装
         */
        public GatewayHandler getFirstGatewayHandler() {
            if (firstGatewayHandler != null) {
                return firstGatewayHandler;
            }
            //1.【第一个实体】
            GatewayHandlerEntity firstGatewayHandlerEntity = gatewayHandlerMapper.getFirstGatewayHandler();
            if(firstGatewayHandlerEntity==null){ return null; }
            //2.【第一个HandlerId】
            String firstHhandlerId = firstGatewayHandlerEntity.getHandlerId();
            //3.【第二个HandlerId】
            String secondHandlerId = firstGatewayHandlerEntity.getNextHandlerId();
            //4.【第一个bean对象】
            GatewayHandler firstGatewayHandler = SpringUtils.getBean(firstHhandlerId, GatewayHandler.class);
            //5.【tmpHandler为第一个bean对象】
            GatewayHandler tmpHandler=firstGatewayHandler;
            //如果下一个HandlerId不为null,则继续
            while (!StringUtils.isBlank(secondHandlerId)){
                //6.【第二个bean对象】->11.【第三个bean对象】
                GatewayHandler secondGatewayHandler = SpringUtils.getBean(secondHandlerId, GatewayHandler.class);
                //7.【设置第一个bean对象的next为第二个bean对象】->12.【设置第二个bean对象的next为第三个bean对象】
                tmpHandler.setNextGatewayHandler(secondGatewayHandler);
                //8.【第二个实体】->13.【第三个实体】
                GatewayHandlerEntity secondHandlerEntity = gatewayHandlerMapper.getByHandler(secondHandlerId);
                if (secondHandlerEntity==null){ break; }
                //9.【第三个HandlerId】->14.【第四个HandlerId】此时为null,后面会退出循环
                secondHandlerId=secondHandlerEntity.getNextHandlerId();
                //10.【tmpHandler为第二个bean对象】->15.【tmpHandler为第三个bean对象】
                tmpHandler=secondGatewayHandler;
            }
            //16.赋值
            this.firstGatewayHandler=firstGatewayHandler;
            //17.返回第一个firstHandler对象
            return  firstGatewayHandler;
        }
    }

    数据库访问层

    GatewayHandlerMapper

    public interface GatewayHandlerMapper {
    
        /**
         * 获取第一个GatewayHandler
         */
        @Select("SELECT  handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid  FROM gateway_handler WHERE  prev_handler_id is null;;")
        public GatewayHandlerEntity getFirstGatewayHandler();
    
        @Select("SELECT  handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid   FROM gateway_handler WHERE  handler_id=#{handlerId}")
        public GatewayHandlerEntity getByHandler(String handlerId);
    
    }

    Entity层

    @Data
    public class GatewayHandlerEntity implements Serializable, Cloneable {
        /**
         * 主键ID
         */
        private Integer id;
        /**
         * handler名称
         */
        private String handlerName;
        /**
         * handler主键id
         */
        private String handlerId;
        /**
         * 下一个handler
         */
        private String nextHandlerId;
    
    }
    

    Controller层

    /**
     * @title: HandlerController
     */
    @RestController
    public class HandlerController {
        @Autowired
        private GatewayHandlerService gatewayHandlerService;
    
        @RequestMapping("/client")
        public String client() {
            GatewayHandler firstGatewayHandler = gatewayHandlerService.getFirstGatewayHandler();
            firstGatewayHandler.service();
            return "success";
        }
    }
    

    相关配置信息

    版权@须臾之余
    https://my.oschina.net/u/3995125

    application.yml

    ###服务启动端口号
    server:
      port: 8080
    
    spring:
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/design_pattern?useUnicode=true&characterEncoding=UTF-8&useSSL=true
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
    
    
    ####打印MyBatias日志
    logging:
      level:
        ### 开发环境使用DEBUG 生产环境info或者error
        com.xuyu.mapper: DEBUG
    

    Maven依赖信息

     <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.1.RELEASE</version>
        </parent>
        <dependencies>
            <!-- sprinboot web -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.10</version>
            </dependency>
            <dependency>
                <groupId>commons-lang</groupId>
                <artifactId>commons-lang</artifactId>
                <version>2.6</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.1.1</version>
            </dependency>
            <!-- mysql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
        </dependencies>

    启动类

    /**
     * @title: AppHandler
     */
    @SpringBootApplication
    @MapperScan("com.xuyu.mapper")
    @EnableAutoConfiguration
    public class AppHandler {
        public static void main(String[] args) {
            SpringApplication.run(AppHandler.class);
            
        }
    }

    效果

    2019-05-09 23:33:33.136  INFO 40524 --- [nio-8080-exec-6] c.xuyu.handler.impl.CurrentLimitHandler  : 第一关 API接口限流操作.....
    2019-05-09 23:33:33.136  INFO 40524 --- [nio-8080-exec-6] com.xuyu.handler.impl.BlacklistHandler   : 第二关 黑名单拦截.......
    2019-05-09 23:33:33.136  INFO 40524 --- [nio-8080-exec-6] c.xuyu.handler.impl.ConversationHandler  : 第三关 用户的会话信息拦截.......
    展开全文
  • 什么是责任链模式 客户端发出一个请求,链上的对象都有机会来处理...2、这些对象使用链式存储结构,形成一个链,每个对象知道自己的下一个对象。 3、一个对象对任务进行处理,可以添加一些操作后将对象传递个下一个...

    什么是责任链模式

    客户端发出一个请求,链上的对象都有机会来处理这一请求,而客户端不需要知道谁是具体的处理对象。这样就实现了请求者和接受者之间的解耦,并且在客户端可以实现动态的组合职责链。使编程更有灵活性。

    关键点

    1、有多个对象共同对一个任务进行处理。
    2、这些对象使用链式存储结构,形成一个链,每个对象知道自己的下一个对象。
    3、一个对象对任务进行处理,可以添加一些操作后将对象传递个下一个任务。也可以在此对象上结束任务的处理,并结束任务。
    4、客户端负责组装链式结构,但是客户端不需要关心最终是谁来处理了任务。
    
    

    责任链模式环境

    1.抽象处理者(Handler)角色:定义出一个处理请求的接口
    2.具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。

    责任链模式优缺点

    优点:
    职责链模式的最主要功能就是:动态组合,请求者和接受者解耦。
    请求者和接受者松散耦合:请求者不需要知道接受者,也不需要知道如何处理。每个职责对象只负责自己的职责范围,其他的交给后继者。各个组件间完全解耦。
    动态组合职责:职责链模式会把功能分散到单独的职责对象中,然后在使用时动态的组合形成链,从而可以灵活的分配职责对象,也可以灵活的添加改变对象职责。
    
    缺点:
    产生很多细粒度的对象:因为功能处理都分散到了单独的职责对象中,每个对象功能单一,要把整个流程处理完,需要很多的职责对象,会产生大量的细粒度职责对象。
    不一定能处理:每个职责对象都只负责自己的部分,这样就可以出现某个请求,即使把整个链走完,都没有职责对象处理它。这就需要提供默认处理,并且注意构造链的有效性。
    

    责任链模式应用场景

    1.多条件流程判断 权限控制
    2.ERP系统 流程审批 总经理、人事经理、项目经理
    3.Java过滤器的底层实现Filter 
    比如:在Java过滤器中客户端发送请求到服务器端,过滤会经过参数过滤、session过滤、表单过滤、隐藏过滤、检测请求头过滤
    

    网关权限控制责任链模式

    在网关作为微服务程序的入口,拦截客户端所有的请求实现权限控制 ,比如先判断Api接口限流、黑名单、用户会话信息拦截。

    Api接口限流→黑名单拦截→用户会话信息拦截

    GatewayHandler抽象角色

    /**
     * @title: GatewayHandler
     */
    public abstract class GatewayHandler {
        /**
         * 执行下一个handler
         */
        protected GatewayHandler nextGatewayHandler;
        public void setNextGatewayHandler(GatewayHandler nextGatewayHandler) {
            this.nextGatewayHandler = nextGatewayHandler;
        }
    
        //实现的handler 处理方案 强制必须实现
        public abstract void service();
    
        protected void nextService() {
            if (nextGatewayHandler != null)
                // 指向下一关
                nextGatewayHandler.service();
        }
    }
    

    具体Handler实现

    @Slf4j
    @Component
    public class CurrentLimitHandler extends GatewayHandler {
        @Override
        public void service() {
            log.info("第一关 API接口限流操作.....");
            //指向下一关
            nextService();
        }
    }
    @Component
    @Slf4j
    public class BlacklistHandler extends GatewayHandler {
        @Override
        public void service() {
            log.info("第二关 黑名单拦截.......");
            //指向下一关
            nextService();
        }
    }
    @Component
    @Slf4j
    public class ConversationHandler extends GatewayHandler {
        @Override
        public void service() {
            log.info("第三关 用户的会话信息拦截.......");
            }
    }

    基于数据库实现

    相关SQL语句

    CREATE TABLE `gateway_handler` (
      `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `handler_name` varchar(32) DEFAULT NULL COMMENT 'handler名称',
      `handler_id` varchar(32) DEFAULT NULL COMMENT 'handler主键id',
      `prev_handler_id` varchar(32) DEFAULT NULL,
      `next_handler_id` varchar(32) DEFAULT NULL COMMENT '下一个handler',
      PRIMARY KEY (`ID`)
    ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COMMENT='权限表';
    
    -- ----------------------------
    -- Records of gateway_handler
    -- ----------------------------
    INSERT INTO `gateway_handler` VALUES ('16', 'Api接口限流', 'currentLimitHandler', null, 'blacklistHandler');
    INSERT INTO `gateway_handler` VALUES ('17', '黑名单拦截', 'blacklistHandler', 'currentLimitHandler', 'conversationHandler');
    INSERT INTO `gateway_handler` VALUES ('18', '会话验证', 'conversationHandler', 'blacklistHandler', null);
    

    Utils

    @Component
    public class SpringUtils implements ApplicationContextAware {
    
        private static ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    
        //获取applicationContext
        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }
    
        //通过name获取 Bean.
        public static Object getBean(String name){
            return getApplicationContext().getBean(name);
        }
    
        //通过class获取Bean.
        public static <T> T getBean(Class<T> clazz){
            return getApplicationContext().getBean(clazz);
        }
    
        //通过name,以及Clazz返回指定的Bean
        public static <T> T getBean(String name,Class<T> clazz){
            return getApplicationContext().getBean(name, clazz);
        }
    
    }

    GatewayHandlerService

    /**
     * @title: GatewayHandlerService
     */
    @Service
    public class GatewayHandlerService {
        @Autowired
        private GatewayHandlerMapper gatewayHandlerMapper;
        private GatewayHandler firstGatewayHandler;
        /**
         * 获取数据库第一个handeler封装
         */
        public GatewayHandler getFirstGatewayHandler() {
            if (firstGatewayHandler != null) {
                return firstGatewayHandler;
            }
            //1.【第一个实体】
            GatewayHandlerEntity firstGatewayHandlerEntity = gatewayHandlerMapper.getFirstGatewayHandler();
            if(firstGatewayHandlerEntity==null){ return null; }
            //2.【第一个HandlerId】
            String firstHhandlerId = firstGatewayHandlerEntity.getHandlerId();
            //3.【第二个HandlerId】
            String secondHandlerId = firstGatewayHandlerEntity.getNextHandlerId();
            //4.【第一个bean对象】
            GatewayHandler firstGatewayHandler = SpringUtils.getBean(firstHhandlerId, GatewayHandler.class);
            //5.【tmpHandler为第一个bean对象】
            GatewayHandler tmpHandler=firstGatewayHandler;
            //如果下一个HandlerId不为null,则继续
            while (!StringUtils.isBlank(secondHandlerId)){
                //6.【第二个bean对象】->11.【第三个bean对象】
                GatewayHandler secondGatewayHandler = SpringUtils.getBean(secondHandlerId, GatewayHandler.class);
                //7.【设置第一个bean对象的next为第二个bean对象】->12.【设置第二个bean对象的next为第三个bean对象】
                tmpHandler.setNextGatewayHandler(secondGatewayHandler);
                //8.【第二个实体】->13.【第三个实体】
                GatewayHandlerEntity secondHandlerEntity = gatewayHandlerMapper.getByHandler(secondHandlerId);
                if (secondHandlerEntity==null){ break; }
                //9.【第三个HandlerId】->14.【第四个HandlerId】此时为null,后面会退出循环
                secondHandlerId=secondHandlerEntity.getNextHandlerId();
                //10.【tmpHandler为第二个bean对象】->15.【tmpHandler为第三个bean对象】
                tmpHandler=secondGatewayHandler;
            }
            //16.赋值
            this.firstGatewayHandler=firstGatewayHandler;
            //17.返回第一个firstHandler对象
            return  firstGatewayHandler;
        }
    }

    数据库访问层

    GatewayHandlerMapper

    public interface GatewayHandlerMapper {
    
        /**
         * 获取第一个GatewayHandler
         */
        @Select("SELECT  handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid  FROM gateway_handler WHERE  prev_handler_id is null;;")
        public GatewayHandlerEntity getFirstGatewayHandler();
    
        @Select("SELECT  handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid   FROM gateway_handler WHERE  handler_id=#{handlerId}")
        public GatewayHandlerEntity getByHandler(String handlerId);
    
    }

    Entity层

    @Data
    public class GatewayHandlerEntity implements Serializable, Cloneable {
        /**
         * 主键ID
         */
        private Integer id;
        /**
         * handler名称
         */
        private String handlerName;
        /**
         * handler主键id
         */
        private String handlerId;
        /**
         * 下一个handler
         */
        private String nextHandlerId;
    
    }
    

    Controller层

    /**
     * @title: HandlerController
     */
    @RestController
    public class HandlerController {
        @Autowired
        private GatewayHandlerService gatewayHandlerService;
    
        @RequestMapping("/client")
        public String client() {
            GatewayHandler firstGatewayHandler = gatewayHandlerService.getFirstGatewayHandler();
            firstGatewayHandler.service();
            return "success";
        }
    }
    

    相关配置信息

    版权@须臾之余https://my.oschina.net/u/3995125

    application.yml

    ###服务启动端口号
    server:
      port: 8080
    
    spring:
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/design_pattern?useUnicode=true&characterEncoding=UTF-8&useSSL=true
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
    
    
    ####打印MyBatias日志
    logging:
      level:
        ### 开发环境使用DEBUG 生产环境info或者error
        com.xuyu.mapper: DEBUG
    

    Maven依赖信息

     <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.1.RELEASE</version>
        </parent>
        <dependencies>
            <!-- sprinboot web -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.10</version>
            </dependency>
            <dependency>
                <groupId>commons-lang</groupId>
                <artifactId>commons-lang</artifactId>
                <version>2.6</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.1.1</version>
            </dependency>
            <!-- mysql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
        </dependencies>

    启动类

    /**
     * @title: AppHandler
     */
    @SpringBootApplication
    @MapperScan("com.xuyu.mapper")
    @EnableAutoConfiguration
    public class AppHandler {
        public static void main(String[] args) {
            SpringApplication.run(AppHandler.class);
            
        }
    }

    效果

    2019-05-09 23:33:33.136  INFO 40524 --- [nio-8080-exec-6] c.xuyu.handler.impl.CurrentLimitHandler  : 第一关 API接口限流操作.....
    2019-05-09 23:33:33.136  INFO 40524 --- [nio-8080-exec-6] com.xuyu.handler.impl.BlacklistHandler   : 第二关 黑名单拦截.......
    2019-05-09 23:33:33.136  INFO 40524 --- [nio-8080-exec-6] c.xuyu.handler.impl.ConversationHandler  : 第三关 用户的会话信息拦截.......

    版权

    本文参考:蚂蚁课堂:http://www.mayikt.com

    展开全文
  • 面试题包含了不同技术层面的面试问题,同时也能对一些没有面试开发经验的小白给予不可估量的包装, 让你的薪水绝对翻倍, 本人亲试有效.Java面试题84集、java面试专属及面试必问课程,所有的面试题有视屏讲解, 解答方案....
  • PowerShell中遵循的一切都是对象,具有一些专属的特性,可以使用这些属性来区别它们。由于WindowsUnix/Linux之间有本质区别,因此在Windows中要实现强大的Shell外壳不能遵循Unix/Linux的技术路线。而用对象来操作...
  • 华为Cloud BU IaaS存储服务开发部总经理林超在会上发布了专属企业存储服务(DESS)、 云服务器备份服务(CSBS)、弹性文件服务(SFS)、云硬盘服务(EVS)共享云硬盘和云硬盘扩容、对象存储服务(OBS)低频访问存储...
  • 数组是用来存取基本数据类型数据的(也可以存取...String:当老大了,最常见最经常使用的类之一,存储的字符串是(字符串对象的一个)不可更改的常量。 StringBuilder:不经常使用,只有频繁做连接等字符串操作...

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 319
精华内容 127
关键字:

对象存储和专属对象存储