一、spring通过注解导入bean大体可分为四种方式,我们主要来说以下import的两种实现方法:1、通过实现importserlector接口,实现bean加载:
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、 通过实现importserlector接口,实现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 {}
二、 springboot启动过程中会自动装配我们从spring-boot-autoconfigure-2.0.6.release.jar下搜索到tomcat的相关配置,发现有两个自动装配类,分别包含了三个定制器(面向对象的单一职责原则),还有一个工厂类。
2.1、tomcatwebserverfactorycustomizer:定制servlet和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); }}
2.2、servletwebserverfactorycustomizer:webserverfactorycustomizer 将serverproperties属性应用于tomcat web服务器。
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); }}
2.3、servletwebserverfactorycustomizer :webserverfactorycustomizer 将serverproperties属性应用于tomcat web服务器。
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,相当于有了spring加载的入口通过abstractapplicationcontext#onrefresh()在ioc 容器中的带动tomcat启动,然后在接着执行 ioc容器的其他步骤。
我们通过断点可以观察tomcat加载的整个生命周期,以及三个定制器的加载过程。
@overridepublic 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); } }}
备注: 在这个过程中我们需要了解bean的生命周期,tomcat的三个定制器均在beanpostprocessorsregistrar(bean后置处理器)过程中加载;
构造方法-->bean后置处理器before-->initializingbean-->init-method-->bean后置处理器after
org.springframework.beans.factory.support.abstractautowirecapablebeanfactory#docreatebeanorg.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;}
以上就是springboot中如何利用tomcat容器实现自启动的详细内容。
