8年java开发告诉你为什么选择Spring Boot?

Spring是一个非常流行的基于Java的框架,用于构建Web和企业应用程序。与许多其他仅关注一个领域的框架不同,Spring框架提供了广泛的功能,通过其项目组合项目满足现代业务需求。

Spring框架提供了以多种方式配置bean的灵活性,例如XML,Annotations和JavaConfig。随着功能数量的增加,复杂性也会增加,配置Spring应用程序变得繁琐且容易出错。

Spring团队创建了Spring Boot来解决配置的复杂性。

但在深入了解SpringBoot之前,我们将快速浏览一下Spring框架,看看SpringBoot试图解决的问题是什么。

在本文中,我们将介绍:

  • Spring框架概述

  • 使用Spring MVC和JPA(Hibernate)的Web应用程序

  • 快速品尝Spring Boot

 

Spring框架概述

如果您是Java开发人员,那么您很可能已经听说过Spring框架,并且可能已经在您的项目中使用过它。Spring框架主要是作为依赖注入容器创建的,但它远不止于此。

Spring很受欢迎有几个原因:

  • Spring的依赖注入方法鼓励编写可测试的代码

  • 易于使用但功能强大的数据库事务管理功能

  • Spring简化了与其他Java框架的集成,如JPA / Hibernate ORM,Struts / JSF /等。网络框架

  • 用于构建Web应用程序的最先进的Web MVC框架

除了Spring框架之外,还有许多其他Spring姐妹项目可帮助构建满足现代业务需求的应用程序:

  • Spring Data:简化关系和NoSQL数据存储的数据访问。

  • Spring Batch:提供强大的批处理框架。

  • Spring Security:用于保护应用程序的强大安全框架。

  • Spring Social:支持与Facebook,Twitter,LinkedIn,GitHub等社交网站集成。

  • Spring Integration:企业集成模式的一种实现,用于使用轻量级消息传递和声明性适配器促进与其他企业应用程序的集成。

还有许多其他有趣的项目可满足各种其他现代应用程序开发需求 有关更多信息,请查看http://spring.io/projects

在最初几天,Spring框架提供了一种基于XML的方法来配置bean。后来,Spring引入了基于XML的DSL,Annotations和基于JavaConfig的方法来配置bean。

让我们快速看看每种配置样式的外观。

 

基于XML的配置

 
<bean id="userService" class="com.sivalabs.myapp.service.UserService"> <property name="userDao" ref="userDao"/> </bean> <bean id="userDao" class="com.sivalabs.myapp.dao.JdbcUserDao"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="secret"/> </bean>
 

 

基于注释的配置

 
 
@Service public class UserService { private UserDao userDao; @Autowired public UserService(UserDao dao){ this.userDao = dao; } ... ... }
 
@Repository public class JdbcUserDao { private DataSource dataSource; @Autowired public JdbcUserDao(DataSource dataSource){ this.dataSource = dataSource; } ... ... }

 

基于JavaConfig的配置

 
 
@Configuration public class AppConfig { @Bean public UserService userService(UserDao dao){ return new UserService(dao); } @Bean public UserDao userDao(DataSource dataSource){ return new JdbcUserDao(dataSource); } @Bean public DataSource dataSource(){ BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/test"); dataSource.setUsername("root"); dataSource.setPassword("secret"); return dataSource; } }

哇... Spring提供了很多方法来做同样的事情,我们甚至可以混合使用这些方法,并在同一个应用程序中使用基于JavaConfig和Annotation的配置样式。

这是一个很大的灵活性,它既好又坏。对Spring框架不熟悉的人可能会对使用哪种方法感到困惑。截至目前,Spring团队建议采用基于JavaConfig的方法,因为它提供了更大的灵活性。

但是没有一种适合所有类型的解决方案。必须根据自己的应用需求选择方法。

好了,现在您已经了解了各种样式的Spring bean配置的外观。

让我们快速了解一下典型的SpringMVC + JPA / Hibernate Web应用程序配置的配置。

 

使用Spring MVC和JPA(Hibernate)的Web应用程序

在了解Spring Boot是什么以及它提供了哪些功能之前,让我们先看看一下典型的Spring Web应用程序配置,痛点以及Spring Boot如何解决这些问题。

 

第1步:配置Maven依赖项

我们需要做的第一件事是配置pom.xml中所需的所有依赖项。

 
 
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.sivalabs</groupId> <artifactId>springmvc-jpa-demo</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>springmvc-jpa-demo</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.9.2.RELEASE</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.13</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.13</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.13</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.4.190</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.3.11.Final</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring4</artifactId> <version>2.1.4.RELEASE</version> </dependency> </dependencies> </project>

我们已经配置了所有Maven jar依赖项,包括Spring MVC,Spring Data JPA,JPA / Hibernate,Thymeleaf和Log4j。

 

步骤2:使用JavaConfig配置服务/ DAO层Bean

 
 
@Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages="com.sivalabs.demo") @PropertySource(value = { "classpath:application.properties" }) public class AppConfig { @Autowired private Environment env; @Bean public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } @Value("${init-db:false}") private String initDatabase; @Bean public PlatformTransactionManager transactionManager() { EntityManagerFactory factory = entityManagerFactory().getObject(); return new JpaTransactionManager(factory); } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setGenerateDdl(Boolean.TRUE); vendorAdapter.setShowSql(Boolean.TRUE); factory.setDataSource(dataSource()); factory.setJpaVendorAdapter(vendorAdapter); factory.setPackagesToScan("com.sivalabs.demo"); Properties jpaProperties = new Properties(); jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); factory.setJpaProperties(jpaProperties); factory.afterPropertiesSet(); factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); return factory; } @Bean public HibernateExceptionTranslator hibernateExceptionTranslator() { return new HibernateExceptionTranslator(); } @Bean public DataSource dataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName")); dataSource.setUrl(env.getProperty("jdbc.url")); dataSource.setUsername(env.getProperty("jdbc.username")); dataSource.setPassword(env.getProperty("jdbc.password")); return dataSource; } @Bean public DataSourceInitializer dataSourceInitializer(DataSource dataSource) { DataSourceInitializer dataSourceInitializer = new DataSourceInitializer(); dataSourceInitializer.setDataSource(dataSource); ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(); databasePopulator.addScript(new ClassPathResource("data.sql")); dataSourceInitializer.setDatabasePopulator(databasePopulator); dataSourceInitializer.setEnabled(Boolean.parseBoolean(initDatabase)); return dataSourceInitializer; } }

在我们的AppConfig.java配置类中,我们完成了以下操作:

  • 使用@Configuration批注将其标记为Spring Configuration类。

  • 使用@EnableTransactionManagement启用基于注释的事务管理

  • 配置@EnableJpaRepositories以指示在哪里查找Spring Data JPA存储库

  • 使用@PropertySource批注和PropertySourcesPlaceholderConfigurer bean定义配置PropertyPlaceHolder bean ,该定义从application.properties文件加载属性。

  • 为DataSource,JPA EntityManagerFactory,JpaTransactionManager定义的bean 。

  • 配置DataSourceInitializer bean以通过在应用程序启动时执行data.sql脚本来初始化数据库。

我们需要在application.properties中配置属性占位符值,如下所示:

 
 
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=admin init-db=true hibernate.dialect=org.hibernate.dialect.MySQLDialect hibernate.show_sql=true hibernate.hbm2ddl.auto=update

我们可以创建一个简单的SQL脚本data.sql来将样本数据填充到USER表中:

 
 
log4j.rootCategory=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p %t %c{2}:%L - %m%n log4j.category.org.springframework=INFO log4j.category.com.sivalabs=DEBUG

我们可以使用基本配置创建log4j.properties文件,如下所示:

log4j.rootCategory = INFO,stdout log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern =%5p%t%c {2}:%L - %m%n log4j.category.org.springframework = INFO log4j.category.com.sivalabs = DEBUG

 

第3步:配置Spring MVC Web Layer Beans

我们将不得不配置Thymeleaf ViewResolver,静态ResourceHandlers,i18n等的MessageSource等。

 
 
@Configuration @ComponentScan(basePackages = { "com.sivalabs.demo"}) @EnableWebMvc public class WebMvcConfig extends WebMvcConfigurerAdapter { @Bean public TemplateResolver templateResolver() { TemplateResolver templateResolver = new ServletContextTemplateResolver(); templateResolver.setPrefix("/WEB-INF/views/"); templateResolver.setSuffix(".html"); templateResolver.setTemplateMode("HTML5"); templateResolver.setCacheable(false); return templateResolver; } @Bean public SpringTemplateEngine templateEngine() { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver()); return templateEngine; } @Bean public ThymeleafViewResolver viewResolver() { ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver(); thymeleafViewResolver.setTemplateEngine(templateEngine()); thymeleafViewResolver.setCharacterEncoding("UTF-8"); return thymeleafViewResolver; } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**").addResourceLocations("/resources/"); } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } @Bean(name = "messageSource") public MessageSource configureMessageSource() { ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); messageSource.setBasename("classpath:messages"); messageSource.setCacheSeconds(5); messageSource.setDefaultEncoding("UTF-8"); return messageSource; } }

在我们的WebMvcConfig.java配置类中,我们完成了以下操作:

  • 使用@Configuration批注将其标记为Spring Configuration类。

  • 使用@EnableWebMvc启用基于注释的Spring MVC配置

  • 通过注册TemplateResolver,SpringTemplateEngine,ThymeleafViewResolver bean 配置Thymeleaf ViewResolver 。

  • 注册的ResourceHandlers bean用于指示对URI / resources / **的静态资源的请求,将从location / resources /目录提供。

  • 配置的MessageSource bean 从classpath 加载来自ResourceBundle messages- {country-code} .properties的 i18n消息。

目前我们没有要配置的消息,因此在src / main / resources文件夹中创建一个空的messages.properties文件。

 

第4步:注册Spring MVC FrontController Servlet DispatcherServlet

在Servlet 3.x规范之前,我们必须在web.xml中注册Servlets / Filters 。从Servlet 3.x规范开始,我们可以使用ServletContainerInitializer以编程方式注册Servlets / Filters 。

Spring MVC提供了一个方便的类AbstractAnnotationConfigDispatcherServletInitializer来注册DispatcherServlet。

 
 
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { AppConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { WebMvcConfig.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected Filter[] getServletFilters() { return new Filter[]{ new OpenEntityManagerInViewFilter() }; } }

在我们的SpringWebAppInitializer.java配置类中,我们完成了以下操作:

  • 我们已将AppConfig.class配置为RootConfirationClasses,它将成为包含所有子(DispatcherServlet)上下文共享的bean定义的父ApplicationContext。

  • 我们已将WebMvcConfig.class配置为ServletConfigClasses,它是包含WebMvc bean定义的子ApplicationContext。

  • 我们已将“/”配置为ServletMapping意味着所有请求都将由DispatcherServlet处理。

  • 我们已将OpenEntityManagerInViewFilter注册为Servlet过滤器,以便我们可以在呈现视图时延迟加载JPA Entity惰性集合。

 

步骤5:创建JPA实体和Spring Data JPA存储库

为User实体创建JPA实体User.java和Spring Data JPA存储库。

 
 
@Entity public class User { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Integer id; private String name; //setters and getters } public interface UserRepository extends JpaRepository<User, Integer> { }

 

第6步:创建SpringMVC控制器

创建一个SpringMVC控制器来处理URL “/”并呈现用户列表。

@Controller public class HomeController { @Autowired UserRepository userRepo; @RequestMapping("/") public String home(Model model) { model.addAttribute("users", userRepo.findAll()); return "index"; } }

 

第7步:创建Thymeleaf视图/WEB-INF/views/index.html以呈现用户列表

 
 
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"/> <title>Home</title> </head> <body> <table> <thead> <tr> <th>Id</th> <th>Name</th> </tr> </thead> <tbody> <tr th:each="user : ${users}"> <td th:text="${user.id}">Id</td> <td th:text="${user.name}">Name</td> </tr> </tbody> </table> </body> </html>

我们现在都设置为运行该应用程序。但在此之前,我们需要在IDE中下载和配置服务器,如Tomcat或Jetty或Wildfly等。

您可以下载Tomcat 8并在您喜欢的IDE中进行配置,运行应用程序并将浏览器指向http:// localhost:8080 / springmvcjpa-demo。您应该在表格中看到用户详细信息列表。

是的......我们做到了。

但是等等......仅仅显示从数据库表中提取的用户详细信息列表并不是太多工作?

让我们诚实公平。所有这些配置不仅适用于这一个用例。此配置也是应用程序其余部分的基础。

但是,如果你想快速启动并运行,这还有很多工作要做。

它的另一个问题是,假设您想要开发另一个具有类似技术堆栈的SpringMVC应用程序?

好吧,你复制粘贴配置并调整它。对?但要记住一件事:如果你必须一次又一次地做同样的事情,你应该找到一种自动化的方法。

除了一次又一次地编写相同的配置外,你还看到其他任何问题吗?

好吧,让我列出我在这里遇到的问题。

  • 您需要寻找特定Spring版本的所有兼容库并进行配置。

  • 95%的时候我们以相同的方式配置DataSource,EntitymanagerFactory,TransactionManager等bean。如果Spring可以自动为我做这件事,那不是很好吗。

  • 类似地,我们大多数时候以相同的方式配置SpringRVC bean,如ViewResolver,MessageSource等。

如果Spring可以自动为我做这将是非常棒的!!!

想象一下,如果Spring能够自动配置bean怎么办?如果您可以使用简单的可自定义属性自定义自动配置怎么办?

例如,不要将DispatcherServlet url-pattern映射到“/”,而是将其映射到“/ app /”。您可能希望将它们放在“/ WEB-INF / templates /”文件夹中,而不是将Thymeleaf视图放在“/ WEB-INF / views”文件夹中。

所以基本上你希望Spring自动执行操作但是提供了以更简单的方式覆盖默认配置的灵活性?

那么,你即将进入SpringBoot的世界,在那里你的梦想成真!

 

快速品尝春季靴子

欢迎来到Spring Boot!Spring Boot可以满足您的需求。它将自动为您执行操作,但允许您根据需要覆盖默认值。

而不是在理论上解释我宁愿通过例子来解释。

因此,让我们实现我们之前构建的相同应用程序,但这次使用SpringBoot。

 

第1步:创建基于Maven的Spring Boot项目

创建一个Maven项目并配置依赖项,如下所示:

 
 
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.sivalabs</groupId> <artifactId>hello-springboot</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>hello-springboot</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.2.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies> </project>

哇我们的pom.xml突然变得那么小!

 

步骤2:在application.properties中配置Datasource / JPA Properties,如下所示

 
 
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=admin spring.datasource.initialize=true spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true

您可以将相同的data.sql文件复制到src / main / resources文件夹中。

 

步骤3:为实体创建JPA实体和Spring Data JPA存储库接口

与springmvc-jpa-demo应用程序相同,创建User.java,UserRepository.java和HomeController.java。

 

第4步:创建Thymeleaf视图以显示用户列表

将我们在springmvc-jpa-demo应用程序中创建的/WEB-INF/views/index.html复制到我们新项目的src /-main / resources / templates文件夹中。

 

第5步:创建SpringBoot EntryPoint类

使用main方法创建Java类Application.java,如下所示:

 
 
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

现在将Application.java作为Java应用程序运行,并将浏览器指向http:// localhost:8080 /。

您应该以表格格式查看用户列表。COOOL!

好吧,我听说你在喊“发生什么事了”。

让我解释刚刚发生的事情。

1.轻松依赖管理

  • 首先要注意的是我们正在使用一些名为spring-boot-starter- *的依赖项。记得我说“95%的时候我使用相同的配置。因此,当您默认添加springboot-starter-web依赖时,它将在开发Spring -webmvc,jackson-json,validation-api和tomcat等Spring MVC应用程序时提取所有常用库。

  • 我们添加了spring-boot-starter-data-jpa依赖项。这将拉动所有spring-data-jpa依赖项并添加Hibernate库,因为大多数应用程序使用Hibernate作为JPA实现。

2.自动配置

  • 不仅spring-boot-starter-web添加了所有这些库,而且还配置了常用的注册bean,如DispatcherServlet,ResourceHandlers,MessageSource等bean,具有合理的默认值。

  • 我们还添加了spring-boot-starter-Thymeleaf,它不仅添加了Thymeleaf库依赖项,还自动配置了ThymeleafViewResolver bean。

  • 我们没有定义任何DataSource,EntityManagerFactory,TransactionManager等bean,但它们是自动创建的。怎么样?如果我们的类路径中有任何内存数据库驱动程序,如H2或HSQL,那么SpringBoot将自动创建一个内存中的DataSource,然后自动注册EntityManagerFactory,TransactionManager bean以及合理的默认值。但我们正在使用MySQL,因此我们需要明确提供MySQL连接细节。我们在application.properties文件中配置了这些MySQL连接细节,SpringBoot 使用这些属性创建了一个DataSource。

3.嵌入式Servlet容器支持

最重要和最令人惊讶的是我们创建了一个简单的Java类,注释了一些神奇的注释@SpringApplication,它有一个main方法,通过运行该main,我们可以运行应用程序并在http:// localhost:8080 /上访问它。

servlet容器来自哪里? 我们添加了spring-boot-starter-web,它自动提取spring-boot-starter-tomcat,当我们运行main()方法时,它启动了tomcat作为嵌入式容器,这样我们就不必在任何部署我们的应用程序了。外部安装的tomcat服务器。

顺便提一下,你看到我们在pom.xml中的包装类型是'jar'而不是'war'。精彩!

好的,但如果我想使用Jetty服务器而不是tomcat呢? 很简单,从spring-boot-starter-web中排除spring-bootstarter-tomcat,并包含spring-boot-starter-jetty。

而已。

但是,这看起来很神奇!

我可以想象你在想什么。你觉得SpringBoot看起来很酷,它会自动为我做很多事情。但我仍然没有完全理解它是如何真正在幕后工作的。对?

我能够了解。观看魔术表演通常很有趣,但在软件开发中却没有。别担心,我们将会查看这些内容,并详细解释未来文章中幕后发生的事情。但是我不想在本文中将所有内容都转发给你,从而压倒你。

另外本人从事在线教育多年,将自己的资料整合建了一个公众号,对于有兴趣一起交流学习java的初学者可以微信搜索:程序员文明,里面有大神会给予解答,也会有许多的资源可以供大家学习分享,欢迎大家前来一起学习进步!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值