【Java企业生态系统的演进】从单体J2EE到云原生微服务
Java企业生态系统的演进:从单体J2EE到云原生微服务
目录标题
- Java企业生态系统的演进:从单体J2EE到云原生微服务
- 摘要
- 1. 引言
- 2. 整体框架演进:从原始Java到Spring Cloud
- 2.1 原始Java阶段(1995-1999)
- 2.2 J2EE阶段(1999-2004)
- 2.3 轻量级框架阶段(2002-2006)
- 2.4 Spring框架阶段(2004-2012)
- 2.5 Spring Boot阶段(2014-2018)
- 2.6 Spring Cloud阶段(2015-至今)
- 3. 数据访问技术演进:从JDBC到Spring Data
- 3.1 JDBC阶段(1997-2002)
- 3.2 DAO模式阶段(2000-2005)
- 3.3 ORM(Hibernate)阶段(2002-2008)
- 3.4 JPA阶段(2006-2012)
- 3.5 Spring Data阶段(2011-至今)
- 4. Web开发范式演进:从Servlet/JSP到前后端分离
- 4.1 Servlet/JSP阶段(1997-2003)
- 4.2 Struts阶段(2000-2006)
- 4.3 JSF阶段(2004-2010)
- 4.4 Spring MVC阶段(2005-2015)
- 4.5 RESTful API阶段(2010-2017)
- 4.6 前后端分离阶段(2015-至今)
- 5. 演进模式分析与展望
- 5.1 演进模式分析
- 5.2 未来展望
- 6. 结论
- 附 Java企业生态系统演进代码示例
- Java企业生态系统演进代码示例
- 主要框架演进
- 1. 原始Java阶段 (1995-1999)
- 2. J2EE阶段 (1999-2004)
- 3. Spring框架阶段 (2004-2012)
- 4. Spring Boot阶段 (2014-2018)
- 5. Spring Cloud阶段 (2015-至今)
- 数据访问技术演进
- Web开发范式演进
摘要
本文系统性地分析了Java企业生态系统自1995年诞生以来的演进历程,重点关注三条主要技术路线:整体框架演进、数据访问技术演进以及Web开发范式演进。研究表明,Java生态系统的发展遵循了从复杂到简化、从紧耦合到松耦合、从单体到分布式的总体趋势。通过对各个演进阶段的技术特征、架构模式和设计理念的深入分析,本文揭示了推动Java技术栈演进的核心驱动力:开发效率提升、维护成本降低以及适应不断变化的业务需求。研究结果对理解企业软件架构的演进规律和预测未来发展趋势具有重要的理论和实践意义。
关键词:Java企业生态系统、框架演进、软件架构、Spring、微服务
1. 引言
Java作为一种面向对象的编程语言,自1995年诞生以来,已经发展成为企业级应用开发的主流技术。在这一演进过程中,Java生态系统经历了从简单到复杂再到简化的辩证发展,形成了丰富多样的框架、工具和最佳实践。本文旨在从学术角度系统梳理Java企业生态系统的演进历程,深入分析每一次技术变革背后的动因和影响,为理解软件架构的演进规律提供理论参考。
研究表明,Java生态系统的演进可以从三个维度进行考察:整体框架演进、数据访问技术演进以及Web开发范式演进。这三条技术路线虽各有侧重,但相互影响、共同推动了Java企业应用从最初的简单应用到当今的云原生微服务架构的转变。
2. 整体框架演进:从原始Java到Spring Cloud
2.1 原始Java阶段(1995-1999)
最初的Java应用开发主要依赖于Java SE(Standard Edition)提供的基础类库,开发者需要编写大量底层代码实现业务逻辑。这一阶段的特点是:
- 缺乏统一的企业级应用开发规范
- 应用架构高度依赖开发者个人经验
- 组件复用率低,维护成本高
- 分布式计算能力有限
在此阶段,开发者通常需要直接处理网络通信、线程管理、异常处理等底层问题,导致开发效率低下,代码质量参差不齐。
2.2 J2EE阶段(1999-2004)
1999年,Sun Microsystems发布了Java 2 Enterprise Edition(J2EE),首次为企业级Java应用提供了统一的规范和标准组件。J2EE包含了多个核心组件:
- Enterprise JavaBeans(EJB):提供分布式组件模型
- Java Servlet:处理HTTP请求
- JavaServer Pages(JSP):动态生成Web内容
- Java Transaction API(JTA):管理分布式事务
- Java Naming and Directory Interface(JNDI):提供命名和目录服务
- Java Message Service(JMS):实现企业消息传递
J2EE的出现标志着Java正式进入企业级应用开发领域。然而,随着实践的深入,J2EE的问题也逐渐显现:
- 过度设计和复杂的规范
- EJB组件模型过于笨重
- 配置繁琐,依赖大型应用服务器
- 开发周期长,学习曲线陡峭
这些问题导致了"J2EE疲劳"现象,为轻量级框架的兴起创造了条件。
2.3 轻量级框架阶段(2002-2006)
为了解决J2EE的复杂性问题,以Hibernate、Struts和Spring为代表的轻量级框架开始兴起。这些框架的特点是:
- 专注于解决特定领域问题
- 简化配置,减少样板代码
- 不依赖于大型应用服务器
- 提高开发效率和代码可测试性
其中,Rod Johnson在2002年发表的《Expert One-on-One J2EE Design and Development》一书中提出的Spring框架,通过依赖注入(DI)和面向切面编程(AOP)等创新概念,为Java企业级应用开发带来了革命性变化。
2.4 Spring框架阶段(2004-2012)
Spring框架逐渐成为Java企业应用开发的事实标准,其核心思想是:
- 控制反转(IoC)容器:管理对象生命周期和依赖关系
- 面向切面编程(AOP):分离横切关注点
- 声明式事务管理:简化事务控制
- 统一的异常体系:简化异常处理
- 与其他框架的无缝集成:如Hibernate、JPA等
Spring框架的模块化设计允许开发者根据需要选择特定功能,极大地提高了开发灵活性。然而,随着Spring生态系统的不断扩展,配置的复杂性再次成为问题。
2.5 Spring Boot阶段(2014-2018)
为了解决Spring框架配置复杂的问题,Pivotal团队于2014年推出了Spring Boot。Spring Boot基于"约定优于配置"原则,提供了以下核心特性:
- 自动配置:根据类路径自动配置Spring应用
- 起步依赖:简化Maven/Gradle配置
- 内嵌服务器:内置Tomcat、Jetty或Undertow
- 外部化配置:支持多种配置源
- Actuator:提供生产级监控和管理功能
Spring Boot极大地简化了Spring应用的开发流程,减少了配置代码,使开发者能够更加专注于业务逻辑。
2.6 Spring Cloud阶段(2015-至今)
随着微服务架构的兴起,Spring Cloud应运而生。Spring Cloud是一套基于Spring Boot的微服务开发工具,提供了:
- 服务注册与发现:如Eureka、Consul
- 客户端负载均衡:如Ribbon
- 声明式REST客户端:Feign
- 分布式配置:Spring Cloud Config
- 断路器:Hystrix
- API网关:Zuul、Spring Cloud Gateway
- 分布式追踪:Sleuth、Zipkin
Spring Cloud为微服务架构的实现提供了完整的技术栈,使得复杂的分布式系统开发变得相对简单,推动了Java应用从单体架构向微服务架构的转变。
3. 数据访问技术演进:从JDBC到Spring Data
3.1 JDBC阶段(1997-2002)
Java Database Connectivity(JDBC)是Java最早的数据库访问API,提供了与关系型数据库交互的基础能力。JDBC的特点是:
- 直接操作SQL语句
- 手动管理数据库连接和资源释放
- 手动映射结果集到Java对象
- 异常处理繁琐
使用JDBC进行数据库操作通常需要编写大量样板代码,例如:
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {conn = DriverManager.getConnection(URL, USER, PASSWORD);stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");stmt.setLong(1, userId);rs = stmt.executeQuery();if (rs.next()) {User user = new User();user.setId(rs.getLong("id"));user.setName(rs.getString("name"));// 更多映射...return user;}return null;
} catch (SQLException e) {throw new DataAccessException(e);
} finally {// 资源释放代码...
}
这种方式不仅冗长,而且容易出错,尤其是在处理资源释放和异常时。
3.2 DAO模式阶段(2000-2005)
为了解决JDBC直接使用的问题,数据访问对象(Data Access Object,DAO)模式开始流行。DAO模式的核心思想是:
- 分离数据访问逻辑和业务逻辑
- 封装数据库访问细节
- 提供面向对象的数据访问接口
- 实现数据访问的可插拔性
典型的DAO实现包括:
public interface UserDao {User findById(Long id);void save(User user);void update(User user);void delete(User user);
}public class JdbcUserDao implements UserDao {// JDBC实现...
}
DAO模式虽然提高了代码的组织性,但并未从根本上解决JDBC使用的繁琐问题。
3.3 ORM(Hibernate)阶段(2002-2008)
对象关系映射(Object-Relational Mapping,ORM)技术的出现,特别是Hibernate框架,彻底改变了Java数据访问的方式。ORM的核心特性包括:
- 自动映射Java对象和数据库表
- 透明的持久化机制
- 缓存机制提高性能
- 复杂查询支持
- 事务管理
使用Hibernate,开发者可以通过简单的注解或XML配置实现对象与数据库的映射:
@Entity
@Table(name = "users")
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(name = "username")private String name;// getters and setters...
}
Hibernate大大简化了数据访问代码,但其配置复杂性和学习曲线仍然较高。
3.4 JPA阶段(2006-2012)
为了标准化ORM技术,Java社区提出了Java Persistence API(JPA)规范。JPA提供了:
- 统一的ORM标准
- 供应商中立的API
- 标准化的查询语言(JPQL)
- 标准化的对象生命周期管理
JPA的出现使得应用程序可以轻松切换底层ORM实现(如Hibernate、EclipseLink等),提高了代码的可移植性。
3.5 Spring Data阶段(2011-至今)
Spring Data进一步简化了数据访问层的开发,其核心思想是通过接口定义和约定减少样板代码。Spring Data的特点包括:
- 基于接口的DAO自动实现
- 方法名约定自动生成查询
- 分页和排序支持
- 自定义查询注解
- 多数据源支持
- 非关系型数据库支持
使用Spring Data,开发者只需定义接口,无需编写实现类:
public interface UserRepository extends JpaRepository<User, Long> {User findByName(String name);List<User> findByAgeGreaterThan(int age);@Query("SELECT u FROM User u WHERE u.email LIKE %:domain")List<User> findByEmailDomain(@Param("domain") String domain);
}
Spring Data极大地提高了数据访问层的开发效率,是当前Java数据访问技术的主流选择。
4. Web开发范式演进:从Servlet/JSP到前后端分离
4.1 Servlet/JSP阶段(1997-2003)
Java Web开发最初基于Servlet和JSP技术:
- Servlet:处理HTTP请求和响应
- JSP:混合HTML和Java代码生成动态内容
- JavaBeans:封装数据
这一阶段的Web应用通常采用Model 1架构,即JSP页面直接处理请求并生成响应。这种架构在简单应用中表现良好,但随着应用复杂性增加,代码维护变得困难。
4.2 Struts阶段(2000-2006)
Apache Struts框架引入了Model-View-Controller(MVC)模式,将Web应用分为三个部分:
- Model:业务逻辑和数据访问
- View:表现层,通常是JSP
- Controller:处理请求,协调Model和View
Struts的核心组件包括:
- ActionServlet:中央控制器
- ActionForm:封装表单数据
- Action:处理具体业务逻辑
- struts-config.xml:配置文件
Struts改进了Web应用的架构,但其配置繁琐且缺乏灵活性。
4.3 JSF阶段(2004-2010)
JavaServer Faces(JSF)是Java EE的标准Web框架,引入了组件化开发模型:
- UI组件模型:预定义的可重用组件
- 导航模型:声明式页面导航
- 托管Bean:后台Java对象
- 事件驱动模型:类似桌面应用开发
JSF简化了复杂UI的开发,但其生命周期复杂,性能问题明显,逐渐被更轻量级的框架所取代。
4.4 Spring MVC阶段(2005-2015)
Spring MVC是Spring框架的Web模块,提供了一种轻量级的MVC实现:
- DispatcherServlet:中央控制器
- 基于注解的控制器
- 灵活的视图解析
- 数据绑定和验证
- 与Spring生态系统无缝集成
Spring MVC的简洁性和灵活性使其成为长期流行的Web框架:
@Controller
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/{id}")public String getUser(@PathVariable Long id, Model model) {model.addAttribute("user", userService.findById(id));return "userDetails";}
}
4.5 RESTful API阶段(2010-2017)
随着移动应用和单页应用(SPA)的兴起,RESTful API逐渐成为主流的Web开发模式:
- 资源导向设计
- 标准HTTP方法语义(GET、POST、PUT、DELETE)
- 无状态通信
- JSON/XML数据交换
- 超媒体链接(HATEOAS)
Spring MVC和后来的Spring Boot都提供了优秀的RESTful API支持:
@RestController
@RequestMapping("/api/users")
public class UserApiController {@Autowiredprivate UserService userService;@GetMapping("/{id}")public User getUser(@PathVariable Long id) {return userService.findById(id);}@PostMapping@ResponseStatus(HttpStatus.CREATED)public User createUser(@RequestBody User user) {return userService.save(user);}
}
4.6 前后端分离阶段(2015-至今)
最新的Web开发范式是完全的前后端分离:
- 后端:专注于API提供和业务逻辑
- 前端:使用JavaScript框架(React、Angular、Vue.js)构建客户端应用
- 通过API进行数据交换
- 各自独立开发、测试和部署
这种架构带来了多种优势:
- 关注点分离,专业分工
- 提高开发效率
- 更好的用户体验
- 多端复用后端API(Web、移动、桌面)
5. 演进模式分析与展望
5.1 演进模式分析
通过对Java企业生态系统演进的系统分析,可以发现以下关键模式:
- 复杂性循环:从简单到复杂再到简化的循环演进
- 关注点分离:持续细化和分离系统关注点
- 标准化与创新:标准化与创新相互促进
- 开发效率驱动:开发效率始终是核心驱动力
- 适应性演进:对业务需求变化的持续适应
5.2 未来展望
Java企业生态系统的未来发展可能包括:
- 云原生技术深化:如GraalVM、Quarkus等
- 响应式编程模型普及:如Project Reactor、RxJava
- 函数式编程范式融合:函数式特性在企业应用中的应用
- 低代码/无代码平台兴起:降低开发门槛
- AI辅助开发:人工智能辅助编码和测试
6. 结论
本文系统梳理了Java企业生态系统在框架、数据访问和Web开发三个维度的演进历程。研究表明,Java生态系统的发展遵循了从复杂到简化、从紧耦合到松耦合、从单体到分布式的总体趋势。这一演进过程不仅反映了技术本身的发展,也体现了软件工程理念的进步,对理解企业软件架构的演进规律具有重要的理论和实践意义。
Java企业生态系统的成功在于其持续创新与适应能力,未来仍将继续演进以应对新的技术挑战和业务需求。
附 Java企业生态系统演进代码示例
一套简单明了的代码示例,展示了Java企业应用从最早期到现代云原生架构的演变过程。
Java企业生态系统演进代码示例
这些代码示例覆盖了六大关键演进阶段和三条主要技术路线:
主要框架演进
1. 原始Java阶段 (1995-1999)
// 使用原始JDBC连接数据库的例子
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;try {// 手动加载JDBC驱动Class.forName("com.mysql.jdbc.Driver");// 手动创建数据库连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");// 创建并执行SQL语句stmt = conn.createStatement();rs = stmt.executeQuery("SELECT * FROM users");// 手动处理结果集while (rs.next()) {System.out.println("User: " + rs.getString("name"));}
} catch (Exception e) {e.printStackTrace();
} finally {// 手动关闭所有资源...
}
2. J2EE阶段 (1999-2004)
展示了复杂的EJB组件模型,需要定义多个接口和实现类:
// 远程接口
public interface User extends EJBObject {String getName() throws RemoteException;void setName(String name) throws RemoteException;
}// Bean实现类 - 必须实现多个生命周期方法
public class UserBean implements EntityBean {private EntityContext context;private Long id;private String name;// 必须实现EntityBean的所有方法public void setEntityContext(EntityContext context) { this.context = context; }public void unsetEntityContext() { this.context = null; }public void ejbActivate() {}public void ejbPassivate() {}// ...更多方法...
}
3. Spring框架阶段 (2004-2012)
展示了注解配置和依赖注入:
@Service
public class UserServiceImpl implements UserService {private final UserDao userDao;@Autowiredpublic UserServiceImpl(UserDao userDao) {this.userDao = userDao;}@Override@Transactional(readOnly = true)public User getUser(Long id) {return userDao.findById(id);}
}
4. Spring Boot阶段 (2014-2018)
展示自动配置和简化开发:
@SpringBootApplication
public class UserManagementApplication {public static void main(String[] args) {SpringApplication.run(UserManagementApplication.class, args);}
}// 自动配置的JPA Repository - 无需实现
@Repository
public interface UserRepository extends JpaRepository<User, Long> {List<User> findByName(String name);
}
5. Spring Cloud阶段 (2015-至今)
微服务架构示例:
// 微服务注册
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {public static void main(String[] args) {SpringApplication.run(UserServiceApplication.class, args);}
}// 服务间通信
@FeignClient("order-service")
public interface OrderClient {@GetMapping("/api/orders/user/{userId}")List<Order> getOrdersByUser(@PathVariable("userId") Long userId);
}
数据访问技术演进
从直接JDBC、DAO模式、Hibernate、JPA到Spring Data,展示了数据访问层的简化过程。
Web开发范式演进
从Servlet/JSP的直接操作,到Struts、JSF、Spring MVC,再到RESTful API和前后端分离架构。
这些代码示例清晰展示了Java企业生态系统如何逐步演进,从复杂的手动配置到约定优于配置的简化开发模式,从单体应用到分布式微服务架构。每一次演进都致力于提高开发效率、降低维护成本,并使系统更加灵活和可扩展。
// Java企业生态系统演进代码示例/*** 1. 原始Java阶段 (1995-1999)* 特点:直接使用Java SE API,手动处理底层细节*/// 使用原始JDBC连接数据库的例子
import java.sql.*;public class OriginalJavaExample {public static void main(String[] args) {Connection conn = null;Statement stmt = null;ResultSet rs = null;try {// 手动加载JDBC驱动Class.forName("com.mysql.jdbc.Driver");// 手动创建数据库连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");// 创建并执行SQL语句stmt = conn.createStatement();rs = stmt.executeQuery("SELECT * FROM users");// 手动处理结果集while (rs.next()) {System.out.println("User: " + rs.getString("name"));}} catch (Exception e) {e.printStackTrace();} finally {// 手动关闭所有资源try {if (rs != null) rs.close();if (stmt != null) stmt.close();if (conn != null) conn.close();} catch (SQLException e) {e.printStackTrace();}}}
}/*** 2. J2EE阶段 (1999-2004)* 特点:EJB组件模型,复杂的配置和依赖*/// EJB 2.x示例 - 需要定义多个接口和实现类
// Home接口
public interface UserHome extends EJBHome {User create() throws CreateException, RemoteException;User findByPrimaryKey(Long id) throws FinderException, RemoteException;
}// 远程接口
public interface User extends EJBObject {String getName() throws RemoteException;void setName(String name) throws RemoteException;
}// Bean实现类
public class UserBean implements EntityBean {private EntityContext context;private Long id;private String name;// 必须实现EntityBean的所有方法public void setEntityContext(EntityContext context) { this.context = context; }public void unsetEntityContext() { this.context = null; }public void ejbActivate() {}public void ejbPassivate() {}public void ejbLoad() {}public void ejbStore() {}public void ejbRemove() {}public Long ejbCreate() { return null; }public void ejbPostCreate() {}// 业务方法public String getName() { return name; }public void setName(String name) { this.name = name; }
}// 客户端使用代码
try {InitialContext ctx = new InitialContext();UserHome home = (UserHome) ctx.lookup("java:comp/env/ejb/User");User user = home.create();user.setName("John");
} catch (Exception e) {e.printStackTrace();
}/*** 3. 轻量级框架阶段 (2002-2006)* 特点:简化配置,POJO编程模型*/// Spring 1.x 示例 - 依赖注入// POJO类
public class UserService {private UserDao userDao;// setter注入public void setUserDao(UserDao userDao) {this.userDao = userDao;}public User findUser(Long id) {return userDao.findById(id);}
}// XML配置
/*
<beans><bean id="userDao" class="com.example.UserDaoImpl" /><bean id="userService" class="com.example.UserService"><property name="userDao" ref="userDao" /></bean>
</beans>
*/// Hibernate示例
public class User {private Long id;private String name;// getters and setters
}/*
<!-- Hibernate映射文件 user.hbm.xml -->
<hibernate-mapping><class name="com.example.User" table="USERS"><id name="id" column="ID"><generator class="native"/></id><property name="name" column="NAME"/></class>
</hibernate-mapping>
*//*** 4. Spring框架阶段 (2004-2012)* 特点:注解配置,AOP,综合解决方案*/// Spring 2.5+ 注解示例
@Repository
public class UserDaoImpl implements UserDao {@Overridepublic User findById(Long id) {// 实现查询逻辑return new User(id, "User " + id);}
}@Service
public class UserServiceImpl implements UserService {private final UserDao userDao;@Autowiredpublic UserServiceImpl(UserDao userDao) {this.userDao = userDao;}@Override@Transactional(readOnly = true)public User getUser(Long id) {return userDao.findById(id);}
}// Spring MVC控制器
@Controller
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/{id}")public String getUser(@PathVariable Long id, Model model) {model.addAttribute("user", userService.getUser(id));return "userDetails";}
}/*** 5. Spring Boot阶段 (2014-2018)* 特点:自动配置,起步依赖,内嵌服务器*/// 只需几个注解即可创建完整应用
@SpringBootApplication
public class UserManagementApplication {public static void main(String[] args) {SpringApplication.run(UserManagementApplication.class, args);}
}// 自动配置的JPA Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {// 无需实现,Spring Data自动提供实现List<User> findByName(String name);@Query("SELECT u FROM User u WHERE u.email LIKE %:domain")List<User> findByEmailDomain(@Param("domain") String domain);
}// RESTful API控制器
@RestController
@RequestMapping("/api/users")
public class UserApiController {@Autowiredprivate UserRepository userRepository;@GetMappingpublic List<User> getAllUsers() {return userRepository.findAll();}@GetMapping("/{id}")public ResponseEntity<User> getUserById(@PathVariable Long id) {return userRepository.findById(id).map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build());}@PostMappingpublic User createUser(@RequestBody User user) {return userRepository.save(user);}
}// 简化的application.properties
/*
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=user
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
*//*** 6. Spring Cloud阶段 (2015-至今)* 特点:微服务架构,分布式系统支持*/// 服务注册 - Eureka服务端
@SpringBootApplication
@EnableEurekaServer
public class ServiceRegistryApplication {public static void main(String[] args) {SpringApplication.run(ServiceRegistryApplication.class, args);}
}// 微服务 - 用户服务
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {public static void main(String[] args) {SpringApplication.run(UserServiceApplication.class, args);}
}// 服务间通信 - Feign客户端
@FeignClient("order-service")
public interface OrderClient {@GetMapping("/api/orders/user/{userId}")List<Order> getOrdersByUser(@PathVariable("userId") Long userId);
}// 在用户服务中使用订单服务
@Service
public class UserAccountService {@Autowiredprivate UserRepository userRepository;@Autowiredprivate OrderClient orderClient;public UserAccountDetails getUserDetails(Long userId) {User user = userRepository.findById(userId).orElseThrow();List<Order> orders = orderClient.getOrdersByUser(userId);return new UserAccountDetails(user, orders);}
}// API网关配置
/*
spring:cloud:gateway:routes:- id: user-serviceuri: lb://user-servicepredicates:- Path=/users/**- id: order-serviceuri: lb://order-servicepredicates:- Path=/orders/**
*//*** 数据访问技术演进示例*/// 1. JDBC直接访问
public User findUserById(long id) {Connection conn = null;PreparedStatement stmt = null;ResultSet rs = null;try {conn = DriverManager.getConnection(DB_URL, USER, PASS);stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");stmt.setLong(1, id);rs = stmt.executeQuery();if (rs.next()) {User user = new User();user.setId(rs.getLong("id"));user.setName(rs.getString("name"));return user;}return null;} catch (SQLException e) {throw new RuntimeException(e);} finally {// 关闭资源}
}// 2. DAO模式
public interface UserDao {User findById(long id);void save(User user);void update(User user);void delete(User user);
}public class JdbcUserDao implements UserDao {@Overridepublic User findById(long id) {// JDBC实现}// 其他方法实现
}// 3. Hibernate ORM
public class HibernateUserDao implements UserDao {private SessionFactory sessionFactory;@Overridepublic User findById(long id) {Session session = sessionFactory.getCurrentSession();return (User) session.get(User.class, id);}@Overridepublic void save(User user) {Session session = sessionFactory.getCurrentSession();session.save(user);}// 其他方法实现
}// 4. JPA
@Entity
@Table(name = "users")
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(name = "name")private String name;// getters and setters
}public class JpaUserDao implements UserDao {@PersistenceContextprivate EntityManager entityManager;@Overridepublic User findById(long id) {return entityManager.find(User.class, id);}@Overridepublic void save(User user) {entityManager.persist(user);}// 其他方法实现
}// 5. Spring Data
public interface UserRepository extends JpaRepository<User, Long> {// 自动生成实现List<User> findByNameContaining(String namePart);@Query("SELECT u FROM User u WHERE u.active = true")List<User> findActiveUsers();
}// 使用Spring Data
@Service
public class UserService {@Autowiredprivate UserRepository userRepository;public List<User> findActiveUsersWithName(String name) {return userRepository.findByNameContaining(name).stream().filter(User::isActive).collect(Collectors.toList());}
}/*** Web开发演进示例*/// 1. Servlet/JSP
public class UserServlet extends HttpServlet {private UserDao userDao = new JdbcUserDao();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String idStr = req.getParameter("id");long id = Long.parseLong(idStr);User user = userDao.findById(id);req.setAttribute("user", user);RequestDispatcher dispatcher = req.getRequestDispatcher("/user.jsp");dispatcher.forward(req, resp);}
}// JSP页面
/*
<html>
<body><h1>User Details</h1><p>ID: <%= ((User)request.getAttribute("user")).getId() %></p><p>Name: <%= ((User)request.getAttribute("user")).getName() %></p>
</body>
</html>
*/// 2. Struts
public class UserAction extends Action {private UserDao userDao = new JdbcUserDao();@Overridepublic ActionForward execute(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response) throws Exception {UserForm userForm = (UserForm) form;long id = userForm.getId();User user = userDao.findById(id);userForm.setName(user.getName());return mapping.findForward("success");}
}// 3. JSF
@ManagedBean
@RequestScoped
public class UserBean {@EJBprivate UserService userService;private long id;private String name;public String loadUser() {User user = userService.findById(id);this.name = user.getName();return "userDetails";}// getters and setters
}// JSF页面
/*
<h:form><h:inputText value="#{userBean.id}" /><h:commandButton value="Load" action="#{userBean.loadUser}" /><h:outputText value="#{userBean.name}" />
</h:form>
*/// 4. Spring MVC
@Controller
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/{id}")public String getUser(@PathVariable Long id, Model model) {User user = userService.findById(id);model.addAttribute("user", user);return "userDetails";}@PostMappingpublic String createUser(@ModelAttribute User user) {userService.save(user);return "redirect:/users/" + user.getId();}
}// 5. RESTful API
@RestController
@RequestMapping("/api/users")
public class UserRestController {@Autowiredprivate UserService userService;@GetMapping("/{id}")public User getUser(@PathVariable Long id) {return userService.findById(id);}@PostMapping@ResponseStatus(HttpStatus.CREATED)public User createUser(@RequestBody User user) {return userService.save(user);}@PutMapping("/{id}")public User updateUser(@PathVariable Long id, @RequestBody User user) {user.setId(id);return userService.update(user);}@DeleteMapping("/{id}")@ResponseStatus(HttpStatus.NO_CONTENT)public void deleteUser(@PathVariable Long id) {userService.delete(id);}
}// 6. 前后端分离
// 后端: Spring Boot RESTful API (同上)// 前端: React组件
/*
import React, { useState, useEffect } from 'react';
import axios from 'axios';function UserList() {const [users, setUsers] = useState([]);useEffect(() => {axios.get('/api/users').then(response => {setUsers(response.data);}).catch(error => console.error(error));}, []);return (<div><h1>Users</h1><ul>{users.map(user => (<li key={user.id}>{user.name}</li>))}</ul></div>);
}export default UserList;
*/
相关文章:
【Java企业生态系统的演进】从单体J2EE到云原生微服务
Java企业生态系统的演进:从单体J2EE到云原生微服务 目录标题 Java企业生态系统的演进:从单体J2EE到云原生微服务摘要1. 引言2. 整体框架演进:从原始Java到Spring Cloud2.1 原始Java阶段(1995-1999)2.2 J2EE阶段&#x…...
【爬虫基础】第二部分 爬虫基础理论 P1/3
上节内容回顾:【爬虫基础】第一部分 网络通讯 P1/3-CSDN博客 【爬虫基础】第一部分 网络通讯-Socket套接字 P2/3-CSDN博客 【爬虫基础】第一部分 网络通讯-编程 P3/3-CSDN博客 爬虫相关文档,希望互相学习,共同进步 风123456789ÿ…...
第2章_保护您的第一个应用程序
第2章_保护您的第一个应用程序 在本章中,您将学习如何使用 Keycloak 保护您的第一个应用程序。为了让事情更有趣,您将运行的示例应用程序由两部分组成,前端 Web 应用程序和后端 REST API。这将向您展示用户如何向前端进行身份验证࿰…...
山东大学软件学院人工智能导论实验之知识库推理
目录 实验目的: 实验代码: 实验内容: 实验结果 实验目的: 输入相应的条件,根据知识库推理得出相应的知识。 实验代码: def find_data(input_process_data_list):for epoch, data_process in enumerat…...
Java 网络协议面试题答案整理,最新面试题
TCP和UDP的主要区别是什么? TCP(传输控制协议)和UDP(用户数据报协议)的主要区别在于TCP是面向连接的协议,而UDP是无连接的协议。这导致了它们在数据传输方式、可靠性、速度和使用场景方面的不同。 1、连接…...
win10把c盘docker虚拟硬盘映射迁移到别的磁盘
c盘空间本身就比较小、如果安装了docker服务后,安装的时候没选择其他硬盘,虚拟磁盘也在c盘会占用很大的空间,像我的就三十多个G,把它迁移到其他磁盘一下子节约几十G 1、先输入下面命令查看 docker 状态 wsl -l -v 2、如果没有停止…...
AOP进阶-02.通知顺序
一.通知顺序 当有多个切面类中的切入点表达式一样时,这些切面类的执行顺序是怎样的呢?如图我们将定义两个切面类,一个MyAspect2,一个MyAspect3,一个MyAspect4。执行后我们发现, 对于目标方法前的通知方法&…...
${sym} 与 String(sym) 的区别
在 JavaScript 中,${sym}(模板字符串插值)和 String(sym)(显式类型转换)虽然都涉及将值转换为字符串,但它们的底层逻辑和行为存在显著差异,尤其是在处理 Symbol 等特殊类型时。以下是具体对比&a…...
sglang框架源码笔记
文章目录 整体架构1. **客户端(Client)**:2. **服务器端(Server)**:3. **调度器与模型工作节点(Scheduler & Model Worker)**: TpModelWorker类ModelRunner类TpModel…...
2025年SCI一区智能优化算法:混沌进化优化算法(Chaotic Evolution Optimization, CEO),提供MATLAB代码
一、混沌进化优化算法 https://github.com/ITyuanshou/MATLABCode 1. 算法简介 混沌进化优化算法(Chaotic Evolution Optimization, CEO)是2025年提出的一种受混沌动力学启发的新型元启发式算法。该算法的主要灵感来源于二维离散忆阻映射的混沌进化过…...
uake 网络安全 reverse网络安全
🍅 点击文末小卡片 ,免费获取网络安全全套资料,资料在手,涨薪更快 本文首发于“合天网安实验室” 首先从PEID的算法分析插件来介绍,要知道不管是在CTF竞赛的REVERSE题目中,还是在实际的商业产品中…...
C语言实现单链表
单链表是数据结构中最基础的链式结构,它不按照线性的顺序存储数据,而是由若干个同一结构类型的“节点”依次串联而成的,即每一个节点里保存着下一个节点的地址(指针)。 上图中,一个表头变量head是用来存储链表首节点的地址,链表中每个节点有data(数据)部分和n…...
Rk3568驱动开发_点亮led灯代码完善(手动挡)_6
1.实现思路: 应用层打开设备后通过write函数向内核中写值,1代表要打开灯,0代表要关闭灯 Linux配置gpio和控制gpio多了一个虚拟内存映射操作 2.注意事项: 配置和读写操作的时候要谨慎,比如先关掉gpio再注销掉虚拟内存…...
threejs:document.createElement创建标签后css设置失效
vue3threejs,做一个给模型批量CSS2D标签的案例,在导入模型的js文件里,跟着课程写的代码如下: import * as THREE from three; // 引入gltf模型加载库GLTFLoader.js import { GLTFLoader } from three/addons/loaders/GLTFLoader.…...
在 compare-form.vue 中添加 compareDate 隐藏字段,并在提交时自动填入当前时间
在 compare-form.vue 中添加 compareDate 隐藏字段,并在提交时自动填入当前时间。 提交表单时存入的对象是FakeRegistration,这个对象里面有compareDate字段,刚好表格查询的对象也是FakeRegistration,所以表格展示的时间就是刚才…...
使用DeepSeek/ChatGPT等AI工具辅助编写wireshark过滤器
随着deepseek,chatgpt等大模型的能力越来越强大,本文将介绍借助deepseek,chatgpt等大模型工具,通过编写提示词,辅助生成全面的Wireshark显示过滤器的能力。 每一种协议的字段众多,流量分析的需求多种多样,…...
Java 大视界 -- Java 大数据在智能物流路径规划与车辆调度中的创新应用(102)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
YOLOv12 ——基于卷积神经网络的快速推理速度与注意力机制带来的增强性能结合
概述 实时目标检测对于许多实际应用来说已经变得至关重要,而Ultralytics公司开发的YOLO(You Only Look Once,只看一次)系列一直是最先进的模型系列,在速度和准确性之间提供了稳健的平衡。注意力机制的低效阻碍了它们在…...
一个行为类似标准库find算法的模板
函数需要两个模板类型参数,一个表示函数的迭代器参数,另一个表示值的类型。 代码 #include<iostream> #include<string> #include<vector> #include<list>using namespace std;template <typename IterType,typename T>…...
LLC谐振变换器恒压恒流双竞争闭环simulink仿真
1.模型简介 本仿真模型基于MATLAB/Simulink(版本MATLAB 2017Ra)软件。建议采用matlab2017 Ra及以上版本打开。(若需要其他版本可联系代为转换)针对全桥LLC拓扑,利用Matlab软件搭建模型,分别对轻载…...
Elasticsearch 的分布式架构原理:通俗易懂版
Elasticsearch 的分布式架构原理:通俗易懂版 Lucene 和 Elasticsearch 的前世今生 Lucene 是一个功能强大的搜索库,提供了高效的全文检索能力。然而,直接基于 Lucene 开发非常复杂,即使是简单的功能也需要编写大量的 Java 代码&…...
[深度学习]基于C++和onnxruntime部署yolov12的onnx模型
基于C和ONNX Runtime部署YOLOv12的ONNX模型,可以遵循以下步骤: 准备环境:首先,确保已经下载后指定版本opencv和onnruntime的C库。 模型转换: 安装好yolov12环境并将YOLOv12模型转换为ONNX格式。这通常涉及使用深度学习…...
seacmsv9报错注入
1、seacms的介绍 seacms中文名:海洋影视管理系统。是一个采用了php5mysql架构的影视网站框架,因此,如果该框架有漏洞,那使用了该框架的各个网站都会有相同问题。 2、源码的分析 漏洞的部分源码如下: <?php …...
剑指 Offer II 033. 变位词组
comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20033.%20%E5%8F%98%E4%BD%8D%E8%AF%8D%E7%BB%84/README.md 剑指 Offer II 033. 变位词组 题目描述 给定一个字符串数组 strs ,将 变位词 组合在一起…...
【2025全网最新最全】前端Vue3框架的搭建及工程目录详解
文章目录 安装软件Node.js搭建Vue工程创建Vue工程精简Vue项目文件 Vue工程目录的解读网页标题的设置设置全局样式路由配置 安装软件Node.js 下载地址:https://nodejs.org/zh-cn/ 安装完成后,打开cmd,查看环境是否准备好 node -v npm -vnpm使用之前一定…...
前缀和专题练习 ——基于罗勇军老师的《蓝桥杯算法入门C/C++》
目录 一、0求和 - 蓝桥云课 算法代码: 代码思路概述 代码详细解释 数组定义 输入读取 前缀和计算部分 结果计算部分 输出结果 程序结束 总结 二、1.可获得的最小取值 - 蓝桥云课 算法代码: 代码思路概述 详细代码逻辑解释 输入初始化 …...
1.测试策略与计划设计指南
1.介绍 1.1项目介绍 完整项目组成:1.基于K8S定制开发的SaaS平台;2.多个团队提供的中台服务(微服务);3.多个业务团队开发的系统平台。涉及多个项目团队、上百个微服务组件。 测试在所有团队开发测试后,自己搭建测试环境,…...
pikachu
暴力破解 基于表单的暴力破解 【2024版】最新BurpSuit的使用教程(非常详细)零基础入门到精通,看一篇就够了!让你挖洞事半功倍!_burpsuite使用教程-CSDN博客 登录页面,随意输入抓包,发送到攻击…...
HDFS扩缩容及数据迁移
1.黑白名单机制 在HDFS中可以通过黑名单、白名单机制进行节点管理,决定数据可以复制/不可以复制到哪些节点。 黑名单通常是指在HDFS中被标记为不可用或不可访问的节点列表,这些节点可能由于硬件故障、网络问题或其他原因而暂时或永久性地无法使用。当一…...
设计模式-(状态模式,策略模式,代理模式,责任链模式)
状态模式 概念: 用于管理一个对象在不同状态下的行为变化。它允许对象在内部状态改变时改变其行为,从而让对象看起来像是改变了其类。状态模式的核心思想是将状态封装到独立的类中,每个状态类都定义了在该状态下对象的行为 状态模式主要涉…...
二、IDE集成DeepSeek保姆级教学(使用篇)
各位看官老爷好,如果还没有安装DeepSeek请查阅前一篇 一、IDE集成DeepSeek保姆级教学(安装篇) 一、DeepSeek在CodeGPT中使用教学 1.1、Edit Code 编辑代码 选中代码片段 —> 右键 —> CodeGPT —> Edit Code, 输入自然语言可编辑代码,点击S…...
通义灵码插件安装入门教学 - IDEA(安装篇)
在开发过程中,使用合适的工具和插件可以极大地提高我们的工作效率。今天,我们将详细介绍如何在 IntelliJ IDEA 中安装并配置通义灵码插件,这是一款旨在提升开发者效率的实用工具。无论你是新手还是有经验的开发者,本文都将为你提供…...
每天一个Flutter开发小项目 (4) : 构建收藏地点应用 - 深入Flutter状态管理
引言 欢迎回到 每天一个Flutter开发小项目 系列博客!在前三篇博客中,我们从零开始构建了计数器应用、待办事项列表应用,以及简易天气应用。您不仅掌握了 Flutter 的基础组件和布局,还学习了网络请求、JSON 解析等实用技能,更重要的是,我们一起探讨了高效的 Flutter 学习…...
qt-C++笔记之QtCreator新建项目即Create Project所提供模板的逐个尝试
qt-C笔记之QtCreator新建项目即Create Project所提供模板的逐个尝试 code review! 文章目录 qt-C笔记之QtCreator新建项目即Create Project所提供模板的逐个尝试1.Application(Qt):Qt Widgets Application1.1.qmake版本1.2.cmake版本 2.Application(Qt):Qt Console Applicati…...
【NestJS系列】安装官方nestjs CLI 工具
环境搭建指南:从零开始创建 NestJS 项目 一、工具准备 1. 安装 Node.js 环境 推荐使用 LTS 版本(目前 20.x 以上)验证安装:终端执行 node -v 和 npm -vNode.js 官网下载2. 包管理器选择 这里选用更高效的 pnpm,你也可选择 npm 或 yarn # 安装 pnpm npm install -g pnp…...
【Springboot知识】Logback从1.2.x升级到1.3.x需要注意哪些点?
文章目录 **1. 确认依赖版本**示例依赖配置(Maven): **2. 处理 StaticLoggerBinder 的移除**解决方案: **3. 修改日志配置文件**示例 logback.xml 配置: **4. 检查兼容性问题**Spring Boot 2.x 的兼容性解决方案&#…...
【Linux C | 时间】localtime 的介绍、死机、死锁问题以及 localtime_r 函数的时区问题
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
每日一题——LRU缓存机制的C语言实现详解
LRU缓存机制的C语言实现详解 参考1. 数据结构设计双向链表节点哈希表节点哈希表LRU缓存结构 2. 初始化哈希表和双向链表哈希函数初始化哈希表初始化双向链表创建LRU缓存 3. 更新双向链表4. 实现Get操作5. 实现Put操作更新节点值删除最久未使用节点插入或更新节点 6. 释放缓存释…...
虚函数表和虚函数表指针
1.虚函数表什么时候生成? 编译器编译的时候生成 2.虚函数表存放在哪里? 讨论两种情况:在磁盘(可执行程序)、在内存(运行状态) 3.虚函数表与虚函数表指针的关系 每个类只有一个虚函数&#x…...
计算机毕业设计SpringBoot+Vue.js图书进销存管理系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
3-2 WPS JS宏 工作簿的打开与保存(模板批量另存为工作)学习笔记
************************************************************************************************************** 点击进入 -我要自学网-国内领先的专业视频教程学习网站 *******************************************************************************************…...
大白话Vuex 核心概念(state、mutations、actions)的使用案例与原理
大白话Vuex 核心概念(state、mutations、actions)的使用案例与原理 Vuex是Vue.js应用程序中专门用来管理状态的工具,就好像是一个大管家,帮你把项目里一些重要的数据和操作管理得井井有条。下面用大白话结合案例来介绍Vuex核心概…...
【学写LibreCAD】1 LibreCAD主程序
一、源码 头文件: #ifndef MAIN_H #define MAIN_H#include<QStringList>#define STR(x) #x #define XSTR(x) STR(x)/*** brief handleArgs* param argc cli argument counter from main()* param argv cli arguments from main()* param argClean a list…...
CentOS7最小化安装中使用curl安装yum和wget
在 CentOS 7 最小化安装中,如果已经有curl工具,可以按照以下步骤使用它来安装yum和wget: 1. 备份原有的 yum 源配置文件 为了避免配置冲突或后续需要恢复,先备份原有的yum源配置文件。 mv /etc/yum.repos.d/CentOS-Base.repo /…...
【Linux】learning notes(3)make、copy、move、remove
文章目录 1、mkdir (make directory)2、rmdir (remove directory)3、rm(remove)4、>5、touch 新建文件6、mv(move)7、cp(copy) 1、mkdir (make…...
P10108 [GESP202312 六级] 闯关游戏
题目大意 如题 分析 设最佳通关方案为 { s 1 , s 2 , . . . , s k } \{s_1,s_2,...,s_k\} {s1,s2,...,sk},其中 s i s_i si 代表第 i i i 次到达的关卡( ≥ N \ge N ≥N 的不算)。 当 a k N − 1 a_kN-1 akN−1 时&#…...
Dubbo RPC 原理
一、Dubbo 简介 Apache Dubbo 是一款高性能、轻量级的开源 RPC 框架,支持服务治理、协议扩展、负载均衡、容错机制等核心功能,广泛应用于微服务架构。其核心目标是解决分布式服务之间的高效通信与服务治理问题。 二、Dubbo 架构设计 1. 核心组件 Prov…...
网络安全 机器学习算法 计算机网络安全机制
(一)网络操作系统 安全 网络操作系统安全是整个网络系统安全的基础。操作系统安全机制主要包括访问控制和隔离控制。 访问控制系统一般包括主体、客体和安全访问政策 访问控制类型: 自主访问控制强制访问控制 访问控制措施: 入…...
【Jenkins】一种灵活定义多个执行label节点的jenkinsfile写法
确定执行机器和自定义工作目录(忽略节点的workspace) pipeline{agent {node {label "XXXXX"customWorkspace "E:/workspace/"}}parameters {}options {}stages {}post {} }仅确定执行机器 pipeline{agent { label "XXXXX&quo…...
Web自动化之Selenium控制已经打开的浏览器(Chrome,Edge)
在使用selenium进行web自动化或爬虫的时候,经常会面临登录的情况,对于这种情况,我们可以利用Selenium控制已经打开的浏览器,从而避免每次都需要重新打开浏览器并进行登录的繁琐步骤。 目录 说明 启动浏览器 注意 --user-data-dir说明 代码设定 代码 改进代…...