创建一个工程,包含springboot和user两个module

SpringBoot是基于的Spring,所以我们要依赖Spring,然后我希望我们模拟出来的SpringBoot也支持Spring MVC的那一套功能,所以也要依赖Spring MVC,包括Tomcat等,所以在SpringBoot模块中要添加以下依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.60</version>
</dependency>
</dependencies>
在User模块只添加我们创建的SpringBoot的依赖:
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>springboot</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
定义相关Controller和Service

@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("test")
public String test(){
return userService.test();
}
}
@Service
public class UserService {
public String test() {
return "tacy";
}
}
在真正使用SpringBoot时,核心会用到SpringBoot一个类和注解:
现在也来模拟实现他们。
@TacySpringBootApplication注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScan
public @interface TacySpringBootApplication {
}
用来实现启动逻辑的TacySpringApplication类:
public class TacySpringApplication {
public static void run(Class clazz) {
}
}
**在MyApplication中来使用: **
@TacySpringBootApplication
public class UserApplication {
public static void main(String[] args) {
TacySpringApplication.run(UserApplication.class);
}
}
目前只是壳子出来了,还不能跑起来
目标: 希望run方法一旦执行完,就能在浏览器中访问到UserController,那势必在run方法中要启动Tomcat,通过Tomcat就能接收到请求了。
在SpringMVC中有一个Servlet非常核心,那就是DispatcherServlet,这个DispatcherServlet需要绑定一个Spring容器,因为DispatcherServlet接收到请求后,就会从所绑定的Spring容器中找到所匹配的Controller,并执行所匹配的方法。
所以,在run方法中,我们要实现的逻辑如下:
public class TacySpringApplication {
public static void run(Class clazz) {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(clazz);
applicationContext.refresh();
}
}
使用内嵌的tomcat, Embed-Tomcat
public static void startTomcat(WebApplicationContext applicationContext){
Tomcat tomcat = new Tomcat();
Server server = tomcat.getServer();
Service service = server.findService("Tomcat");
Connector connector = new Connector();
connector.setPort(8081);
Engine engine = new StandardEngine();
engine.setDefaultHost("localhost");
Host host = new StandardHost();
host.setName("localhost");
String contextPath = "";
Context context = new StandardContext();
context.setPath(contextPath);
context.addLifecycleListener(new Tomcat.FixContextListener());
host.addChild(context);
engine.addChild(host);
service.setContainer(engine);
service.addConnector(connector);
tomcat.addServlet(contextPath, "dispatcher", new DispatcherServlet(applicationContext));
context.addServletMappingDecoded("/*", "dispatcher");
try {
tomcat.start();
} catch (LifecycleException e) {
e.printStackTrace();
}
}
public static void run(Class clazz) {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(clazz);
applicationContext.refresh();
startTomcat(applicationContext);
}
现在运行Application,就能正常的启动项目,并能接收请求

在浏览器上访问:http://localhost:8081/test

上面已经实现了一个简单的SpringBoot,接下来继续扩充,实现以下需求:
需求目标: 希望SpringBoot自动帮我实现,对于程序员用户而言,只要在Pom文件中添加相关依赖就可以了,想用Tomcat就加Tomcat依赖,想用Jetty就加Jetty依赖
定义一个接口,WebServer, 在这个接口中定义一个start方法
public interface WebServer {
public void start();
}
再针对Tomcat和Jetty提供2个实现类
public class TomcatWebServer implements WebServer{
@Override
public void start() {
System.out.println("启动Tomcat");
}
}
public class TomcatWebServer implements WebServer{
@Override
public void start() {
System.out.println("启动Jetty");
}
}
在TacySpringApplication中的run方法中,去获取对应的WebServer,然后启动对应的webServer,代码为:
public static void run(Class clazz){
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(clazz);
applicationContext.refresh();
WebServer webServer = getWebServer(applicationContext);
webServer.start();
}
public static WebServer getWebServer(ApplicationContext applicationContext){
return null;
}
实现一个条件注解@TacyConditionalOnClass
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(TacyOnClassCondition.class)
public @interface TacyConditionalOnClass {
String value() default "";
}
真正实现条件逻辑的是@Conditional(TacyOnClassCondition.class)中的TacyOnClassCondition
public class TacyOnClassCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(TacyConditionalOnClass.class.getName());
String className = (String) annotationAttributes.get("value");
try {
context.getClassLoader().loadClass(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}