Spring Finishing Series (16)-Understanding Spring containers and Dubbo+zookeeper unit test exception handling through unit tests

Source: Internet
Author: User
Tags bind exception handling throw exception xmlns zookeeper zookeeper client


First, let's say one conclusion: unit tests are isolated from the spring container of the main project, that is, unit tests cannot access the main Project Spring container and need to load the spring container yourself.

Next is the code instance, where the Web master project is running, and you might see code like this in the unit test:

Code One: current Class-Loaded

public class Testspring {

    @Test public
    void Testspring () {
        Loginservice loginservice = This.getbean (" Loginservice ");
    }

    The following is a container instance declaration and initialization, destruction of
    private classpathxmlapplicationcontext context;

    @Before public
    Void before () {
        //Load Spring container
        context = new Classpathxmlapplicationcontext (" Spring-context.xml ");
    }

    @After public
    Void after () {
        Context.destroy ();
    }

    Gets the bean from the static variable ApplicationContext and automatically transforms it into the type of the assigned value object.
    Public <T> T Getbean (String name) {
        return (T) Context.getbean (name);
    }

    Gets the bean from the static variable ApplicationContext and automatically transforms it into the type of the assigned value object.
    Public <T> T Getbean (class<t> requiredtype) {
        return Context.getbean (requiredtype);
    }
}

Code two: Inherit the loaded type

/** 
 * @Description: Login unit Test Class
 */Public
class Logintest extends springjunitsupport{

    @Autowired
    Private Loginservice Loginservice;

    @Test public
    void Testlogin () {
        loginservice.login ();
    }
}
Let unit tests run in the spring environment, with spring framework-related support
@RunWith (springjunit4classrunner.class)
//Load Spring container
@ Contextconfiguration ("Classpath:/spring-context.xml") public
class Springjunitsupport {

}

Code three: Dynamically add Spring profile

/** * @Description: Login unit Test class */public class logintest{//use @before annotations to load Spring container configuration file, cannot pass

    The bean is injected in a way that is automatically assembled, since the automatic assembly annotations are performed earlier than @before//@Autowired private loginservice loginservice;

    Private Testspringcontextsupport springcontextsupport = null;

        @Before public void SetUp () throws Exception {springcontextsupport = new testspringcontextsupport (); 
        When the spring container is initialized, the spring bean configuration file springcontextsupport.init (new string[] {"Classpath:/support-quartz.xml"} is added dynamically;
    Loginservice = Springcontextsupport.getbean ("Loginservice");
    } @Test public void Testlogin () {loginservice.login (); }
}
public class Testspringcontextsupport {//Initializes a static variable with a static statement block to hold the Spring container profile public static list<string> cont
    Extlist = new arraylist<string> ();
    static {Contextlist.add ("classpath:/spring-context.xml");

    } private ApplicationContext context; Define initialization method, dynamically add spring configuration file to static profile collection public void init (string[] contextfile) {list<string> List = new Array
        List<string> ();
        List.addall (contextlist);
        for (int i = 0; Contextfile! = null && i < contextfile.length; i++) {List.add (contextfile[i]);
        } string[] x = new string[list.size ()];
        List.toarray (x);
    Load Spring Container context = new Classpathxmlapplicationcontext (x);
    }//Gets the bean from the static variable ApplicationContext and automatically transforms to the type of the assigned value object.
    Public <T> T Getbean (String name) {return (T) Context.getbean (name);
    }//Gets the bean from the static variable ApplicationContext and automatically transforms to the type of the assigned value object. Public <T> T Getbean (class<t&Gt
    Requiredtype) {return Context.getbean (requiredtype); }
}


As in the above three ways, there is one thing in common, that is, before the unit test method executes, it is a lot of trouble to load the spring container.
Because the Web master project is running, why does the unit test also load the spring container separately, because the spring container for the Web master project is isolated from the unit test and verified by the following means:

Verification 1:

Remove all the code that loads the spring container from the unit test to ensure that the main project is running, with @autowired annotations (@Autowired annotations can assemble spring internal beans), and get the beans for the spring application context. Then get the business bean through it, the code is as follows:

/** 
 * @Description: Login unit Test Class
 *
/public class

    logintest{//Auto Assemble Spring application context Bean
    @Autowired
    Private ApplicationContext context;

    @Test public
    void Testlogin () {
        //By applying a context bean, get business bean
        loginservice loginservice = (loginservice) Context.getbean ("Loginservice");
        Loginservice.login ();
    }
}

The result must be a null pointer exception, and the context object is null.

verify two, stop the web main project, and unit test load the spring container using the second inherited method above, as in the following code:

/** 
 * @Description: Login unit test class, Inherit Springjunitsupport load Spring container
 */Public
class Logintest extends springjunitsupport{

    //Auto Assemble Spring application context Bean
    @Autowired
    private applicationcontext context;

    @Test public
    void Testlogin () {
        //By applying a context bean, get business bean
        loginservice loginservice = (loginservice) Context.getbean ("Loginservice");
        Loginservice.login ();
    }
}
@RunWith (Springjunit4classrunner.class)
//Load Spring container
@ContextConfiguration ("classpath:/ Spring-context.xml ") Public
class Springjunitsupport {

}


As a result, this verifies that the unit tests are isolated from the spring container of the main project and that the unit test must load the spring container itself.

It's been said that loading the spring container is actually loading the configuration file, loading the bean inside the config file into the spring container, and verifying that it is important to understand and apply this by searching the Bean object in the Spring container.

the last of the eggs, understanding is because the project is confused, explored before you can understand thoroughly, such as an example:

1, the main project runs, provides the service interface, adopts the way for the Dubbo+zookeeper way;

2, Unit test, call the service provided by the provider, using the inherited load spring configuration file;

3. Throw exception: The address has been bound to use (addr already in use:bind)

java.lang.IllegalStateException:Failed to load ApplicationContext ...
caused By:com.alibaba.dubbo.rpc.RpcException:Fail to start server (url:dubbo://127.0.0.1:20880/...
......
caused by:com.alibaba.dubbo.remoting.RemotingException:Failed to bind Nettyserver on/127.0.0.1:20880, cause:failed to Bind to:/0.0.0.0:20880 ...
caused by:org.jboss.netty.channel.ChannelException:Failed to bind to:/0.0.0.0:20880 ...
caused by:java.net.BindException:Address already in Use:bind
...

4. Exception reason: Because the Dubbo+zookeeper method is used, the main project Spring provider registers the 127.0.0.1:20880, the unit test loads the spring configuration file to register the 0.0.0.0:20880 address, However, 20880 is already occupied by the primary container, so unit tests do not load properly.

5, the solution: to stop the main container, using unit testing alone, that is, as a service side and as a client

6. Throw the exception again:

DEBUG [2016-08-18 18:30:26,603]-Zkclient.java ()-Closing zkclient ...
INFO [2016-08-18 18:30:26,603]-Zkeventthread.java ()-Terminate zkclient event thread. DEBUG [2016-08-18 18:30:26,603]-Zkconnection.java ()-Closing ZooKeeper connected to 119.254.166 .167:2181 DEBUG [2016-08-18 18:30:26,603]-Zookeeper.java ()-Closing session:0x15678a538f900 EF DEBUG [2016-08-18 18:30:26,603]-Clientcnxn.java ()-Closing Client for session:0x15678a538
F900ef ... DEBUG [2016-08-18 18:30:26,808]-Zkclient.java ()-Closing zkclient...done INFO [2016-08-18 18:30:26,810]-Dubboprotocol.java ()-[Dubbo] Close Dubbo Server:/127.0.0.1:20880, Dubbo version : 2.5.4, current host:127.0.0.1 INFO [2016-08-18 18:30:26,812]-Abstractserver.java ()-[Dubbo] Close Nettyserver bind/0.0.0.0:20880, export/127.0.0.1:20880, Dubbo version:2.5.4, current host:127.0.0.1 INFO [2016-08-18 18:30:26,812]-Clientcnxn.java ()-Eventthread shut down for Session:0x15678a538f900ef ERROR [2016-08-18 18:30:26,813]-failback Registry.java ()-[Dubbo] Failed to Uregister dubbo://127.0.0.1:20880/... com.alibaba.dubbo.rpc.Rp cexception:failed to unregister dubbo://127.0.0.1:20880/business method ... at Com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry.doUnregister (zookeeperregistry.java:108) at Com.alibaba.dubbo.registry.support.FailbackRegistry.unregister (failbackregistry.java:160) at Com.alibaba.dubbo.registry.integration.registryprotocol$1.unexport (registryprotocol.java:130) at Com.alibaba.dubbo.config.ServiceConfig.unexport (serviceconfig.java:270) at Com.alibaba.dubbo.config.spring.ServiceBean.destroy (servicebean.java:255) at Org.springframework.beans.factory.support.DisposableBeanAdapter.destroy (Disposablebeanadapter.java: 258) at Org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean ( defaultsingletonbeanregistry.java:538) at Org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton ( defaultsingletonbeanregistry.java:514) at Org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton ( defaultlistablebeanfactory.java:831) at Org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons ( defaultsingletonbeanregistry.java:483) at Org.springframework.context.support.AbstractApplicationContext.destroyBeans (Abstractapplicationcontext.java : 923) at Org.springframework.context.support.AbstractApplicationContext.doClose (Abstractapplicationcontext.java : 897) at Org.springframework.context.support.abstractapplicationcontext$1.run (Abstractapplicationcontext.java : 811) caused by:java.lang.NullPointerException at org. I0itec.zkclient.zkclient$8.call (zkclient.java:720) at Org. i0iTec.zkclient.ZkClient.retryUntilConnected (zkclient.java:675) at Org. I0Itec.zkclient.ZkClient.delete (zkclient.java:716) at
    Com.alibaba.dubbo.remoting.zookeeper.zkclient.ZkclientZookeeperClient.delete (zkclientzookeeperclient.java:57) At Com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry.doUnregister (zookeeperregistry.java:106) ... More


The key information that needs to be noted above can be summed up as: Zookeeper client shutdown (Closing zkclient ...), Dubbo service shutdown (Close Dubbo server ...), logoff Dubbo a method failed (Failed to Uregister dubbo://127.0.0.1:20880/...)
Although not carefully explore what is going on, but it should be the unit test load both the server and the client (that is, load the spring configuration file), when the test method is completed to close the service, due to sequencing problems caused by the exception.

7, the solution: The provider is initiated by the main container, as for the unit test, on the last egg that sentence, unit testing as a client, only need to get the service provider's Bean object, you can complete the service end of the provider's call.

So where does this object come from, the Dubbo+zookeeper method configures the subscription service's configuration file in the client, which has the provider's corresponding bean, so the unit test only needs to load the client subscription configuration file, the code is as follows:

@RunWith (Springjunit4classrunner.class)
@ContextConfiguration ({"Classpath:/spring/test-dubbo-consumer.xml") }) public
class Coderulerpcimpldubbotest {
    @Autowired
    private userrpc userrpc;

    @Test public
    void Testgetuserbycode () {
        Bizcode = Userrpc.getuserbycode ("001");
    }

}

Client subscriber configuration file:

<?xml version= "1.0" encoding= "UTF-8"?> <beans xmlns= "Http://www.springframework.org/schema/beans" xmlns:
    Xsi= "Http://www.w3.org/2001/XMLSchema-instance" xmlns:context= "Http://www.springframework.org/schema/context"
    Xmlns:jdbc= "Http://www.springframework.org/schema/jdbc" xmlns:jee= "Http://www.springframework.org/schema/jee"
    xmlns:tx= "Http://www.springframework.org/schema/tx" xmlns:util= "Http://www.springframework.org/schema/util"
    xmlns:task= "Http://www.springframework.org/schema/task" xmlns:dubbo= "Http://code.alibabatech.com/schema/dubbo" xsi:schemalocation= "Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/ Spring-beans-4.0.xsd Http://www.springframework.org/schema/context Http://www.springframework.org/schema/context /spring-context-4.0.xsd Http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/ Spring-jdbc-4.0.xsd Http://www.springframework.org/schema/jee httP://www.springframework.org/schema/jee/spring-jee-4.0.xsd HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/TX/HTTP Www.springframework.org/schema/tx/spring-tx-4.0.xsd Http://www.springframework.org/schema/util/HTTP Www.springframework.org/schema/util/spring-util-4.0.xsd Http://www.springframework.org/schema/task/HTTP Www.springframework.org/schema/task/spring-task-4.0.xsd Http://code.alibabatech.com/schema/dubbo/HTTP Code.alibabatech.com/schema/dubbo/dubbo.xsd "> <!--Consumer app name information, this is equivalent to a name, we Dubbo Management page is more clear which application is exposed--&L T;dubbo:application name= "Spring_dubbo_consumer" ></dubbo:application> <!--using zookeeper registry to expose the service address-- > <dubbo:registry address= "zookeeper://127.0.0.1:2181" check= "true" ></dubbo:registry> < !--User Management Service to reference-<dubbo:reference interface= "Com.test.rpc.UserRPC" id= "Userrpc" ></dubbo:referenc E> </beans>

The above problem is resolved, and the relationship between the spring container, unit test, Spring-bean, and the Dubbo and zookeeper are also deeply understood.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.