一、核心注解定义
SpringBoot的"约定优于配置"核心依赖注解实现,我们先定义核心注解:
import java.lang.annotation.*;
// 组合注解,替代@Configuration+@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@MyConfiguration
@EnableMyAutoConfiguration
public @interface MySpringBootApplication {
String scanBasePackages() default "";
}
// 配置类注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyConfiguration {
boolean proxyBeanMethods() default true;
}
// 开启自动配置
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MyAutoConfigurationImportSelector.class)
public @interface EnableMyAutoConfiguration {
}
// 自动配置类注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@MyConfiguration(proxyBeanMethods = false)
public @interface MyAutoConfiguration {
}
// 条件注解:存在指定类时生效
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConditionalOnClass {
String[] value() default {};
}
// 条件注解:不存在指定Bean时生效
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConditionalOnMissingBean {
Class<?>[] value() default {};
}
二、自动配置导入选择器
实现ImportSelector接口,加载自动配置类:
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class MyAutoConfigurationImportSelector implements ImportSelector {
private static final String AUTO_CONFIGURATION_FILE =
"META-INF/myspringboot/autoconfigure.imports";
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> configurations = new ArrayList<>();
// 读取自动配置文件
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(
getClass().getClassLoader().getResourceAsStream(AUTO_CONFIGURATION_FILE)
)
)) {
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (!line.isEmpty() && !line.startsWith("#")) {
configurations.add(line);
}
}
} catch (IOException e) {
throw new RuntimeException("Failed to load auto-configuration classes", e);
}
return configurations.toArray(new String);
}
}
三、条件评估器
实现条件注解的评估逻辑:
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
public class OnClassCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnClass.class.getName());
if (attributes == null) {
return false;
}
String[] classNames = (String[]) attributes.get("value");
for (String className : classNames) {
try {
context.getClassLoader().loadClass(className);
} catch (ClassNotFoundException e) {
return false;
}
}
return true;
}
}
public class OnMissingBeanCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnMissingBean.class.getName());
if (attributes == null) {
return false;
}
Class<?>[] beanTypes = (Class<?>[]) attributes.get("value");
for (Class<?> beanType : beanTypes) {
if (context.getBeanFactory().containsBean(beanType.getName())) {
return false;
}
}
return true;
}
}
四、示例自动配置类
创建一个模拟的Web自动配置类:
@MyAutoConfiguration
@ConditionalOnClass("javax.servlet.Servlet")
public class WebAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyDispatcherServlet dispatcherServlet() {
return new MyDispatcherServlet();
}
@Bean
@ConditionalOnMissingBean
public MyTomcatWebServer tomcatWebServer(MyDispatcherServlet dispatcherServlet) {
return new MyTomcatWebServer(dispatcherServlet);
}
}
五、嵌入式Web服务器实现
模拟Tomcat服务器的核心逻辑:
public class MyTomcatWebServer {
private final MyDispatcherServlet dispatcherServlet;
public MyTomcatWebServer(MyDispatcherServlet dispatcherServlet) {
this.dispatcherServlet = dispatcherServlet;
}
public void start() {
System.out.println("启动嵌入式Tomcat服务器,端口:8080");
System.out.println("注册DispatcherServlet处理请求");
// 实际Tomcat初始化逻辑简化
}
}
public class MyDispatcherServlet {
public void service(String request, String response) {
System.out.println("DispatcherServlet处理请求:" + request);
// 请求分发逻辑简化
}
}
六、SpringBoot应用启动类
实现核心启动逻辑:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MySpringApplication {
public static void run(Class<?> primarySource, String... args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册主配置类
context.register(primarySource);
// 刷新容器
context.refresh();
// 启动Web服务器
startWebServer(context);
System.out.println("MySpringBoot应用启动完成!");
}
private static void startWebServer(AnnotationConfigApplicationContext context) {
MyTomcatWebServer webServer = context.getBean(MyTomcatWebServer.class);
if (webServer != null) {
webServer.start();
}
}
}
七、测试应用
创建测试启动类和控制器:
@MySpringBootApplication
public class MyTestApplication {
public static void main(String[] args) {
MySpringApplication.run(MyTestApplication.class, args);
}
}
// 控制器示例
@MyController
@RequestMapping("/hello")
public class HelloController {
@GetMapping
public String hello() {
return "Hello MySpringBoot!";
}
}
八、自动配置文件
在resources/META-INF/myspringboot/autoconfigure.imports中添加:
com.example.autoconfigure.WebAutoConfiguration