当前位置: 首页 > news >正文

Java框架Spring(一)

一、Spring 是什么

Spring 是一个轻量级的,IOC和AOP的一站式Java 开发框架,是为了简化企业级应用开发而生的。

名词解释:

        轻量级:框架体积小(核心模块)

        IOC:Inversion of Control,直译过来是控制反转,把创建对象的控制权,反转给spring框架。以前,在程序中需要对象都是自己new。例如new StudentDao对象。

        AOP:Aspect Oriented Programming, 直译过来就是面向切面编程。AOP 是一种编 程思想,是面向对象编程(OOP)的一种补充。

        将程序中一些公共的非业务代码分离提取出来开,然后在业务代码执行时,给他们横切进来。底层使用的是动态代理的机制实现。在我们的业务代码不显示调用,但是执行业务代码,会通过代理对象调用非业务代码

        一站式:除了核心的IOC和AOP功能之外,还对数据访问层,web层都有封装,所以是一站式的

二、spring的HelloWorld 

1、使用的model类

package com.wbc.SpringPro.model;public class Admin {private String account;private String password;public Admin(String account, String password) {this.account = account;this.password = password;}public Admin() {}public String getAccount() {return account;}public void setAccount(String account) {this.account = account;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}

 2、spring 核心功能jar包

<!-- spring-context--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.2.RELEASE</version></dependency>

3、spring的配置文件

在src/main/resources创建spring.xml文件作为配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--在spring配置文件中 注册spring管理的类 --><bean id="admin" class="com.wbc.SpringPro.model.Admin"></bean>
</beans>

4、Spring的helloWorld

package com.wbc.SpringPro.test;import com.wbc.SpringPro.model.Admin;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test1 {public static void main(String[] args) {/*ClassPathXmlApplicationContext是spring框架中的一个具体的实现类,负责生成管理程序中的对象可以看作是一个容器,所以一般把spring框架称为spring容器或是IOC容器new ClassPathXmlApplicationContext("spring.xml");用于生成spring容器getBean("配置文件的id",.class文件) 从spring框架(spring容器)中获取需要的对象控制反转---一种编程思想把生成对象的控制权,反转给spring框架,矿建负责对整个对象的整个生命周期对外提供获取对象的方法,我们在程序中哪里需要就在哪里获取即可*/ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring.xml");Admin admin = applicationContext.getBean("admin", Admin.class);Admin admin1 = (Admin) applicationContext.getBean("admin");System.out.println(admin);System.out.println(admin1);}
}

 5、相关说明、

ClassPathXmlApplicationContext是spring框架中的一个具体的实现类,负责生成管理程序中的对象
可以看作是一个容器,所以一般把spring框架称为spring容器或是IOC容器new ClassPathXmlApplicationContext("spring.xml");用于生成spring容器getBean("配置文件的id",.class文件) 从spring框架(spring容器)中获取需要的对象
也可以不传入。class文件,但在接收时需要强转
控制反转---一种编程思想把生成对象的控制权,反转给spring框架,矿建负责对整个对象的整个生命周期对外提供获取对象的方法,我们在程序中哪里需要就在哪里获取即可

三、spring的Bean管理

        bean对象:由于把对象统一交给spring管理后,spring会对对象进行功能的增强,所以在spring框架中生成的对象,统一称为bean对象,用去区分是自己new的还是框架生成的。

        spring的bean管理有两种方式

1、基于xml配置方式

<bean id="admin" class="com.wbc.SpringPro.model.Admin" scope="prototype"></bean>
使用bean标签配置需要让Spring管理的类
id="对象名称" 可以在getBean中获得到spring生成的对象
class="需要让spring管理的地址"
scope="配置bean对象的作用域"scope="singleton" 单例的  在spring启动时就会创建对象,且始终只创建一个对象scope="prototype" 原型的(多例的) 在每次获得对象时,都创建一个新的对象

IOC指的是让spring框架创建对象,创建对象的同时,还有一个动作称为依赖注入

依赖注入:在创建对象的时候,为对象赋值

依赖注入有两种方式 1、通过属性注入(set方法) 2、通过构造方法注入 

(1)通过属性注入

<bean id="admin" class="com.wbc.SpringPro.model.Admin" scope="prototype"><!--调用的是类中的set方法--><property name="account" value="admin"></property><property name="password" value="111"></property>
</bean>

 需要注意的是,框架使用set get方法,需要我们在类中的成员变量和成员方法名称命名规范

(2)通过构造方法注入

<bean id="admin" class="com.wbc.SpringPro.model.Admin" scope="prototype"><!--调用构造方法的依赖注入--><constructor-arg name="account" value="admin"></constructor-arg><constructor-arg name="password" value="111"></constructor-arg>
</bean> 

(3)例:在test中通过service调用dao的方法

将AdminDao当作属性添加在AdminService中,并提供set和get方法

package com.wbc.SpringPro.service;import com.wbc.SpringPro.dao.AdminDao;
import com.wbc.SpringPro.model.Admin;public class AdminService {AdminDao adminDao ;public void saveAdmin() {adminDao.saveAdmin();}public AdminDao getAdminDao() {return adminDao;}public void setAdminDao(AdminDao adminDao) {this.adminDao = adminDao;}
}

 AdminDao的定义

package com.wbc.SpringPro.dao;import com.wbc.SpringPro.model.Admin;public class AdminDao {public  void saveAdmin() {System.out.println("保存admin");}
}

通过bean标签配置在spring中

  • name属性指定要注入的属性名称。
  • ref属性指定要注入的bean的ID(在Spring上下文中已经定义的其他bean)。即,ref="adminDao"表示将名为adminDao的bean注入到当前bean的adminDao属性中。
<bean id="adminDao" class="com.wbc.SpringPro.dao.AdminDao"></bean><bean id="adminService" class="com.wbc.SpringPro.service.AdminService"><!--name是adminService的属性名 ref表示要注入的上下文中存在的bean的id--><property name="adminDao" ref="adminDao"></property>
</bean>

 通过adminService调用

package com.wbc.SpringPro.test;import com.wbc.SpringPro.service.AdminService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test2 {public static void main(String[] args) {ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring.xml");AdminService adminService = (AdminService) applicationContext.getBean("adminService", AdminService.class);adminService.saveAdmin();}
}

2、使用注解进行配置

(1)开启注册扫描

<context:component-scan base-package="包名"> </context:component-scan>

 (2)通过注解配置

@Component(value = "admin")
@Scope(value = "prototype")
/*等同于在配置文件中添加<bean id="admin" class="com.wbc.SpringPro.model.Admin" scope="prototype"></bean>*/

@Componen 通用类

@Service       service层

@Repository  dao层

以上注解都可以实现创建对象功能,只是为了后续扩展功能,在不同的层使用不 同的注解标记

@Scope(value=“prototype”) 原型

@Scope(value=“ singleton ”) 单例  

package com.wbc.SpringPro.service;import com.wbc.SpringPro.dao.AdminDao;
import com.wbc.SpringPro.model.Admin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;@Service(value = "adminService")public class AdminService {@Autowired//自动注入AdminDao adminDao ;public void saveAdmin() {adminDao.saveAdmin();}public AdminDao getAdminDao() {return adminDao;}public void setAdminDao(AdminDao adminDao) {this.adminDao = adminDao;}
}
package com.wbc.SpringPro.dao;import com.wbc.SpringPro.model.Admin;
import org.springframework.stereotype.Repository;@Repository(value = "adminDao")
public class AdminDao {public  void saveAdmin() {System.out.println("保存admin");}
}
package com.wbc.SpringPro.test;import com.wbc.SpringPro.service.AdminService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test2 {public static void main(String[] args) {ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring.xml");AdminService adminService = (AdminService) applicationContext.getBean("adminService", AdminService.class);adminService.saveAdmin();}
}

(3)自动注入

在属性上方通过注释的方式自动依赖注入

        自动注入有两种值的匹配方式:1、通过属性的类型进行查找@Autowired(String提供):用于在属性和属性的set方法上,如果写在属性上,set方法可以不需要Autowired注解默认情况下要注入的值不能为空(required=true)
                @Resource(jdk提供):注入的值也不能为空,既可以通过属性的类型查找,又可以通过对象名查找2、通过对象的名字进行查找@Qualifier(value = "对象的名字")String提供@Resource(name = "adminDao")jdk提供

3、注解配置于xml配置的优缺点

注解优点: 方便,直观,高效(代码少,没有配置文件的书写那么复杂)。

注解缺点:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的。

xml 优点:配置和代码是分离的,在 xml 中做修改,无需编译代码,只需重启服务器即可将新的                       配置加载。

xml缺点:编写麻烦,效率低,大型项目过于复杂。 

三、Spring 数据访问层管理

1、Spring管理JDBC

(1)添加依赖项

<!-- spring-jdbc-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.2.RELEASE</version>
</dependency><!--mysql-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version>
</dependency><!--阿里数据源 数据库链接管理组件-->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version>
</dependency>

(2) 在spring配置文件中,通过bean标签添加对象的配置,使spring来管理对象

<!--阿里巴巴数据库链接管理对象,负责生成数据库链接对象,以及提供了数据库链接池功能让spring管理数据库链接对象 相比myBatis的数据连接池,druid的功能更加灵活
-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://127.0.0.1:3306/ssmd?serverTimezone=Asia/Shanghai"></property><property name="username" value="root"></property><property name="password" value="Wbc11280"></property><property name="initialSize" value="10"></property><!--初始化连接数量--><property name="maxActive" value="20"></property><!--最大连接数量-->
</bean><!--配置spring中对jdbc进行封装的操作类 jdbcTemplate在jdbcTemplace中注入druiDataSourse属性
-->
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate"><property name="dataSource" ref="druidDataSource"></property>
</bean>

(3)在dao层方法内执行sql

package com.wbc.SpringPro.dao;import com.wbc.SpringPro.model.Admin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;@Repository(value = "adminDao")
public class AdminDao {@AutowiredJdbcTemplate jdbcTemplate;public  void saveAdmin() {/*System.out.println("保存admin");*/jdbcTemplate.execute("create table ..."); //主要执行创建表的ddl语句,没有返回值 jdbcTemplate.update("insert into admin(account,password,gender) values(?,?,?)","张三","111","男");List<Admin> adminList=jdbcTemplate.query("select * from admin", new RowMapper<Admin>(){@Overridepublic Admin mapRow(ResultSet resultSet, int i) throws SQLException {Admin admin=new Admin();admin.setAccount(resultSet.getString("account"));admin.setPassword(resultSet.getString("password"));return admin;}});System.out.println(adminList);}
}

执行成功

2、spring整合Mybaits

(1)为什么myBatis要整合阿里巴巴Druid连接池 

  1. 性能优化:Druid是一个高性能的JDBC连接池,能够提供良好的性能表现,通过连接池技术可以有效地重用数据库连接,从而减少连接的创建和销毁开销。

  2. 监控和统计:Druid提供了丰富的监控和统计功能,能够实时监控数据库连接的使用情况、SQL执行情况等,有助于开发者快速发现并解决性能瓶颈和问题。

  3. 灵活配置:Druid支持多种配置选项,可以根据应用的需求进行灵活配置,如设置最小和最大连接数、连接超时时间等,以适应不同的使用场景。

  4. 安全性:Druid提供了SQL监控和防止SQL注入等安全特性,可以更好地保护数据库的安全。

  5. 易于集成:MyBatis已经提供了与Druid的良好集成支持,开发者可以方便地配置和使用Druid作为数据源,无需过多的修改。

(2)spring整合myBatis和Druid 

Spring集成Mybatis其核心是将SqlSessionFactory交由Spring管理,并由 Spring管理对dao接口的代理实现。

我们从新创建一个JavaEE项目

jdk选择java8并添加web依赖

 

1)导入jar包
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.wbc.ssm</groupId><artifactId>ssm</artifactId><version>1.0-SNAPSHOT</version><name>ssm</name><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.target>1.8</maven.compiler.target><maven.compiler.source>1.8</maven.compiler.source><junit.version>5.9.2</junit.version></properties><dependencies><dependency><groupId>javax</groupId><artifactId>javaee-web-api</artifactId><version>8.0.1</version><scope>provided</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>${junit.version}</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>${junit.version}</version><scope>test</scope></dependency><!-- spring-context--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.2.RELEASE</version></dependency><!-- spring-jdbc--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.2.RELEASE</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><!--阿里数据源 数据库链接管理组件--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!--mybatis-spring--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.1</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.2</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>provided</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>3.3.2</version></plugin></plugins></build>
</project>

 (2)搭建myBatis全局配置文件

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--myBatis全局配置文件--><!--    配置日志--><settings><!--        开启工作日志--><setting name="logImpl" value="STDOUT_LOGGING"/><!--        将数据库中的下划线连接名称在java中自动转为驼峰体--><setting name="mapUnderscoreToCamelCase" value="true"/><!--在SqlMapperConfig.xml 中启用二级缓存--><setting name="cacheEnabled" value="true"/></settings><!--    为类配置别名--><typeAliases><!--        为java中的类起别名--><package name="com.wbc.ssm.model"/></typeAliases><!--    配置数据库连接关键信息配置到spring.xml中--><!--mapper映射也配置到spring.xml--></configuration>

(3)搭建spring全局配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!--开启spring注解的扫描功能 指定扫描包--><context:component-scan base-package="com.wbc.ssm"> </context:component-scan><!--阿里巴巴数据库链接管理对象,负责生成数据库链接对象,以及提供了数据库链接池功能让spring管理数据库链接对象 相比myBatis的数据连接池,druid的功能更加灵活--><bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://127.0.0.1:3306/ssmd?serverTimezone=Asia/Shanghai"></property><property name="username" value="root"></property><property name="password" value="Wbc11280"></property><property name="initialSize" value="10"></property><!--初始化连接数量--><property name="maxActive" value="20"></property><!--最大连接数量--></bean><!--spring 管理sqlSessionFactory对象--><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="druidDataSource"></property><!--将druid配置进dataSource--><property name="configLocation"value="classpath:mybatis.xml"></property><!--配置myBatis配置文件--><!--扫描Mapper映射文件--><!--Mapper/*Mapper.xml表示Mapper包下的所有映射--><property name="mapperLocations" value="classpath:Mapper/*Mapper.xml"></property></bean><!--生成dao层接口下的所有代理对象--><!--因此在dao层接口写不需要通过@Repository配置--><bean id="mapperFactory"class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.wbc.ssm.dao"></property><!--指定包名--><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property></bean>
</beans>
由于通过spring 管理sqlSessionFactory对象所以不需要再手动获取sqlSessionFactory对象

 

(4)创建model类
package com.wbc.ssm.model;import org.springframework.stereotype.Component;import java.io.Serializable;@Component
public class Admin implements Serializable {private int id;private String account;private String password;//lombok组件 在编译期间动态生成get、set方法public int getId() {return id;}public void setId(int id) {this.id = id;}public String getAccount() {return account;}public void setAccount(String account) {this.account = account;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "Admin{" +"id=" + id +", account='" + account + '\'' +", password='" + password + '\'' +'}';}
}
(5)创建dao层
package com.wbc.ssm.dao;import com.wbc.ssm.model.Admin;public interface LoginDao {Admin login(Admin admin);
}
(6)创建dao层的映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace需要和接口路径对应-->
<mapper namespace="com.wbc.ssm.dao.LoginDao"><!--cache标签设置mapper开启二级缓存 flushInterval可以设置销毁时间,毫秒为单位 cache可以设置其他属性,包括是否只读,销毁策略等--><cache></cache><!--开启缓存需要返回的model类实现序列化接口Serializable--><select id="login" resultType="Admin">select id,account,password from admin where id = #{id}</select>
</mapper>
(7)创建service类调用dao层
package com.wbc.ssm.service;import com.wbc.ssm.dao.LoginDao;
import com.wbc.ssm.model.Admin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class LoginService {@AutowiredLoginDao loginDao;public Admin login(Admin admin) {Admin admin1 = loginDao.login(admin);return admin1;}
}
(8)测试Test
package com.wbc.ssm.test;import com.wbc.ssm.model.Admin;
import com.wbc.ssm.service.LoginService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {//调用xml配置文件ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");//获取service对象LoginService loginService = applicationContext.getBean("loginService", LoginService.class);//模拟web前端传入的数据Admin admin = new Admin();admin.setId(1);//调用方法查询Admin admin1 = loginService.login(admin);System.out.println(admin1);}
}

输出

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • QT+OSG显示一个三维模型
  • 又一个强大的开源编辑器Vditor
  • safari扩展程序开发
  • 03_React 收集表单数据和 组件生命周期
  • 【drools】Rulesengine构建及intelj配置
  • 怎样写好提示词(Prompt) 二
  • ETAS工具链自动化实战指南<二>
  • 图像处理 -- 图像清晰度测量方法
  • Vue3项目开发——新闻发布管理系统(四)
  • 【解压即玩】使命de召唤4
  • Python与Plotly实现多维度数据的动态可视化——交互式股票价格
  • java-集合框架
  • 【AI绘画】Midjourney前置指令/settings设置详解
  • pdf解密软件哪个好用?掌握3个方法,轻松解锁PDF自由查看!
  • Python 爬虫 示例
  • Google 是如何开发 Web 框架的
  • 30天自制操作系统-2
  • ComponentOne 2017 V2版本正式发布
  • E-HPC支持多队列管理和自动伸缩
  • JDK9: 集成 Jshell 和 Maven 项目.
  • MySQL QA
  • PAT A1017 优先队列
  • Quartz初级教程
  • spring boot 整合mybatis 无法输出sql的问题
  • SQLServer之创建数据库快照
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 老板让我十分钟上手nx-admin
  • 聊聊flink的TableFactory
  • 免费小说阅读小程序
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 试着探索高并发下的系统架构面貌
  • 收藏好这篇,别再只说“数据劫持”了
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 栈实现走出迷宫(C++)
  • 追踪解析 FutureTask 源码
  • ​​​​​​​​​​​​​​Γ函数
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • ###C语言程序设计-----C语言学习(3)#
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • #Linux(Source Insight安装及工程建立)
  • #图像处理
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (接上一篇)前端弄一个变量实现点击次数在前端页面实时更新
  • (没学懂,待填坑)【动态规划】数位动态规划
  • (十)c52学习之旅-定时器实验
  • (淘宝无限适配)手机端rem布局详解(转载非原创)
  • *1 计算机基础和操作系统基础及几大协议
  • . Flume面试题
  • .NET Standard 的管理策略
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • @Async注解的坑,小心