spring容器以及Tomcat启动流程
- 在
CasSpringApplication
的run方法中启动spring容器
public class CasSpringApplication {
public static void run(Class clazz) {
// 启动sprinng容器
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(clazz);
context.refresh();
// 启动服务
start(context);
}
}
- 定义服务
2.1 定义接口
public interface WebServer {
void start();
}
2.2 Tomcat实现类
public class TomcatWebServer implements WebServer {
@Override
public void start() {
System.out.println("tomcat 启动了");
}
}
2.3 Jetty实现类
public class JettyWebServer implements WebServer {
@Override
public void start() {
System.out.println("jetty 启动了");
}
}
2.3 获取实现类
public static void start(AnnotationConfigWebApplicationContext applicationContext) {
Map<String, WebServer> webserver = applicationContext.getBeansOfType(WebServer.class);
if (webserver.size() > 1) {
throw new RuntimeException("获取到多个服务");
}
webserver.values().stream().findFirst().get().start();
}
- 动态选择服务
- 如果项目中有Tomcat就启动Tomcat
- 如果项目中有Jetty则启动Jetty
3.1 条件注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Conditional(CondationOnExitClass.class)
public @interface CondationOnExit {
String value() default "";
}
3.2 CondationOnExitClass
实现类
public class CondationOnExitClass implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
MultiValueMap<String, Object> map = metadata.getAllAnnotationAttributes(CondationOnExit.class.getName());
String className = (String) map.getFirst("value");
try {
context.getClassLoader().loadClass(className);
return true;
} catch (ClassNotFoundException e) {
e.printStackTrace();
return false;
}
}
}
3.3 向spring
容器中注入bean
@Configuration
public class WebServerBean {
@Bean
@CondationOnExit("org.apache.catalina.startup.Tomcat")
public TomcatWebServer tomcatWebServer() {
return new TomcatWebServer();
}
@Bean
@CondationOnExit("org.eclipse.jetty.server.Server")
public JettyWebServer jettyWebServer() {
return new JettyWebServer();
}
}
springboot的包扫描
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScan
public @interface CasSpringBoot {
}
springboot 自动装配
- spring有一套自己实现的spi机制 在这里使用java自带的spi 暂时不做太复杂
public class AutoImportSelect implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// java spi
ServiceLoader<AutoConfiguation> configuations = ServiceLoader.load(AutoConfiguation.class);
List<String> list = new ArrayList<>();
for (AutoConfiguation configuation : configuations) {
list.add(configuation.getClass().getName());
}
return list.toArray(new String[0]);
}
}
这个类无法被spring包扫描到 我们需要手动导入
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScan
@Import({AutoImportSelect.class}) // 导入自动装配类
public @interface CasSpringBoot {
}
测试
至此我们一个极简版springboot就实现完毕了
@CasSpringBoot
public class CasApplication {
public static void main(String[] args) {
CasSpringApplication.run(CasApplication.class);
}
}