1 Bean 로딩을 구현하기 위해 ImportSelector 인터페이스를 구현합니다.
public class TestServiceImpl { public void testImpl() { System.out.println("我是通过importSelector导入进来的service"); } } public class TestService implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{"com.ycdhz.service.TestServiceImpl"}; } } @Configuration @Import(value = {TestService.class}) public class TestConfig { } public class TestController { @Autowired private TestServiceImpl testServiceImpl; @RequestMapping("testImpl") public String testTuling() { testServiceImpl.testImpl(); return "Ok"; } }
2. Bean 로딩을 구현하려면:
public class TestService { public TestService() { System.out.println("我是通过ImportBeanDefinitionRegistrar导入进来的组件"); } } public class TestImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //定义一个BeanDefinition RootBeanDefinition beanDefinition = new RootBeanDefinition(TestService.class); //把自定义的bean定义导入到容器中 registry.registerBeanDefinition("testService",beanDefinition); } } @Configuration @Import(TestImportBeanDefinitionRegistrar.class) public class TestConfig { }
spring-boot-autoconfigure-2.0.6.RELEASE.jar에서 Tomcat의 관련 구성을 검색한 결과 두 가지 자동 구성이 있음을 발견했습니다. 어셈블리 클래스 세 개(객체 지향 단일 책임 원칙)와 팩터리 클래스가 포함되어 있습니다.
2.1, TomcatWebServerFactoryCustomizer: 서블릿 및 Reactive 서버에 공통적인 Tomcat 관련 기능을 사용자 정의합니다.
public class TomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<configurabletomcatwebserverfactory>, Ordered { @Override public void customize(ConfigurableTomcatWebServerFactory factory) { ServerProperties properties = this.serverProperties; ServerProperties.Tomcat tomcatProperties = properties.getTomcat(); PropertyMapper propertyMapper = PropertyMapper.get(); propertyMapper.from(tomcatProperties::getBasedir).whenNonNull() .to(factory::setBaseDirectory); propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull() .as(Duration::getSeconds).as(Long::intValue) .to(factory::setBackgroundProcessorDelay); customizeRemoteIpValve(factory); propertyMapper.from(tomcatProperties::getMaxThreads).when(this::isPositive) .to((maxThreads) -> customizeMaxThreads(factory, tomcatProperties.getMaxThreads())); propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive) .to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads)); propertyMapper.from(() -> determineMaxHttpHeaderSize()).when(this::isPositive) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); propertyMapper.from(tomcatProperties::getMaxHttpPostSize) .when((maxHttpPostSize) -> maxHttpPostSize != 0) .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory, maxHttpPostSize)); propertyMapper.from(tomcatProperties::getAccesslog) .when(ServerProperties.Tomcat.Accesslog::isEnabled) .to((enabled) -> customizeAccessLog(factory)); propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull() .to(factory::setUriEncoding); propertyMapper.from(properties::getConnectionTimeout).whenNonNull() .to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout)); propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive) .to((maxConnections) -> customizeMaxConnections(factory, maxConnections)); propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive) .to((acceptCount) -> customizeAcceptCount(factory, acceptCount)); customizeStaticResources(factory); customizeErrorReportValve(properties.getError(), factory); } }</configurabletomcatwebserverfactory>
2.2. ServletWebServerFactoryCustomizer: WebServerFactoryCustomizer는 ServerProperties 속성을 Tomcat 웹 서버에 적용합니다.
public class ServletWebServerFactoryCustomizer implements WebServerFactoryCustomizer<configurableservletwebserverfactory>, Ordered { private final ServerProperties serverProperties; public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) { this.serverProperties = serverProperties; } @Override public int getOrder() { return 0; } @Override public void customize(ConfigurableServletWebServerFactory factory) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(this.serverProperties::getPort).to(factory::setPort); map.from(this.serverProperties::getAddress).to(factory::setAddress); map.from(this.serverProperties.getServlet()::getContextPath) .to(factory::setContextPath); map.from(this.serverProperties.getServlet()::getApplicationDisplayName) .to(factory::setDisplayName); map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession); map.from(this.serverProperties::getSsl).to(factory::setSsl); map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp); map.from(this.serverProperties::getCompression).to(factory::setCompression); map.from(this.serverProperties::getHttp2).to(factory::setHttp2); map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader); map.from(this.serverProperties.getServlet()::getContextParameters) .to(factory::setInitParameters); } }</configurableservletwebserverfactory>
2.3. ServletWebServerFactoryCustomizer: WebServerFactoryCustomizer는 ServerProperties 속성을 Tomcat 웹 서버에 적용합니다.
public class TomcatServletWebServerFactoryCustomizer implements WebServerFactoryCustomizer<tomcatservletwebserverfactory>, Ordered { private final ServerProperties serverProperties; public TomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) { this.serverProperties = serverProperties; } @Override public void customize(TomcatServletWebServerFactory factory) { ServerProperties.Tomcat tomcatProperties = this.serverProperties.getTomcat(); if (!ObjectUtils.isEmpty(tomcatProperties.getAdditionalTldSkipPatterns())) { factory.getTldSkipPatterns() .addAll(tomcatProperties.getAdditionalTldSkipPatterns()); } if (tomcatProperties.getRedirectContextRoot() != null) { customizeRedirectContextRoot(factory, tomcatProperties.getRedirectContextRoot()); } if (tomcatProperties.getUseRelativeRedirects() != null) { customizeUseRelativeRedirects(factory, tomcatProperties.getUseRelativeRedirects()); } } }</tomcatservletwebserverfactory>
AbstractApplicationContext#onReFresh()를 사용하여 tomcat을 IOC 컨테이너에서 시작하도록 구동한 다음 ioc 컨테이너의 다른 단계를 실행합니다.
3가지 커스터마이저의 로딩 과정은 물론, 중단점을 통해 Tomcat 로딩의 전체 라이프사이클을 관찰할 수 있습니다.
@Override public WebServer getWebServer(ServletContextInitializer... initializers) { Tomcat tomcat = new Tomcat(); File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat"); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connector connector = new Connector(this.protocol); tomcat.getService().addConnector(connector); customizeConnector(connector); tomcat.setConnector(connector); //设置是否自动启动 tomcat.getHost().setAutoDeploy(false); //创建Tomcat引擎 configureEngine(tomcat.getEngine()); for (Connector additionalConnector : this.additionalTomcatConnectors) { tomcat.getService().addConnector(additionalConnector); } //刷新上下文 prepareContext(tomcat.getHost(), initializers); //准备启动 return getTomcatWebServer(tomcat); }
private void initialize() throws WebServerException { TomcatWebServer.logger .info("Tomcat initialized with port(s): " + getPortsDescription(false)); synchronized (this.monitor) { try { addInstanceIdToEngineName(); Context context = findContext(); context.addLifecycleListener((event) -> { if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) { // Remove service connectors so that protocol binding doesn't // happen when the service is started. removeServiceConnectors(); } }); // Start the server to trigger initialization listeners this.tomcat.start(); // We can re-throw failure exception directly in the main thread rethrowDeferredStartupExceptions(); try { ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader()); } catch (NamingException ex) { // Naming is not enabled. Continue } // Unlike Jetty, all Tomcat threads are daemon threads. We create a // blocking non-daemon to stop immediate shutdown startDaemonAwaitThread(); } catch (Exception ex) { stopSilently(); throw new WebServerException("Unable to start embedded Tomcat", ex); } } }
Remarks: 이 프로세스에서는 Bean의 수명 주기를 이해해야 합니다. Tomcat의 세 가지 사용자 정의 프로그램은 모두 BeanPostProcessorsRegistrar(Bean 사후 프로세서) 프로세스에 로드됩니다.
구성 방법-->Bean 포스트 processorBefore-->InitializingBean-->init-method-->Bean 후처리 프로세서 설정
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //构造方法 instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Initialize the bean instance. ...... return exposedObject; } protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { //Bean后置处理器Before wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { //Bean后置处理器After wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }</object>
위 내용은 springboot에서 자체 시작을 달성하기 위해 Tomcat 컨테이너를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!