搜 索

那些年被淘汰的技术

  • 231阅读
  • 2022年08月14日
  • 0评论
首页 / Java/Go/Python / 正文

前言:技术的"生死轮回"

"在这个行业里,唯一不变的就是变化本身。" —— 某位被迫学了三遍前端框架的后端程序员

如果你是一个有着十年以上工作经验的 Java 程序员,那么恭喜你,你已经见证了无数技术的兴衰更替。那些曾经让你熬夜加班、掉光头发的技术,如今可能已经静静躺在技术博物馆的角落里,等待着后人前来"考古"。

今天,让我们一起翻开历史的篇章,缅怀那些曾经辉煌一时、如今却逐渐淡出舞台的 Java 技术。别担心,这不是一篇让你伤感的文章——毕竟,送走它们之后,我们又迎来了更多让我们加班的新技术。


第一章:被淘汰的主要原因

在正式开始"悼念"之前,让我们先来分析一下,为什么这些技术会被淘汰:

1. 技术发展的自然规律

就像诺基亚被智能手机取代一样,技术的发展是不可阻挡的洪流。新技术往往能够提供更高的开发效率、更好的性能表现和更优雅的解决方案。当 Spring Boot 出现时,那些还在手动配置 XML 的程序员们,眼泪都流下来了——不是因为不舍,而是因为太香了。

2. 安全性和可靠性的硬伤

某些技术在设计之初就存在安全隐患,随着互联网的发展和攻击手段的升级,这些隐患变得越来越致命。当一个技术三天两头爆出高危漏洞时,再深厚的感情也扛不住运维的怒火。

3. 复杂性——程序员的头号敌人

"简单就是美,复杂就是加班。"

有些技术设计得过于复杂,学习曲线陡峭得像珠穆朗玛峰,配置文件多得像是在写一部长篇小说。当程序员需要花费 80% 的时间在配置和调试上,只有 20% 的时间在实际业务开发上时,这项技术就离被淘汰不远了。

4. 社区和生态的萎缩

技术的生命力很大程度上取决于其社区的活跃度。当 Stack Overflow 上的相关问题越来越少,GitHub 上的 star 数开始停滞,那些曾经的技术明星就开始走向黄昏了。


第二章:那些年,我们一起追过的"前任"

1. Servlet/JSP:Web 开发的"老祖宗"

生卒年代:1997年至今(名义上还活着,实际上已经退居二线)

辉煌时刻

// 曾经,我们是这样写 Web 应用的
public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, 
                         HttpServletResponse response) 
            throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<h1>Hello, World!</h1>");
        out.println("</body></html>");
    }
}

淘汰原因

  • 在 Java 代码里写 HTML?在 HTML 里嵌 Java 代码?这操作简直是代码界的"油水混合"
  • JSP 的 <% %> 标签让代码变得像一锅乱炖
  • 没有前后端分离的概念,改个页面样式都要重启服务器

接班人:Spring MVC + RESTful API + 前端框架(Vue/React)

墓志铭"我不是被打败的,我只是太老了。"


2. Struts:曾经的"一哥"

生卒年代:2000年 - 2017年(Struts 2 在这一年爆出了致命漏洞)

辉煌时刻

在 21 世纪的头十年,如果你不会 Struts,你都不好意思说自己是 Java Web 开发者。面试官问的第一个问题就是:"讲一下 Struts 的工作流程"。

<!-- 还记得这个经典的 struts-config.xml 吗? -->
<struts-config>
    <form-beans>
        <form-bean name="loginForm" 
                   type="com.example.LoginForm"/>
    </form-beans>
    <action-mappings>
        <action path="/login"
                type="com.example.LoginAction"
                name="loginForm"
                scope="request"
                validate="true"
                input="/login.jsp">
            <forward name="success" path="/welcome.jsp"/>
            <forward name="failure" path="/login.jsp"/>
        </action>
    </action-mappings>
</struts-config>

淘汰原因

  • 配置文件多得能绕地球一圈
  • Struts 2 的安全漏洞层出不穷,2017年的 S2-045 漏洞直接让无数企业的服务器"裸奔"
  • 架构设计过于复杂,ActionForm、Action、ActionForward... 概念多到让人头秃

接班人:Spring MVC(以优雅的注解配置完胜)

墓志铭"我曾经是最受欢迎的,直到安全漏洞让我身败名裂。"


3. EJB(Enterprise JavaBeans):企业级的"噩梦"

生卒年代:1998年 - 2010年前后(EJB 3.0 虽然有所改善,但已经难以挽回颓势)

辉煌时刻

在 Sun Microsystems 的愿景中,EJB 是构建企业级分布式应用的终极解决方案。PPT 上的架构图看起来无比优雅...

// 这只是冰山一角
// 你还需要写一堆 XML 配置文件、Home 接口、Remote 接口...
@Stateless
@Remote(HelloRemote.class)
@Local(HelloLocal.class)
public class HelloBean implements HelloRemote, HelloLocal {
    public String sayHello() {
        return "Hello, EJB!";
    }
}

淘汰原因

  • 开发一个简单的 Hello World 需要写 N 个文件
  • 部署流程复杂得像发射火箭
  • 重量级容器(WebLogic、WebSphere)价格昂贵,启动慢得能泡一杯咖啡
  • 测试困难,单元测试几乎是不可能完成的任务

接班人:Spring Framework(轻量级、易测试、控制反转)

墓志铭"我不是不够强大,我只是太重了,重到程序员扛不动。"


4. Java Applet:浏览器里的"失落世界"

生卒年代:1995年 - 2017年(Oracle 正式宣布弃用)

辉煌时刻

在 Flash 还没有一统天下之前,Java Applet 曾经是网页动态内容的希望之星。

<!-- 曾经的浏览器页面 -->
<applet code="GameApplet.class" width="400" height="300">
    Your browser doesn't support Java Applets.
</applet>

淘汰原因

  • 安全漏洞多到让安全专家都怕了
  • 需要安装 Java 插件,用户体验极差
  • 启动速度慢,每次加载都像是在等待宇宙大爆炸
  • HTML5 + JavaScript 的崛起彻底终结了它的命运
  • 各大浏览器纷纷移除对 NPAPI 插件的支持,直接判了死刑

接班人:HTML5、JavaScript、WebAssembly

墓志铭"我曾让网页动起来,可惜我自己却停下了脚步。"


5. OSGi:模块化的"先驱者"

生卒年代:1999年至今(还活着,但在应用开发领域已边缘化)

辉煌时刻

OSGi 是 Java 模块化的先驱,Eclipse IDE 就是基于它构建的。

// Bundle-SymbolicName: com.example.hello
// Bundle-Version: 1.0.0
// Export-Package: com.example.hello.api
// Import-Package: org.osgi.framework

public class Activator implements BundleActivator {
    public void start(BundleContext context) {
        System.out.println("Hello, OSGi!");
    }
    public void stop(BundleContext context) {
        System.out.println("Goodbye, OSGi!");
    }
}

淘汰原因

  • 类加载器地狱(ClassLoader Hell)——当你以为解决了类冲突,新的冲突又出现了
  • 配置复杂,对开发者不友好
  • 大多数应用不需要运行时动态安装/卸载模块的能力
  • Java 9 推出了原生的 JPMS(Java Platform Module System)

接班人:Java 9 Module System、Spring Boot 的 Fat JAR、容器化部署

墓志铭"我太超前了,超前到世界还没准备好接受我。"


6. XML Web Services(SOAP/WSDL):臃肿的"老绅士"

生卒年代:2000年 - 2010年代(仍在银行、政府系统中苟延残喘)

辉煌时刻

在 RESTful API 出现之前,SOAP Web Services 是企业级系统集成的标准方案。

<!-- 一个简单的请求,需要这么多"废话" -->
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header>
        <!-- 可能还有一堆安全相关的头 -->
    </soap:Header>
    <soap:Body>
        <m:GetPrice xmlns:m="http://www.example.org/stock">
            <m:StockName>IBM</m:StockName>
        </m:GetPrice>
    </soap:Body>
</soap:Envelope>

淘汰原因

  • 报文臃肿,一个简单的调用可能 90% 都是 XML 标签
  • WSDL 文件复杂到需要专门的工具来阅读
  • 对开发者不友好,调试困难
  • 性能开销大,解析 XML 本身就是一种浪费

接班人:RESTful API + JSON

墓志铭"我很严谨,但世界需要的是简单。"


7. Hibernate Criteria API(旧版):ORM 的"繁文缛节"

生卒年代:早期 Hibernate 版本 - Hibernate 5.x(被 JPA Criteria API 取代)

辉煌时刻

// 旧版 Criteria 查询
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.eq("name", "Joey"));
criteria.add(Restrictions.gt("age", 18));
criteria.addOrder(Order.asc("createTime"));
List<User> users = criteria.list();

淘汰原因

  • 类型不安全,字段名用字符串表示,拼写错误只能在运行时发现
  • 不符合 JPA 规范
  • 链式调用的方式不够优雅

接班人:JPA Criteria API、QueryDSL、Spring Data JPA

墓志铭"我尽力了,但类型安全才是王道。"


8. Java Date/Calendar:时间处理的"噩梦"

生卒年代:JDK 1.0 - JDK 8(虽然还能用,但已被官方"劝退")

辉煌时刻

// 曾经,我们是这样处理日期的
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, 1);

// 月份从 0 开始???
int month = calendar.get(Calendar.MONTH); // 0 = January, WTF?

// 格式化还要用 SimpleDateFormat,还不是线程安全的
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String formatted = sdf.format(date); // 多线程下可能出问题

淘汰原因

  • Date 类设计糟糕,很多方法早已废弃
  • Calendar 月份从 0 开始,这是什么反人类设计?
  • SimpleDateFormat 线程不安全,生产事故的常客
  • 时区处理复杂且容易出错
  • 可变对象,容易被意外修改

接班人:Java 8 的 java.time 包(LocalDateLocalDateTimeZonedDateTime

墓志铭"月份从 0 开始这件事,我知道错了,但我改不了。"


9. Ant:构建工具的"原始人"

生卒年代:2000年 - 2010年代初(仍有遗留系统在使用)

辉煌时刻

<!-- build.xml 的回忆 -->
<project name="HelloWorld" default="compile">
    <property name="src.dir" value="src"/>
    <property name="build.dir" value="build"/>
    <property name="lib.dir" value="lib"/>
    
    <path id="classpath">
        <fileset dir="${lib.dir}" includes="*.jar"/>
    </path>
    
    <target name="clean">
        <delete dir="${build.dir}"/>
    </target>
    
    <target name="compile" depends="clean">
        <mkdir dir="${build.dir}"/>
        <javac srcdir="${src.dir}" destdir="${build.dir}">
            <classpath refid="classpath"/>
        </javac>
    </target>
</project>

淘汰原因

  • 没有内置依赖管理,JAR 包要手动下载和管理
  • XML 配置繁琐,写构建脚本像在写小说
  • 没有约定优于配置的理念,每个项目的构建脚本都可能不一样
  • 对于复杂项目,构建脚本可能比业务代码还多

接班人:Maven → Gradle

墓志铭"在没有包管理器的年代,我们手动管理 JAR 包,那是一段艰苦但难忘的岁月。"


10. Log4j 1.x:日志界的"老前辈"

生卒年代:2001年 - 2015年(官方宣布停止维护)

辉煌时刻

# log4j.properties,多少人的青春回忆
log4j.rootLogger=INFO, console, file

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

淘汰原因

  • 架构老旧,不支持异步日志
  • 配置文件格式不够灵活
  • 性能不如后来者
  • 不再维护,安全漏洞无人修复

接班人:Logback、Log4j 2.x(然后 Log4j 2 在 2021 年爆出了核弹级漏洞 Log4Shell,安全团队又哭了)

墓志铭"我是日志框架的开创者,我的继任者也没让我省心。"


11. Swing/AWT:桌面应用的"遗老遗少"

生卒年代:1995年(AWT)/ 1998年(Swing)- 至今(名存实亡)

辉煌时刻

// 曾经的桌面应用开发
public class HelloSwing extends JFrame {
    public HelloSwing() {
        setTitle("Hello Swing");
        setSize(400, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        JButton button = new JButton("Click Me!");
        button.addActionListener(e -> 
            JOptionPane.showMessageDialog(this, "Hello, World!"));
        
        add(button);
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> 
            new HelloSwing().setVisible(true));
    }
}

淘汰原因

  • 界面样式老旧,像是上世纪的产物(因为它确实是)
  • 跨平台意味着在所有平台上都一样丑
  • Web 应用和移动应用的崛起,桌面应用市场萎缩
  • JavaFX 也没能拯救 Java 桌面开发,最终也被 Oracle 放弃

接班人:Electron、Web 应用、移动应用

墓志铭"Write Once, Look Ugly Everywhere."


第三章:正在走向衰落的技术

有些技术虽然还没有完全被淘汰,但已经显露出衰落的迹象:

1. JSF(JavaServer Faces)

虽然还在更新,但使用率持续下降。组件化的思想没有错,但 JSF 的实现方式太过笨重。

2. XML 配置

从 Spring Boot 的成功可以看出,开发者更喜欢注解和约定优于配置。XML 配置文件正在逐渐消失。

3. WAR 部署

传统的 WAR 包部署方式正在被 Spring Boot 的可执行 JAR 和容器化部署所取代。

4. 传统 MVC 服务端渲染

前后端分离已成主流,传统的服务端渲染(Thymeleaf、Freemarker)使用场景越来越少。


第四章:从历史中学习

技术选型的智慧

  1. 不要追新过度:新技术需要时间来验证,1.0 版本的框架慎用。
  2. 关注社区活跃度:没有活跃社区的技术,就像没有售后服务的产品。
  3. 学习思想而非工具:Spring 可能会被淘汰,但依赖注入的思想不会。
  4. 保持学习能力:今天的最佳实践,可能是明天的反面教材。

程序员的生存法则

public class Programmer {
    private Stack<String> skills = new Stack<>();
    
    public void survive() {
        while (true) {
            String oldSkill = learnNewTechnology();
            if (skills.size() > 10) {
                String forgotten = skills.remove(0);
                log.info("忘掉了: {}, 反正也用不上了", forgotten);
            }
            skills.push(oldSkill);
        }
    }
    
    private String learnNewTechnology() {
        // TODO: 又要学新东西了...
        return "某个三个月后就会被淘汰的框架";
    }
}

结语:技术的轮回

"太阳底下无新事。"

技术在变,但解决问题的本质需求不变。从 Servlet 到 Spring Boot,从 SOAP 到 REST,从单体到微服务——每一次变革都是对"如何更高效地解决问题"这个命题的新回答。

那些被淘汰的技术,不是失败者。它们是铺路石,是垫脚石,是站在它们肩膀上才有了今天这些"更好"的技术。

作为程序员,我们要做的不是为旧技术的消亡而惋惜,而是要:

  1. 理解技术演进的规律——知道为什么会变,才能预测未来会怎么变
  2. 掌握不变的核心原则——设计模式、架构思想、编程范式,这些比具体框架更有价值
  3. 保持开放的学习心态——今天学的技术,可能五年后就会出现在"被淘汰的技术"列表里

最后,让我们向那些曾经陪伴我们的技术致敬。感谢 Struts,让我们知道了配置地狱的可怕;感谢 EJB,让我们学会了珍惜轻量级框架;感谢 Java Date,让我们明白了好的 API 设计有多重要。

没有你们的"牺牲",就没有今天这些"更好"的技术。

当然,今天的"更好",也可能是明天的"被淘汰"。

这就是技术的轮回,这就是程序员的宿命。

共勉。


本文作者正在学习第 N 个新框架,预计该框架的生命周期为 3-5 年。

评论区
暂无评论
avatar