精华内容
下载资源
问答
  • 来源:blog.csdn.net/riemann_/article/details/97698560答案controller默认单例的,不要使用非静态的成员变量,否则会发生数据逻辑混乱。正因为单例所以不是线程安全的。我们下面来简单的验证下:packagecom....

    来源:blog.csdn.net/riemann_/article/details/97698560

    答案

    controller默认是单例的,不要使用非静态的成员变量,否则会发生数据逻辑混乱。正因为单例所以不是线程安全的。

    我们下面来简单的验证下:

    package com.riemann.springbootdemo.controller;

    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;

    /**
     * @author riemann
     * @date 2019/07/29 22:56
     */

    @Controller
    public class ScopeTestController {

        private int num = 0;

        @RequestMapping("/testScope")
        public void testScope() {
            System.out.println(++num);
        }

        @RequestMapping("/testScope2")
        public void testScope2() {
            System.out.println(++num);
        }

    }

    我们首先访问 http://localhost:8080/testScope,得到的答案是1;然后我们再访问 http://localhost:8080/testScope2,得到的答案是 2

    得到的不同的值,这是线程不安全的。

    接下来我们再来给controller增加作用多例 @Scope("prototype")

    package com.riemann.springbootdemo.controller;

    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;

    /**
     * @author riemann
     * @date 2019/07/29 22:56
     */

    @Controller
    @Scope("prototype")
    public class ScopeTestController {

        private int num = 0;

        @RequestMapping("/testScope")
        public void testScope() {
            System.out.println(++num);
        }

        @RequestMapping("/testScope2")
        public void testScope2() {
            System.out.println(++num);
        }

    }

    我们依旧首先访问 http://localhost:8080/testScope,得到的答案是1;然后我们再访问 http://localhost:8080/testScope2,得到的答案还是 1

    相信大家不难发现 :

    单例是不安全的,会导致属性重复使用。

    解决方案

    1、不要在controller中定义成员变量。2、万一必须要定义一个非静态成员变量时候,则通过注解@Scope(“prototype”),将其设置为多例模式。3、在Controller中使用ThreadLocal变量

    补充说明

    spring bean作用域有以下5个:

    1.singleton:单例模式,当spring创建applicationContext容器的时候,spring会欲初始化所有的该作用域实例,加上lazy-init就可以避免预处理;2.prototype:原型模式,每次通过getBean获取该bean就会新产生一个实例,创建后spring将不再对其管理;(下面是在web项目下才用到的)3.request:搞web的大家都应该明白request的域了吧,就是每次请求都新产生一个实例,和prototype不同就是创建后,接下来的管理,spring依然在监听;4.session:每次会话,同上;5.global session:全局的web域,类似于servlet中的application。

    (完)

    最近热文:分享一份Java架构师学习资料!点赞功能,用 MySQL 还是 Redis 好 ?Spring Boot “内存泄漏”了,美团这样操作!Redis 10亿数据量只需要100MB内存?滴滴开源了哪些有意思的项目?有点牛脾~Spring Boot 中 @EnableXXX 注解什么逻辑?MySQL 面试高频 100 问,看完吊打面试官!坑大发了,MySQL的隐式转换造了个线上BUG

    ——长按关注Java大后端——

    04a11c9bd34172110eab6e3f18f1cdb3.png

    265d95a223a396b9ae636ae9be5a3c68.png戳原文,获取一份面试题资料!
    展开全文
  • (2)本文将介绍两种NAND常见的集成于系统的接口方式,分别integrated controller和SSD。首先,当我们的文件系统或者数据库访问存储设备时,他们都以块设备的访问接口来发出指令的,也就是说,最小...

    本文字数:2823

    阅读时间:15分钟

    前文链接:NAND基础物理特性 NAND FLASH有什么特性?

    NAND 裸片接口及其物理特性 NAND NAND FLASH有什么特性?(2)

    本文将介绍两种NAND常见的集成于系统的接口方式,分别是integrated controller和SSD。

    首先,当我们的文件系统或者数据库访问存储设备时,他们都是以块设备的访问接口来发出指令的,也就是说,最小系统要以512字节的方式访问硬盘。重写一个文件也是对对应的地址进行写入,对于HDD来说这很好办,无非就是磁头转动到对应的盘片,擦除并且重新写入一个block,对于NAND就有点复杂了,因为NAND写入只能按照page顺序写入,擦除时只能按照block擦除的特点,这种以Logical block为单位的操作就需要一套映射关系来处理。

    为了屏蔽NAND的特性,NAND设备的firmware引入了Logical address to physical address映射的概念,从而衍生出garbage collection和write amplify等概念,因此,只要系统希望以块设备形式访问NAND,就必须需要一个firmware来进行转化,而跑起来一个firmware,它需要提供协议解析,逻辑地址映射和NAND接口访问这三部分基础功能,就需要一个controller(SoC)。你可能会惊讶,硬盘里面还有一块SoC?甚至SD卡里也有一个SoC?是的,只要你的系统CPU不支持裸片的直接访问(ONFI or Toggle),那么势必在数据链路的其他位置,有一个芯片部件专门负责这个工作,不同的系统它的位置会不一样,但是它总是存在的。

    NAND with integrated controller是一种将NAND flash存储单元和controller 控制芯片集成在同一个芯片封装上的技术,这种技术的代表是现在的各种手机,因为手机和其他嵌入式设备一样,也需要固化存储层,虽然你平时不怎么关机,但是它总要关机,有时候还会没电,而且需要下载非常多的应用,这些应用存在哪里呢?NAND flash就是一个非常好的选择,它体积小,功耗低(相对于磁介质),几乎可以说是完美匹配了移动设备的特点。

    这种将控制器集成在芯片内部的技术主要有两种接口:

    eMMC:Embedded Multi Media Card,这是一种继承于MMC的协议,

    f6a5d3dd5a700eab277b95dcceeedad1.png

    3b5c0663cf144b1cfec32023c566a888.png

    MMC是一种出生于1997年的Flash卡接口协议,和SD卡是兼容的,这种协议使用了8bit的数据总线,如果大家对各种通信接口协议的发展历史比较了解的话,就会发现现在大部分的协议都普遍从并行协议转换成了串行协议,信号线从普通线转换成了差分线,从ATA到SATA,从PCI到PCIe等等,这是因为随着通信协议在物理层速度的飞速提升,使用并行总线的同步校准和失真都变成了非常大的问题,用串行总线虽然每个clock传输的数据量小了,但是可以将clock的频率提升到GHz级别,从而将数据传输量提高,布局布线更灵活,信号完整性更好。类似于这种级别的超高速总线,例如PCIe,也可以做到并行传输,但是每个lane上使用自己的clock,因为连线上稍微有一点点差异,都会使共用clock的两根线变得不再同步。

    eMMC就是MMC的嵌入式版本,eMMC是为了迎合手机这样的移动设备,将SD卡接口的芯片制作成为更节省PCB面积的BGA封装芯片,这种芯片的吞吐量是个瓶颈,由于时钟限制,必然会被新的串行接口所淘汰。

    2b8a964695eb303ea44d3bf77799a6be.png

    7e52897d8df8172972bed2912c8350e3.png

    UFS:Universal Flash Storage,这是一种JEDEC(固态存储的行业标准组织,类似于一个固态存储行业的联合国这种组织)制定的标准协议,这个协议最大的特点就是使用了串行差分信号,这个接口和很多串行总线接口(例如SPI总线)的定义非常像,有一个时钟引脚,两对差分信号线,分别用来输入和输出数据,还有一个reset引脚:

    差分信号线意味着走线的时候你的UFS芯片可以有更好的灵活度,信号完整性也会更好。

    8e4dafb808506ccedebfe5bcd7e1dbca.png

    现在绝大部分的手机厂商都使用了UFS芯片作为手机的存储空间,一般来说都会用UFS2.0及其以上的芯片,对于顺序读400MB的速度,手机上基本够用了,但随着5G时代的来临,NAND的访问速度问题将成为手机系统的瓶颈。苹果是相对来说比较特别的手机,他们直接在iPhone里装了一块Toshiba的NAND裸片,也就是说他的controller里面集成了Toggle接口的NAND控制器,在访问之后再通过NVMe接入到系统中,从iOS看到的存储设备是一个NVMe设备,从而把NAND芯片变成一个内部集成的SSD,只是这种方法对于一般厂商成本高,如果自己做SoC加入一个Toggle或者ONFI控制器加上纠错解码的LDPC和RAID硬件模块恐怕也是很不划算的事情。

    1d8a96d7386f6337452557dcded2ba94.png

    最后来聊一下比较复杂的,SSD:

    一般来说SSD是用在台式机笔记本或者服务器中的固化存储设备,由于大多数设备必须向下兼容HDD,SSD在最初设计时也是使用了和HDD相同的接口:

    SAS,SATA接口,更早的接口比如SCSI这种我们就不管了。

    NVMe是专门为NAND设计的一种接口协议,它本质上是一个应用层协议,意思是说不论你的数据链路层和物理层跑在什么设备上,SATA也好,PCIe也好,Ethernet也好,理论上它都是可以跑的,只是在设计之初,它的设计者Intel相对好的支持了PCIe总线(毕竟都是自家产品)。

    SATA总线:

    bc215ecefa0f7baf904df0317350334f.png

    SATA接口容易和SAS以及PCIe的U.2接口有点像,但是左边的数据线和右边的电源线之间会断开,而且金手指只在一边有,总的数据线只有两对差分线。

    e848ef514e15951a13ca96008396aeb4.png

    而U.2的接口是PCIe✖4的接口,也就是说一共有4✖2(上行和下行)对差分线路,这里是U.2官方spec给出的pin脚图,图上包含了SATA,SAS和U.2三种设备兼容的主机接口,这种接口可以自动识别出drive是哪种设备,那些管脚可以在特定的模式下使用。

    f13380bfda45d089d77efb815a4a8618.png

    f8f893c473be5d9f3a246cdc069c91a3.png

    还有一种叫做m.2的SSD接口,这是我们装机和装笔记本最常见到的SSD,一般你能从JD上买到的都是这种接口:

    541fee5505ca43752809ea6a46192481.png

    这种接口很容易和m.2的SATA的接口搞混,从外形看唯一的区别是PCIe接口的m.2盘只有一个凹槽,而mSATA有两个:

    685232fbb066b584bd28e121ee63ddc2.png

    其实从M.2的官方spec上可以看到很多种接口类型,这里只是最典型的两种,

    f0c38d63fd2c11ade605a6e9b9023408.png

    M.2的PCIe接口drive可以最高支持4lane的PCIe,最大理论带宽可以达到和U.2一样,但是第一gen4的PCIe还没有普及,第二,M.2的接口电源功率不够给力,所以一般现在市面上最好的M.2的SSD大约可以跑到3500MB/s的顺序读和2000MB/s的顺序写,顺序读已经基本接近Gen3的理论带宽极限4GB/s,但是写一般受限于功耗,不可能做到像PCIe半高半长(HHHL)或者U.2卡那样的写速度,对于个人用户,由于大部分人的每日写入量都达不到1DWPD,写速度并不是个人用户的关注点,同样random的IOPS一般的个人用户也不会太在意。

    从逻辑上看,NVMe和SATA最大的不同在于,NVMe设备的主机可以在多个core上建立多个与drive通信的IO queue,并且queue内的command可以不按照发的顺序返回成功或者失败的状态,并行并且没有顺序要求,原因在于SSD内部其实有很多NAND在并行操作,如果一笔读命令的latency很小,但是在一笔写之后发生,那么它很大概率上会比写先完成,并且回给host,不用等待,这样的效果是极大的减小了读命令的latency。再有,不论是PCIe还是Ethernet,在物理层面上最大带宽也会比SATA高很多,Gen4✖4的PCIe设备最大理论带宽可以达到8GB/s,如果除去一些传输消耗,数据量超过6GB/s对于大多数厂商来说应该不是问题。

    NVMe现在产生了更多的分支,有些厂商希望NVMe可以被移植到Ethernet上,这一点需求上尤其对于存储体量特别大的互联网巨头有非常重要的意义,因为一般这些公司都有海量数据需要存储,建立多个数据中心并且在中心内部和数据中心间使用了NAS这样的存储网络,Open Channel和Zone Namespace这样的概念在这样的需求下应运而生。现在在做这方面工作的主要还是Facebook,Google和Alibaba这样的巨头,其他人多半没有这样的需求。

    总结:为了像正常的块设备一样处理NAND,我们通常在操作系统和NAND之间加了一层映射,主要由SSD或者UFS芯片内的固件来完成,而与之通信的协议,未来的方向只有UFS(移动端)和NVMe(PC和storage)。下一个文章来讲一下firmware是怎么完成从块设备访问到NAND访问的转换工作的。

    展开全文
  • 什么是Spring bootSpring boot由Pivotal团队提供的全新框架,其设计目的用来简化新Spring应用的初始搭建以及开发过程。(自动定义了一些配置)spring boot其实不是什么新的框架,它默认配置了很多框架的使用方式,...

    什么是Spring boot

    • Spring boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。(自动定义了一些配置)
    • spring boot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot是Spring的升级版,Spring容器能做到的事情,它都能做到,而且更简便。
    • 从配置形式上来说,SpringBoot完全抛弃了繁琐的XML文件配置方式,而是替代性地用注解方式来实现,虽然本质来说,是差不多的(类似包扫描,注解扫描,类加载之类)。

    Spring boot优点

    • 使用Spring boot ,可以轻松的创建独立运行的程序,非常容易构建独立的服务组件,是实现分布式架构、微服务架构利器。Spring boot简化了第三方包的引用,通过注解,简化了依赖包的配置。SpringBoot集成的插件更多,从而使用很多服务,都只是引入一个依赖,几个注解和Java类就可以用了。
    • 在Web应用开发这一块,之前的应用一般来说是打包成war包,再发布到相关服务器容器下(例如Tomcat),虽然SpringBoot也可以这么做,但在SpringBoot下更常见的形式是将SpringBoot应用打包成可执行jar包文件。之所以这么做,源于你可以直接将SpringBoot应用看成是一个Java
      Application,其Web应用可以没有webapp目录(更不用说web.xml了),它推荐使用html页面,并将其作为静态资源使用。

    Spring boot的搭建过程

    eclipse的Spring boot的简易搭建过程

    1、进入网址https://start.spring.io/并点击Generate Project按钮下载项目压缩包

    dd57be315822436994eee19c7e719e58

    2、解压后,使用eclipse,Import -> Existing Maven Projects -> Next ->选择解压后的文件夹-> Finsh导入项目,完成。

    在ecplipse里的目录结构:

    src/main/java 程序开发以及主程序入口
    src/main/resources 配置文件
    src/test/java 测试程序

    Application.java 建议放到跟目录下面,主要用于做一些框架配置

    domain目录主要用于实体(Entity)与数据访问层(Repository)

    service 层主要是业务类代码

    controller 负责页面访问控制

    采用默认配置可以省去很多配置,当然也可以根据自己的喜欢来进行更改

    3、最后,启动Application main方法,至此一个java项目搭建好了!4、引入web模块

    pom.xml文件中默认有两个模块:

    spring-boot-starter:核心模块,包括自动配置支持、日志和YAML;
    spring-boot-starter-test:测试模块,包括JUnit、Hamcrest、Mockito。

    往pom.xml中加入模块用来支持web特性:

    org.springframework.boot        spring-boot-starter-web 

    5、编写controller内容

    @RestControllerpublic class HelloWorldController {    @RequestMapping("/hello")    public String index() {        return "Hello World";    }}

    @RestController的意思就是controller里面的方法都以json格式输出,不用再写什么jackjson配置了。

    6、启动主程序,打开浏览器访问http://localhost:8080/hello,就可以看到效果了。7、做单元测试
    打开的src/test/下的测试入口,编写简单的http请求来测试;使用mockmvc进行,利用MockMvcResultHandlers.print()打印出执行结果。

    @RunWith(SpringRunner.class)  @SpringBootTestpublic class HelloWorldControlerTests {    private MockMvc mvc;    @Before    public void setUp() throws Exception {        mvc = MockMvcBuilders.standaloneSetup(new HelloWorldController()).build();    }    @Test    public void getHello() throws Exception {    mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))                .andExpect(MockMvcResultMatchers.status().isOk())                .andDo(MockMvcResultHandlers.print())                .andReturn();    }}

    8、开发环境的调试
    springBoot对调试支持很好,修改之后可以实时生效,需要添加以下的配置:

    org.springframework.boot        spring-boot-devtools        trueorg.springframework.boot            spring-boot-maven-plugin            true

    该模块在完整的打包环境下运行的时候会被禁用。如果你使用java -jar启动应用或者用一个特定的classloader启动,它会认为这是一个“生产环境”。

    IDEA的Spring boot搭建过程

    1、新建一个项目,选择SpringIntializer选项(有时点击下一步的时候会出现报错,其实这是网络的原因,都懂,需要FQ,但是多试几次就好了)

    5a2d954d41494f329474c05204c0dc23


    2、取个名字

    8515acb4cc094e5687b235e97334aac7


    3、选上需要用的,继续

    1f86ce51874946aa8859675f343398ef


    4、填写projectname,结束创建

    65c8c9a72b0f4d28b5c17369d3efe115


    5、不需要提交上SVN的目录,可以通过File -> Settings -> Editor -> File Types设置隐藏

    594259cda4a8426aa68bb046c90ff4d2


    6、点击运行,运行成功

    9f8805dcc5d94035af064668adca37f6

    好了,到这里,一个完整的springboot就搭建完成了,从开发环境的搭建到测试代码编写,这里都分享给大家了

    看着后台数据,看我写的内容的朋友相当多,或许会对某几位老铁有所帮助吧,希望各位能动动手指,点个转发+关注,既是为了让更多人看见,也是给我一点支持,哈哈哈哈,还是喜欢有一些鼓励哒,谢谢!

    关注我,一个脑回路清奇的程序员,希望和大家一起进步,谢谢

    展开全文
  • 那么lombok到底什么呢,lombok一个可以通过简单的注解的形式来帮助我们简化消除一些必须有但显得很臃肿的 Java 代码的工具,简单来说,比如我们新建了一个类,然后在其中写了几个字段,然后通常情况下我们需要...

    相信大家在项目中都使用过Lombok,因为能够简化我们许多的代码,但是该有的功能一点也不少。

    那么lombok到底是个什么呢,lombok是一个可以通过简单的注解的形式来帮助我们简化消除一些必须有但显得很臃肿的 Java 代码的工具,简单来说,比如我们新建了一个类,然后在其中写了几个字段,然后通常情况下我们需要手动去建立getter和setter方法啊,构造函数啊之类的,lombok的作用就是为了省去我们手动创建这些代码的麻烦,它能够在我们编译源码的时候自动帮我们生成这些方法。

    那么Lombok到底是如何做到这些的呢?其实底层就是用到了编译时注解的功能。

    01cb1cabcde4a34e8e856a3701c4930c.png

    Lombok如何使用

    Lombok是一个开源项目,代码是在lombok中,如果是gradle项目的话直接在项目中引用如下即可。

    compile ("org.projectlombok:lombok:1.16.6")

    功能

    那么Lombok是做什么呢?其实很简单,一个最简单的例子就是能够通过添加注解自动生成一些方法,使我们代码更加简洁易懂。例如下面一个类。

     1 @Data
     2 public class TestLombok {
     3    private String name;
     4    private Integer age;
     5
     6    public static void main(String[] args) {
     7        TestLombok testLombok = new TestLombok();
     8        testLombok.setAge(12);
     9        testLombok.setName("zs");
    10    }
    11 }

    我们使用Lombok提供的Data注解,在没有写get、set方法的时候也能够使用其get、set方法。我们看它编译过后的class文件,可以看到它给我们自动生成了get、set方法。

     1 public class TestLombok {
     2    private String name;
     3    private Integer age;
     4
     5    public static void main(String[] args) {
     6        TestLombok testLombok = new TestLombok();
     7        testLombok.setAge(12);
     8        testLombok.setName("zs");
     9    }
    10
    11    public TestLombok() {
    12    }
    13
    14    public String getName() {
    15        return this.name;
    16    }
    17
    18    public Integer getAge() {
    19        return this.age;
    20    }
    21
    22    public void setName(String name) {
    23        this.name = name;
    24    }
    25
    26    public void setAge(Integer age) {
    27        this.age = age;
    28    }
    29
    30}

    当然Lombok的功能不止如此,还有很多其他的注解帮助我们简便开发,网上有许多的关于Lombok的使用方法,这里就不再啰嗦了。正常情况下我们在项目中自定义注解,或者使用Spring框架中@Controller、@Service等等这类注解都是运行时注解,运行时注解大部分都是通过反射来实现的。而Lombok是使用编译时注解实现的。那么编译时注解是什么呢?

    编译时注解

    注解(也被成为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。——————摘自《Thinking in Java》

    Java中的注解分为运行时注解编译时注解,运行时注解就是我们经常使用的在程序运行时通过反射得到我们注解的信息,然后再做一些操作。而编译时注解是什么呢?就是在程序在编译期间通过注解处理器进行处理。

    • 编译期:Java语言的编译期是一段不确定的操作过程,因为它可能是将*.java文件转化成*.class文件的过程;也可能是指将字节码转变成机器码的过程;还可能是直接将*.java编译成本地机器代码的过程
    • 运行期:从JVM加载字节码文件到内存中,到最后使用完毕以后卸载的过程都属于运行期的范畴。

    注解处理工具apt

    注解处理工具apt(Annotation Processing Tool),这是Sun为了帮助注解的处理过程而提供的工具,apt被设计为操作Java源文件,而不是编译后的类。

    它是javac的一个工具,中文意思为编译时注解处理器。APT可以用来在编译时扫描和处理注解。通过APT可以获取到注解和被注解对象的相关信息,在拿到这些信息后我们可以根据需求来自动的生成一些代码,省去了手动编写。注意,获取注解及生成代码都是在代码编译时候完成的,相比反射在运行时处理注解大大提高了程序性能。APT的核心是AbstractProcessor类。

    正常情况下使用APT工具只是能够生成一些文件(不仅仅是我们想象的class文件,还包括xml文件等等之类的),并不能修改原有的文件信息。

    但是此时估计会有疑问,那么Lombok不就是在我们原有的文件中新增了一些信息吗?我在后面会有详细的解释,这里简单介绍一下,其实Lombok是修改了Java中的**抽象语法树AST**才做到了修改其原有类的信息。

    接下来我们演示一下如何用APT工具生成一个class文件,然后我们再说Lombok是如何修改已存在的类中的属性的。

    定义注解

    首先当然我们需要定义自己的注解了

    1 @Retention(RetentionPolicy.SOURCE) 
    2 @Target(ElementType.TYPE) 
    3 public @interface GeneratePrint {
    4
    5    String value();
    6 }

    Retention注解上面有一个属性value,它是RetentionPolicy类型的枚举类,RetentionPolicy枚举类中有三个值。

    1 public enum RetentionPolicy {
    2
    3    SOURCE,
    4
    5    CLASS,
    6
    7    RUNTIME
    8 }
    • SOURCE修饰的注解:修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中
    • CLASS修饰的注解:表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候
    • RUNTIME修饰的注解:表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时。所以它能够通过反射调用,所以正常运行时注解都是使用的这个参数

    Target注解上面也有个属性value,它是ElementType类型的枚举。是用来修饰此注解作用在哪的。

     1 public enum ElementType {
     2    TYPE,
     3
     4    FIELD,
     5
     6    METHOD,
     7
     8    PARAMETER,
     9
    10    CONSTRUCTOR,
    11
    12    LOCAL_VARIABLE,
    13
    14    ANNOTATION_TYPE,
    15
    16    PACKAGE,
    17
    18    TYPE_PARAMETER,
    19
    20    TYPE_USE
    21 }

    定义注解处理器

    我们要定义注解处理器的话,那么就需要继承AbstractProcessor类。继承完以后基本的框架类型如下

     1 @SupportedSourceVersion(SourceVersion.RELEASE_8)
     2 @SupportedAnnotationTypes("aboutjava.annotion.MyGetter")
     3 public class MyGetterProcessor extends AbstractProcessor {
     4    @Override
     5    public synchronized void init(ProcessingEnvironment processingEnv) {
     6    super.init(processingEnv);
     7    }
     8
     9    @Override
    10    public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
    11        return true;
    12    }
    13 }

    我们可以看到在子类中上面有两个注解,注解描述如下

    • @SupportedSourceVersion:表示所支持的Java版本
    • @SupportedAnnotationTypes:表示该处理器要处理的注解

    继承了父类的两个方法,方法描述如下

    • init方法:主要是获得编译时期的一些环境信息
    • process方法:在编译时,编译器执行的方法。也就是我们写具体逻辑的地方

    我们是演示一下如何通过继承AbstractProcessor类来实现在编译时生成类,所以我们在process方法中书写我们生成类的代码。如下所示。


     1 @Override
     2 public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
     3    StringBuilder builder = new StringBuilder()
     4            .append("package aboutjava.annotion;\n\n")
     5            .append("public class GeneratedClass {\n\n"
     6            .append("\tpublic String getMessage() {\n"
     7            .append("\t\treturn \"");
     8    
     9    for (Element element : roundEnv.getElementsAnnotatedWith(MyGetter.class)) {
    10        String objectType = element.getSimpleName().toString();
    11        
    12        builder.append(objectType).append(" says hello!\\n");
    13    }
    14    builder.append("\";\n"
    15            .append("\t}\n"
    16            .append("}\n"); 
    17    try { 
    18        JavaFileObject source = processingEnv.getFiler().createSourceFile("aboutjava.annotion.GeneratedClass");
    19        Writer writer = source.openWriter();
    20        writer.write(builder.toString());
    21        writer.flush();
    22        writer.close();
    23    } catch (IOException e) {
    24        
    25        
    26    }
    27    return true;
    28 }

    定义使用注解的类(测试类)

    上面的两个类就是基本的工具类了,一个是定义了注解,一个是定义了注解处理器,接下来我们来定义一个测试类(TestAno.java)。我们在类上面加上我们自定的注解类。

    1 @MyGetter
    2 public class TestAno {
    3
    4    public static void main(String[] args) {
    5        System.out.printf("1");
    6    }
    7 }

    这样我们在编译期就能生成文件了,接下来演示一下在编译时生成文件,此时不要着急直接进行javac编译,MyGetter类是注解类没错,而MyGetterProcessor是注解类的处理器,那么我们在编译TestAnoJava文件的时候就会触发处理器。因此这两个类是无法一起编译的。

    先给大家看一下我的目录结构

    aboutjava2    
    -- annotion3        
    -- MyGetter.java4       
    -- MyGetterProcessor.java5       
    -- TestAno.java

    所以我们先将注解类和注解处理器类进行编译

    javac aboutjava/annotion/MyGett*

    接下来进行编译我们的测试类,此时在编译时需要加上processor参数,用来指定相关的注解处理类。

    javac -processor aboutjava.annotion.MyGetterProcessor aboutjava/annotion/TestAno.java

    大家可以看到动态图中,自动生成了Java文件。

    3634f9f4c2e692a671293a305e5c5d93.gif
    展开全文
  • 什么是k8s,k8s这个词来自于希腊语,有主管,舵手,船长的意思,我们从图标中能看出来。在k8s的网站上,描述这样的生产级别的容器编排系统从定义中可以提炼出三个关键字,分别生产级别容器编排系统1...
  • 什么是k8s,k8s这个词来自于希腊语,有主管,舵手,船长的意思,我们从图标中能看出来。在k8s的网站上,描述这样的生产级别的容器编排系统从定义中可以提炼出三个关键字,分别生产级别容器编排系统1. 生产级别说...
  • controller>用于配置ActionServlet. 属性 描述 bufferSize 指定上载文件的输入缓冲的大小。该属性为可选项,默认值为4096. className 指定和<controller>元素对应的配置类。默认为org.apache.str...
  • [img=https://img-bbs.csdn.net/upload/201907/09/1562685913_197952.png][/img]
  • map( 'GET', '/[a:controller]/', function($controller, $action = 'index') { if( method_exists( $controller, $action )) $controller::Index(); else echo 'missing'; }); </code></pre> <p>what does ...
  • 1.先名词解释吧:DAO = Data Access Object = 数据存取对象Service = 服务Controller = 控制器Util = 工具Model = 模型首先,一个代码是不是有完善的结构,和是不是有上面这些东西没有什么关系,只是通常来说,我们...
  • 成人高考是什么意思?可以上大学吗?如果一个人学历很低,没有足够的时间和精力来进行学历的提升工作,那么成人高考无疑是很好的选择。那么,成人高考是什么意思?可以上大学吗? 成人高考是什么意思? 成人高考是成人...
  • 首先,一个代码是不是有完善的结构,和是不是有上面这些东西没有什么关系,只是通常来说,我们做一个大项目会把项目分解成很多不不同的模块(Module),然后根据用途和角色,我们对这些模块有一个通用的命名规则,这...
  • 作者:技能树IT修真院链接:https://www.zhihu.com/question/58410621/answer/623496434来源:知乎著作权归作者所有。商业转载请联系作者获得...2.什么样才一个好的结构 3.每一个分类代表什么含义 4.是否适用于W...
  • 2.什么样才一个好的结构 3.每一个分类代表什么含义 4.是否适用于WEB,Android和IOS? 5.进一步的学习的话,要学习系统架构么? 一 为什么需要一个好的代码结构 好的代码结构并不仅仅为了看上去清晰,...
  • BIOS中的每个中文是什么意思,请对照的翻译一下Time/SystemTime时间/系统时间Date/SystemDate日期/系统日期Level2Cache二级缓存SystemMemory系统内存VideoController视频控制器PanelType液晶屏型号AudioController...
  • 2.什么样才一个好的结构 3.每一个分类代表什么含义 4.是否适用于WEB,Android和IOS? 5.进一步的学习的话,要学习系统架构么? 一 为什么需要一个好的代码结构 好的代码结构并不仅仅为了看上去清晰,它更...
  • ①首先得明白jQuery对象只能使用jQuery对象的属性和方法...③$('xx')jQuery对象,$('xx')[0]将jQuery对象:$('xx')转换为JavaScript对象,这样才可以使用JavaScript对象的属性和方法; ④我们再看这行代码的背景,H
  • MVC是什么意思

    千次阅读 2020-05-15 09:21:55
    “Model” 代表的应用的业务逻辑(通过JavaBean,EJB 组件实现),“View” 应用的表示面(JSP 页面),"Controller"提供应用的处理过程控制(一般一个 Servlet),通过这种设计模型把应用逻辑,处理过程和...
  • 展开全部Time/System Time 时间/系统时间Date/System Date 日期/系统日期Level 2 Cache 二级缓存System Memory 系统内存Video Controller 视频控制器Panel Type 液晶屏型号Audio Controller 音频控制器Modem ...
  • 第一个@Controller意思就是注明这个方法控制器的意思,标明了这个方法控制器就可以在网页对这个方法进行访问 第二个@RequestMapping("/session")这个方法注明这个方法的地址就是session,这个session可以...
  • 2006-04-14求电脑各种错误信息的中文意思求电一、BIOS中的提示信息提示信息 说明Drive A error 驱动器A错误System halt 系统挂起Keyboard controller error 键盘控制器错误Keyboard error or no keyboard present ...
  • 编程中的脚手架是什么意思

    千次阅读 2018-12-23 13:55:29
    脚手架一种由一些 model–view–controller 框架支持的技术,程序员可以在其中指定应用程序数据库的使用方式。该编译器或框架使用说明书中,与预先定义的代码模板在一起,产生最终代码的应用程序可以使用它来创建...
  • 解决办法:找到C:\Program Files\Common Files\Microsoft Shared\OFFICE12\Office Setup Controller,将这个文件夹删除或改名,就不再出现提示了。 上面网上提供的解决方法,但是我试着改了下改名,未果,尝试删除...
  • OTP ROM MCU是什么意思

    千次阅读 2015-11-03 17:33:16
    MCU(Micro Controller Unit),又称单片微型计算机(Single Chip Microcomputer),指随着大规模集成电路的出现及其发展,将计算机的CPU、RAM、ROM、定时数器和多种I/O接口集成在一片芯片上,形成芯片级的计算机。...

空空如也

空空如也

1 2 3 4 5 ... 14
收藏数 277
精华内容 110
关键字:

controller是什么意思