索悟

索悟 查看完整档案

西安编辑西安科技大学  |  软件工程 编辑保密  |  java 编辑填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

索悟 关注了问题 · 4月8日

javassist重复增强及跟其他agent冲突问题

背景

有时候需要对服务进行调试,通过项目后门(接口)临时插入调试代码,用到javassistinsertAt,例如:

ctMethod.insertAt(45, "{ System.out.println(\"test\"); }");

调试完之后再清理掉调试的代码,用的是transform返回null的方式:

public static class ResetClassFileTransformer implements ClassFileTransformer {
    @Override
    public byte[] transform(
            ClassLoader loader,
            String className,
            Class<?> classBeingRedefined,
            ProtectionDomain protectionDomain,
            byte[] classfileBuffer) {
        return null;
    }
}

但是这种方式,如果在执行清理之后,项目没有重启的情况下,再次通过项目后门插入调试代码,之前被清理掉的增强代码又会出现了,比如执行以下增加之后:

ctMethod.insertAt(45, "{ System.out.println(\"test2\"); }");

执行结果是:

test
test2

原因是因为javassistClassPoolCtClass的增强会有缓存,所以我改为在清理时,同时执行CtClassdetach方法。
改了之后确实也解决了以上的问题,但是发现如果项目有其他的agent,并且该agent也用javassist做增强的话,在detach之后再次增强,agent的增强也会被清理掉。例如:

  1. 项目已有的agent里有insertBefore是打印出before,然后项目运行时通过后门执行insertAt打印test,这时候执行的结果是:

    before
    test
  2. 调试完之后执行清理ResetClassFileTransformer),这时候agent的增强还在,所以执行的结果是:

    before
  3. 这时候再次增强,通过insertAt打印test2,然而执行的结果是:

    test2

    agent的增强被清除了。

问题

要怎么做到可以重复的增强 -> 清除,但是又不影响项目已经引入的其他agent

关注 2 回答 0

索悟 回答了问题 · 4月8日

解决如何获取文件夹的目录结构?

 /**
 * 输出给定目录下的文件,包括子目录中的文件
 *
 * @param dirPath 给定的目录
 */
public Map<String, Map> readFiles(String dirPath , Map<String, Map> fileAndDirMap) {
    // 建立当前目录中文件的File对象
    File curfile = new File(dirPath);
    // 取得代表目录中所有文件的File对象数组
    File[] list = curfile.listFiles();
    if (list != null) {
        for (File file : list) {
            if (file.isDirectory()) {
                Map<String, Map> map = new HashMap<>();
                fileAndDirMap.put(file.getPath(), map);
                readFiles(file.getPath(), map);
            } else {
                fileAndDirMap.put(file.getPath(),null);
            }
        }
    }
    // 遍历file数组
    return fileAndDirMap;
}

你的思路有问题,你的返回值格式只是Map<String,List<String>>,不满足你想要的分层格式,要换成Map存储子目录才可以

关注 5 回答 4

索悟 回答了问题 · 4月7日

问几个虚拟机相关的问题哈

1.第一个问题解释起来有点拗口,我个人认为用作GCRoot的对象,都是可以准确判断这个对象一定有被使用,或者对象所在区域不容易被GC的,你看你图上的那些作为GCRoot的对象,都有这个特性
①虚拟机栈引用的对象,虚拟机的栈帧是随着方法调用而入栈,方法结束而出栈的,方法调用的时候那些用到的对象肯定是有在使用吧,所以肯定可以作为GCroot
②剩下的那些作为GCroot的差不多也是这个道理,方法区加载的类一般也很少会被GC,所以自然也可以作为GCroot
你的疑惑大概就在于为什么局部变量都可以,为什么全局变量不可以,事实上①中也说明了,局部变量可以是因为栈帧随着方法调用结束而出入栈,这一点可以判断引用的对象是否在使用,而全局变量包含在对象中,何时使用,是否在使用并没有可以依据的标准,因此不可以作为GCroot
2.我觉得原文的意思大概是,如果没有覆盖finalize()方法的话,就表示这个对象已经“死亡”了是会直接标记回收的,可以结合标记-清除算法来看,标记的本质是为了找出要回收的对象,之所以进行二次标记,是为了给一些实现了finalize()方法的类的一次运行该方法的机会,这些实现了finalize()方法会在第一次标记过程中放在F-Queue队列中而不进行标记,如果执行finalize()方法后该对象和GCroot产生了关联,那么对象就会避免被回收,重新存活,如果执行finalize()方法还是没有和GCroot有关联,那么就会被标记回收

关注 4 回答 3

索悟 回答了问题 · 4月7日

解决java扫描文件Scanner如何换行?

image.png
试试这个

关注 3 回答 2

索悟 回答了问题 · 4月6日

解决为什么右移操作会stack overflow?

/2操作的话,右移一位就可以了,你这样相当于是/4操作,另外这样的算法也不是很严谨,可以选择使用(end-start)/2 + start,防止出现数组过大导致的int值溢出问题

关注 2 回答 1

索悟 关注了标签 · 2020-03-17

关注 10

索悟 关注了标签 · 2020-03-17

关注 4

索悟 发布了文章 · 2020-03-17

Serializable接口分析

Serializable接口概述

  Serializable接口是一个定义在java.io包下的一个语义接口。实现该接口的类都可以进行序列化或反序列化操作(即将对象转化成字节流或将字节流转回对象的操作)。之所以提供这么一个作用,就是因为在java程序在底层操作时,数据都是字节流的形式。而对象作为java中数据的基本载体,为了在底层实现对数据的读取操作,就需要一个方式来使得对象和字节流之间可以互相转换。而Serializable接口就提供了这个功能。

序列化与反序列化

  前面提到,将对象转化成字节流的过程,称为序列化,而将字节流转化为对象的过程,称为反序列化。在java中,ObjectOutputStream和ObjectInputStream这两个类可以帮助我们方便的数据的序列化。因此,在下文的探讨中,我预先实现了两个工具类用于对象的序列化和反序列化。如下:

//将对象保存在指定路径下,文件名为类名
public static void wirteObject(Object o) throws FileNotFoundException, IOException {
    String filename = o.getClass().getName();
    File file = new File(BASE_PATH + filename);
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
    oos.writeObject(o);
    oos.close();
}
//将数据从文件中读取,转化为对象
public static Object readObject(Class c) throws FileNotFoundException, IOException, ClassNotFoundException {
    String filename = c.getName();
    File file = new File(BASE_PATH + filename);
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
    Object o = ois.readObject();
    ois.close();
    return o;
}

其中,BASE_PATH是我指定的一个路径,是一个常量字符串。
`
public static final String BASE_PATH = "D:\mytest\";`

case 1:没有实现Serializable接口的类是否能被序列化

首先,定义一个普通类


class User{
    String name;
    int age;
    public User(String name,int age) {
        this.age = age;
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }   
}

执行以下程序,尝试将User类对象转化为文件

    
User u = new User("小明",13);
wirteObject(u);

输出结果如下;

Exception in thread "main" java.io.NotSerializableException: langanal.stringanal.User
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at langanal.stringanal.SerializableAnal.wirteObject(SerializableAnal.java:25)
at langanal.stringanal.SerializableAnal.main(SerializableAnal.java:40)

由输出结果可以看到,没有实现Serializable接口的类,其对象不能被序列化。

case 2:实现Serializable接口,数据序列化后,反序列化回来的对象数据是否与原数据一致?

给原来的User类实现Serializable接口


class User implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    String name;
    int age;
    public User(String name,int age) {
        this.age = age;
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

执行以下程序,并查看结果


User u = new User("小明",13);
wirteObject(u);
u = (User)readObject(User.class);
System.out.println(u.getName()); //小明
System.out.println(u.getAge()); //13

输出结果与注释中一致,表明数据反序列化后,对象数据与序列化之前的对象数据一致

case 3:实现Serializable接口类的子类,一样可以实现序列化

定义一个case2中User的子类SubUser


class SubUser extends User{
    int state;
    public SubUser(String name,int age,int state) {
        super(name,age);
        this.state = state;
    }
    public int getState() {
        return state;
    }
    public void setState(int state) {
        this.state = state;
    }
}

运行以下程序,结果与注释中一致


SubUser su = new SubUser("小明",13,1);
wirteObject(su);
su = (SubUser)readObject(SubUser.class);
System.out.println(su.getName()); //小明
System.out.println(su.getAge()); //13
System.out.println(su.getState()); //1

case 4:某个没有实现Serializable接口的类,当它的子类实现了Serializable接口时,子类可以在序列化操作中执行父类的初始化,但前提是父类拥有不带参的构造方法,如果父类没有相关方法,则会在运行时抛出异常

User类取消实现Serializable接口,SubUser实现Serializable接口,其他保持不变,即,父类没有无参构造方法


class User{
    String name;
    int age;
    public User(String name,int age) {
        this.age = age;
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

    class SubUser extends User implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    int state;
    public SubUser(String name,int age,int state) {
        super(name,age);
        this.state = state;
    }
    public int getState() {
        return state;
    }
    public void setState(int state) {
        this.state = state;
    }
}

运行如下程序


SubUser su = new SubUser("小明",13,1);
try {
    wirteObject(su);
} catch (IOException e) {
    System.out.println("序列化执行失败");
    e.printStackTrace();
}
try {
    su = (SubUser)readObject(SubUser.class);
} catch (ClassNotFoundException | IOException e) {
    System.out.println("反序列化执行失败");
    e.printStackTrace();
}

输出如下


反序列化执行失败
java.io.InvalidClassException: langanal.stringanal.SubUser; no valid constructor
at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(Unknown Source)
at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at langanal.stringanal.SerializableAnal.readObject(SerializableAnal.java:33)
at langanal.stringanal.SerializableAnal.main(SerializableAnal.java:47)

从输出中,也可以看到,虽然子类实现了序列化操作,但在反序列化过程中,因为父类没有实现无参构造器,所以导致程序抛出异常。
将User类修改如下:

class User{
    String name;
    int age;
    //新添加的无参构造器
    public User() {
        this.name = "小明(无参构造)";
        this.age = 999;
    }
    public User(String name,int age) {
        this.age = age;
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

运行如下程序,输出与注释一致:

SubUser su = new SubUser("小明",13,1);
try {
    wirteObject(su);
} catch (IOException e) {
    System.out.println("序列化执行失败");
    e.printStackTrace();
}
try {
    su = (SubUser)readObject(SubUser.class);
} catch (ClassNotFoundException | IOException e) {
    System.out.println("反序列化执行失败");
    e.printStackTrace();
}
System.out.println(su.getName()); //小明(无参构造)
System.out.println(su.getAge()); //999
System.out.println(su.getState()); //1

由以上输出也可以看出,在反序列化过程中,父类的构建由父类的无参构造器完成,而父类原先的数据不会还原,但相对的,实现了序列化的子类,依然会还原原先数据。另外,还需要强调的是,父类的无参构造方法,对子类必须可见,如果将父类构造方法设置成private等子类不可见性式,程序将会报出如下异常:

java.io.InvalidClassException: langanal.stringanal.SubUser; no valid constructor
at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(Unknown Source)
at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at langanal.stringanal.SerializableAnal.readObject(SerializableAnal.java:33)
at langanal.stringanal.SerializableAnal.main(SerializableAnal.java:47)

case 5:readObject和writeObject方法的使用

首先声明,这两个方法并非在文章开头定义的方法,且为了防止混淆,在下面的代码中,工具方法更名为readObject_util以及writeObject_util
测验如下:
定义一个SpecialClass类,类中包含三个String成员变量,分别为static和transient符号修饰,以及不加任何修饰的String变量

class SpecialClass implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    static String static_str;
    String normal_str;
    transient String transient_str;
    public SpecialClass(String static_str,String normal_str,String transient_str) {
        this.static_str = static_str;
        this.normal_str = normal_str;
        this.transient_str = transient_str;
        
    }
    public SpecialClass() {
        this.static_str = "static";
        this.normal_str = "normal";
        this.transient_str = "transient";
    }
    public static String getStatic_str() {
        return static_str;
    }
    public static void setStatic_str(String static_str) {
        SpecialClass.static_str = static_str;
    }
    public String getNormal_str() {
        return normal_str;
    }
    public void setNormal_str(String normal_str) {
        this.normal_str = normal_str;
    }
    public String getTransient_str() {
        return transient_str;
    }
    public void setTransient_str(String transient_str) {
        this.transient_str = transient_str;
    }
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
        this.static_str = (String)in.readObject();
        this.transient_str = (String)in.readObject();
    }
    private void writeObject(ObjectOutputStream out)throws IOException{
        out.writeObject(static_str);
        out.writeObject(transient_str);
    }
}

运行如下程序:

SpecialClass sc = new SpecialClass("static_change","normal_change","transient_change");
System.out.println("-------序列化操作之前------------------");
System.out.println(sc.getStatic_str()); 
System.out.println(sc.getNormal_str()); 
System.out.println(sc.getTransient_str()); 
try {
    wirteObject_util(sc);
} catch (IOException e) {
    System.out.println("序列化执行失败");
    e.printStackTrace();
}
try {
    sc = (SpecialClass)readObject_util(SpecialClass.class);
} catch (ClassNotFoundException | IOException e) {
    System.out.println("反序列化执行失败");
    e.printStackTrace();
}
System.out.println("-------序列化操作之后------------------");
System.out.println(sc.getStatic_str()); 
System.out.println(sc.getNormal_str()); 
System.out.println(sc.getTransient_str()); 

输出如下:

-------序列化操作之前------------------
static_change
normal_change
transient_change
-------序列化操作之后------------------
static_change
null
transient_change

可以看到,在输出中,输出了定义在readObject和writeObjet中保存和读取的变量,但对于没有定义在其中的普通String成员变量,并没有参与到序列化的过程当中,也就是说,这两个方法覆盖了Serializable接口的默认序列化操作,并且提供了更细化的操作。另外,在SpecialClass类中注释掉readObject和writeObject方法后,再次执行上面的程序,会得到如下输出:

-------序列化操作之前------------------
static_change
normal_change
transient_change
-------序列化操作之后------------------
static_change
normal_change
null

可以直观的看到,transient修饰的字段不参与Serializable接口的默认序列化流程,所以输出为null,但是到目前为止,无法确定static修饰的字段是否参与序列化过程。因此,修改运行程序如下:

SpecialClass sc = null;
try {
    sc = (SpecialClass)readObject_util(SpecialClass.class);
} catch (ClassNotFoundException | IOException e) {
    System.out.println("反序列化执行失败");
    e.printStackTrace();
}
System.out.println("-------序列化操作之后------------------");
System.out.println(sc.getStatic_str()); 
System.out.println(sc.getNormal_str()); 
System.out.println(sc.getTransient_str()); 

这里要注意的是,运行这个程序的前提是已经按照上面的步骤将对象保存为对应的文件,不然会抛出java.io.FileNotFoundException异常
最后输出结果如下:

-------序列化操作之后------------------
null
normal_change
null

由以上结果可以得出,static修饰的字段,也默认不参与序列化的流程。
最后,需要注意的是,这两个方法如果要一起写,readObject方法中数据的读取顺序一定要和writeObject方法中数据写入顺序一致。

case 6:探究serialVersionUID用法

java文档强烈建议,在实现Serializable接口时,都要显示指定serialVersionUID的值,具体是为什么呢?
首先,设定一个类,实现Serializable接口,但不显示指定serialVersionUID的值

class TestUID implements Serializable{        int old;
    public TestUID(int old) {
        this.old = old;
    }
    public int getOld() {
        return old;
    }
    public void setOld(int old) {
        this.old = old;
    }
}

运行如下程序,输入结果与注释一致:

TestUID t = new TestUID(100);
wirteObject_util(t);
t = (TestUID) readObject_util(TestUID.class);
System.out.println(t.getOld()); //100

注释掉wirteObject_util(t)这一句,并将TestUID更新如下:

class TestUID implements Serializable{
    int old;
    int newnum;
    public TestUID(int old) {
        this.old = old;
    }
    public int getOld() {
        return old;
    }
    public void setOld(int old) {
        this.old = old;
    }
    public int getNewnum() {
        return newnum;
    }
    public void setNewnum(int newnum) {
        this.newnum = newnum;
    }
}

运行程序得到报错:

Exception in thread "main" java.io.InvalidClassException: langanal.stringanal.TestUID; local class incompatible: stream classdesc serialVersionUID = 3818576969179375793, local class serialVersionUID = -924220239598009211
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at langanal.stringanal.SerializableAnal.readObject_util(SerializableAnal.java:33)
at langanal.stringanal.SerializableAnal.main(SerializableAnal.java:63)

根据官方文档的说法:

If a serializable class does not explicitly declare a serialVersionUID, then
  the serialization runtime will calculate a default serialVersionUID value
  for that class based on various aspects of the class, as described in the
  Java(TM) Object Serialization Specification.

表明,类对象的变化,直接影响到了serialVersionUID的值的变化,也就导致了异常的报错,关于serialVersionUID的作用,官方规定:“如果接收方加载了一个具有不同于相应发件人类的serialVersionUID的对象的类,则反序列化将导致InvalidClassException 。”也就是说,在类发生变化之后,之前没有显示指定的serialVersionUID发生了变化,与之前已经序列化到文件中的对象的serialVersionUI不一致,所以导致反序列化失败。
按照上述规定,再做一遍实验,首先指定TestUID的serialVersionUID值

class TestUID implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    int old;
    public TestUID(int old) {
        this.old = old;
    }
    public int getOld() {
        return old;
    }
    public void setOld(int old) {
        this.old = old;
    }
}

将以上类的对象序列化保存到文件后,更改类如下:

class TestUID implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    int old;
    int newnum;
    public TestUID(int old) {
        this.old = old;
    }
    public int getOld() {
        return old;
    }
    public void setOld(int old) {
        this.old = old;
    }
    public int getNewnum() {
        return newnum;
    }
    public void setNewnum(int newnum) {
        this.newnum = newnum;
    }
}

反序列化之前的文件,运行以下程序,输出与注释一致,也就表明了,在指定了serialVersionUID值的情况下,改变原先类的结构,不会对反序列化原先类对象造成影响:

TestUID t = (TestUID) readObject_util(TestUID.class);
System.out.println(t.getOld()); //100
查看原文

赞 0 收藏 0 评论 0

索悟 关注了用户 · 2020-03-17

日拱一兵 @tanrigongyibing

欢迎关注,公众号「日拱一兵」,以读侦探小说思维趣味轻松学习Java技术

关注 23820

索悟 赞了文章 · 2020-03-17

程序员2019个人经历,披荆斩棘,终雨过天晴

无畏年少青春,迎风潇洒前行

点赞再看,养成习惯

前言

人生是一个漫长的过程,我们怀有太多的期望,就难免会遭遇失望与挫折。

把理想束之高阁,回过头来却发现我们像是一条鱼,一直以为自己有翅膀便是飞鸟,却终于知道自己飞不了。

生活如水,时而浑浊,时而清澈,我们在社会这个大缸中挣扎——“我常常觉得生活亏待了我,别人为什么总比自己幸福和快乐呢?”。

面对挫折,我们抱怨生活欺骗了我们,我们以为自己的人生已经没有希望。

我们经常把自己比喻为迷失的天鹅,却忘记了自己要怎样去飞翔。

这期是我自己2019的小总结,2019感恩遇见,2019感谢遇见。

写这篇文章的时候本来是没什么的思路的,但是我划着2019年自己的朋友圈,突然就知道了怎么写了,我把自己的盆友圈,按照时间线写出来那不就是我过去一年发生的大事了不是嘛?

昂创作鬼才,就是我,我就是你们的丙丙。

Tip:文章中的不好情绪希望不要影响到您,这个文章估计得不到收获,但是可以图个乐呵,阅读会比较顺畅。

正文

学费压力

这个是我大学班群的一个截图,是的之前的我就是那种交不起学费的仔,除了大一第一次入学交了学费,之后的生活费,学费都是自己实习期间到今年年初才还的。

今年年初,也就是在毕业的半年后,我还完了我的助学贷款,说实话当时感觉无债一身轻。

但是后来才知道这不过是一年的开始,还有太多太多等着我。

周XX就是我

周XX就是我

加班

我今年年初的第一条朋友圈,说实话,这很程序员。

我在老东家我记得印象比较深刻的一天,就是我离职那天。

我第一次在天还是亮着的时候,走在回家的路上,当时感觉这个世界都是陌生的,这一切也不像是真的,像一场梦,像一个泡泡,一碰就破的那种。

其实之前有很多不熟悉程序员这个行业的人问我,我们工资是不是很高呀,有高的有低的,但是高的肯定付出也是多的,你想嘛,老板给你50万一年,你一年赚不到200万以上他能给你?

我身边很多朋友工资都是很高了,但是他们付出也不是一般的多,这点大家要知道。

工作半年给爸妈的惊喜

工作半年的我,收获了自己的第一个年终奖,决定给爸妈换掉卡得不行的手机,买了比当时我的手机还要好的苹果8p顶配,不知道为啥给爸妈买啥都不心疼钱,还很开心哈哈。

老妈经常跟我抱怨手机看电视卡,每次我说要买手机的时候都说不喜欢,就跟我每次叫她旅游,她说没时间一样。

其实我知道是心疼钱,所以我是悄悄买的,现在她用得比我都要6了。

囧途

过年回家路上的一个插曲,回家的大巴士上有个阿姨睡着了,在我肩膀上安详的睡着,我不忍叫醒她,不过她应该几天没洗头了,味道一阵阵传入我的鼻子。

她靠着我安详的睡着,我甚至能听到耳畔那母猪均匀的呼吸声,我的眼角又湿了……

我不知道当时什么为啥穿这么绿,然后没多久跟女朋友也分了,难道……

我的眼角又湿了…….

返杭

我回杭州了,每次出门箱子都会被老妈莫名其妙塞满很多东西,辣椒面,她买的咖啡,小吃,还有路上的水果啥的。

每次家里待久了就很想出去,想逃离这个村子,但是,我一点都不想走……

别人努力出去,我努力回去,昂我是个怪人。

感悟

在回航的路上,感慨了自己的2018一年,就写出来了。

就像现在感慨马上要过去的2019年一样,我就是一个99%时间逗比,1%时间经常感慨的一个人。

长大后的第一个蛋糕

我在回杭的途中过了自己的23岁生日,其实我小学过后,就好像没有过自己的生日蛋糕,自己也不习惯过生日,大概是因为穷吧。

今年觉得一切好不容易呀,所以觉得这个仪式感不能少,于是威逼利诱下,叫跟我一起返途的小伙伴买了个小蛋糕,真好吃,以后还得买。

常态

你们都知道的,我之前老东家电商嘛,24小时待命是我们的常态,图中是我们最普通的样子,我去医院挂号的时候,线上的粉丝出了bug,当场就掏出电脑改了、测试、review、发布。

周围的人像看个另类一样看我,不过我本身就是个怪人,无伤大雅

决定

有一个夜晚,我烧毁了所有的记忆,从此我的梦就透明了,有一个早晨我扔掉了所有的昨天,从此我的脚步就轻盈了。

就在某天早上我做了个决定……

离职

我告别了玲珑这个秀气的花名。

是的我决定在这个夏天离职,离开老东家,说实话老东家的人都很好,也让我有了很大很大的成长,现在的技术广度大多得益于当时的各种场景,但是我还是选择了离开。

不为别的,因为钱,因为穷。

年初还完了自己的助学贷款,又有各种家里的事情,打工的父母工资本身就微薄,加上又多了房贷的压力,我入不敷出了,所以因为钱离开了这个地方。

其实提出离职的时候,Leader我们CTO,还有小伙伴都说了给我涨很多很多的钱,我已经动摇了。

但是以后离职这种东西,说了就说了,覆水难收,至于为啥,大家以后会懂的。

我家

可能你会说哇你都有房贷了,是不是有房了,那还穷?

我老家就是这样的,上个厕所都要跟猪在一个房间,我大一开始就摇摇欲坠,总得有个住的地方吧,所以爸妈拿出多年的积蓄东拼西凑筹足了首付,也算是有了一个像样的家,而且贵州县里的房子很便宜。

可能你都想不到就算是这样的一个首付,对于我们这样的家庭意味着什么吧,所以大学学费是我自己还的,所以后来我实习房租都要拿不出来,所以……

敖丙

是的我来到老东家了,花名也从玲珑变成了敖丙,知道为啥我的所有博客都叫敖丙了吧哈哈。

这中间面了几乎杭州所有的大厂,也拿了很多offer,所以我文章才从面试开始写的。

换了工作的我以为一切都马上好起来,但是事不如人愿,外婆病了,老妈病了,昂我在出了地铁站后不争气的哭了,气自己在这样的情况是那么无能为力。

人生不如意,十之八九

生活还是要继续的嘛,换工作后发现收入是多了不少,但是支出也多了,我还是负债磊磊,昂上个月还房贷没钱了,还是问三歪借的。

惬意

好在新东家是双休的,自己也有了多的时间去阅读,锻炼,甚至有时间每周去逛逛,坐坐发呆,像个老头

Vlog梦

你真的很适合写文章” 这是三歪对我说的一句话,在听到这句话的那个星期,这句话一直在脑海里挥之不去,但是也很纠结,因为本来是准备做个分享生活的up主的,装备都买好了。

昂你们能看到这里肯定也知道了,我选择了写作,我文章的个人色彩非常重,也插入了不少视频的元素,什么求赞求关注呀,还有跟大家问题的互动,我算是在文章里面圆了自己up主的梦吧。

写作

还好我写了,到现在刚好一个月半,在各个平台都收获了不少粉丝,三歪调侃我像个开挂的,其实我没太多感受,因为我也不知道熬了多少个日夜,而且一开始我就像三歪学了他总结的很多写作经验,站在巨人的肩膀上是要爽一点,少走了好多好多弯路。

同时,我也认识了很多大佬,阿里的师兄果哥、Hollis、阿里云的风云学姐,沉默王二、程序员小灰等等。

还有跟我同龄的我没有三颗心脏、JavaGuide等等,当然还有java3y,以前我都是看他们文章长大的,没想过我也有了他们微信嘻嘻。

还认识了各大博客网站的运营,说实话专业的就是不一样,我的文章也偶尔能得到他们的垂青给我推荐,在此真的很感谢他们

也得到好多小伙伴的认可,我在某些博客的数据惨不忍睹,但还是有读者一个个给我点赞,给我鼓励,谢谢。

就比如我只有14个粉丝的简书,还是有小伙伴说我写得不错,给我一个个的点赞点过去。

习惯了

说实话写到了现在,我想我离不开这样的生活了,不然我也不知道干啥,反正周末不写文章也是看书、闲逛。

一个月我写了将近15篇文章,还好文章里面很多都是网上有资料,我自己有笔记,不过我真的不行了,现在周末就是跟三歪往公司走,我两个住公司旁边,走路一分钟那种,所以几乎30天我30天都会去公司。

因为要保持这个更新频率只能牺牲周末了,毕竟平时都有自己的事情,所以我的红牛是一罐一罐的来。

大家也发现了,我的排版,表情包都很多,这个真的耗时,不过大家喜欢看一切都是值得的。

我写一次文章屏幕基本上都是这样的,然后有空了再把不要的删掉,表情包保存起来。

一年技术变化

这一年技术的广度变化很大,接触了很多不同的技术栈,跟之前实习公司的技术栈截然不同,深度也在慢慢深入,特别是进入蘑菇之后,公司全是自研的,让我看到了优良中间件的特性,基于RocketMQ和Kafka有点研发的消息中间件可还行。

从阿里学姐那得知终面我的老大居然是RocketMQ的开山鼻祖之一,身边卧虎藏龙的优秀仔太多了,得好好学习。

现在负责公司的广告投放系统,希望把它做大做强!!!

自己写文章也在不断给自己扫盲,回顾知识点细节,其实还算是个好事情。

现状

11.12号创建的git,现在star已经3.6k了,也在一个月内上了五次Trending,刚满月的他,以后承蒙大家多多关照了,希望以后能成为大家面试突击扫盲还有学习新知识点的地方,我们一起养肥他。

我写了哪些系列?

《吊打面试官》系列:

  • 我之所以会选择面试题材,是因为这次跳槽我几乎面了所有杭州叫得上名字的公司了,效果都挺不错的,其实我的技术一般性,但是我骚嘛,所以我表达会好很多,面试官的感觉都不错,那我就在想为啥不把自己知道的面试点,用自己的话语表达出来呢?

    于是就有了这个系列,但是我这个人为了博眼球就取了这个名字,所以后面很多人就喷我,诺现在文章的前言我都加了下面这句话,希望大家下次喷我换个支点喷我。

所有文章的名字只是我的噱头,我们应该有一颗谦逊的心,所以希望大家怀着空杯心态好好学,一起进步。

《程序人生》系列:

  • 这个系列主要是分享自己和身边小伙伴的个人经历,经验等等。

    因为我身边的励志的例子太多太多了,我就很想出这样的一个专题去写出来给大家看,比如我专科的亦师亦友的朋友,这两天拿了阿里技术专家的offer,我专科的昊哥做字节的Leader,还有渣本的腾讯吴,渣本的Google杰等等等….

    这个专题就当是鸡汤吧大家,能影响一个人是一个人吧,还是那句话我发现读者很多还是学生,或者是刚出社会的盆友,能让大家少走点弯路也是好的,而且很多多年经验的学长也说还是有些许收获的。

    还是那句话,很多人就喷我这样都是少数啊什么什么的,但是在我身边就是很多。

    对于学生,我们说的每句话可能都是他们对社会的认知,大家喷的时候私聊我就好了,别破了别人的梦,自己不努力,也别拉别人下水。

《吐血整理》系列:

  • 写这个的系列的初衷就是想把大家常用的工具,书单等整理出来,把好的东西安利给大家,也希望从大家那等到一些好东西,后续还会写大家希望我整理的东西的。

    一样的还是我整理个书单也有人喷,还是那句话,不爱看不看就好了,私聊我喷,总有需要的人。

《大厂面试》系列:

  • 筹备中,形式应该先写一部分身边小伙伴大厂的面试经历和面试题讲解,后续只能靠投稿了。

《有生之年》系列:

  • 突然想到的一个系列,只是突然想到这个名字哈哈。

JavaFamily-->三太子敖丙

是的第一个月我的公众号就叫【JavaFamily】初衷是把所有Java后端相关的技术栈都写一遍,但是后来发现我的个人色彩太重了,我也写不来纯技术的文章,我骚嘛,所以干脆取个跟我花名相关的名字,本来想就叫【敖丙】的,但是有人先注册了,而且商标其实已经被注册了。

那我就发起了投票,【三太子敖丙】用一票的微弱优势获胜了,以后这个ID估计会陪我直到老去的吧。

Tip:有小伙伴提示我要记得不要侵权,所以我直接注册了商标,多谢提醒,有没有人看咋们都还是不能违法嘛。

恰到了饭

昂我现在已经有了恰饭的收入了,但是说实话不多600块吧,我git增速还挺快的,拉钩教育决定赞助我,每个月给我几百块我就需要在git加个banner就好了。

我粉丝少,一个月也恰不了几次,还是那句话,如果按照工时算在我写文章的的时间,基本上就是一场没有回报的投入吧,血亏的那种,单纯为了恰饭我可能十年都达不到工资的收入。

这就当是写给未来的自己看的吧,一年后或许我有2万粉了,我能恰1200的饭了也说不定对吧。

有人又要diss我了为了恰饭而写,说实话没有恰饭我一样要写,但是应该动力没那么足吧,我要保持一周两更几乎就是贡献自己所有的时间了,三歪知道的我们周末也在公司写文章,就出去玩半天。

像上周那样一周发三篇,我就要工作日熬夜一两个晚上写,发布的晚上还要熬夜改排版,我文章的排版你们也看到了,个人自恋的认为排版还是很用心,错别字多的时候,基本上就是熬夜糊涂的时候把哈哈。

我不知道这样的状态能持续多久,朋友调侃道老东家加班这么多你都有女朋友,来了双休的公司反而更忙了女朋友也找不到,我不知道值不值得,或许只有未来和时间能告诉我值得不值得了。

2020期许

没啥期许,希望明年这个时候我还没放弃写作,家里一切ok,最好能找个女仔哈哈。

做个俗人,贪财好色。

总结

过去的一年,总的来说是美好的一年,我也知道新的一年是更加美好的一年,大家是不是发现我没你们想象的那么风光,以为我的工资肯定过的很潇洒,相反我也偶尔要借钱生活,不过明年肯定不会了,毕竟家里的好起来了。

你看,我这不是就帮家里换了那个村里唯一的大头电视,买了家里的第一个冰箱,这不就好起来了嘛。

在博客平台我才度过了一个月半,未来的路还很长,也希望自己以后的文章大家能多多支持,多多批评指正,我们一起进步。

黑夜无论怎样悠长,白昼总会到来

查看原文

赞 19 收藏 5 评论 10

认证与成就

  • 获得 2 次点赞
  • 获得 2 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 2 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2019-07-05
个人主页被 277 人浏览