【微服务】---1、在原有基础上添加微服务模块

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cdnight/article/details/86732474

前言

当前码农界言必称微服务,行必说分布式。。。嗯,让我也蹭蹭热点,也写写“微服务”。

新建这个程序的本意其实是,作为服务提供者,每次都拖着一个tomcat运行似乎不太合适,所以弄成一个可独立发布的java application程序。也算是简化一下项目了。

背景

这次的项目依然是spring+gradle+xxl-conf配置中心。
项目结构如下:
在这里插入图片描述

创建一个gradle的java模块过程不累述,下面看看当前子模块的build.gradle:

plugins {
    id 'java'
}


group 'net.w2p'
version '1.0-SNAPSHOT'


dependencies {


    compile project(":Shared")
    compile (project(":xxl-conf-core"))
    compile (project(":WebExt"))
    
    //--redis
    compile ref4RedisClient
    //【spring 框架】
    compile ref4SpringFramework

    //【mybatis】
    compile ref4MyBatis
    compile ref4MybatisSpring

    //【apache commons】
    compile ref4ApacheCommons

    //postgresql
    compile ref4PostgresqlJdbcDriver
    //druid    
    compile ref4Druid



}

暂时只需要这么多依赖,以后随项目而添加。

编译替换配置文件

执行:
在这里插入图片描述

结果为:
在这里插入图片描述

替换复制配置成功。

spring的配置文件说明

spring的配置文件有两个,一个是applicationContext.xml,一个是spring-mvc.xml,下面进行要点说明:

注意,java application程序中不需要spring-mvc.xml,因为spring-mvc.xml是web专用的。applicationContext存放在resource下面的,假如没有的话请新建:
在这里插入图片描述

applicationContext.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:task="http://www.springframework.org/schema/task"
       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/aop http://www.springframework.org/schema/aop/spring-aop-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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
 http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd"

>

    <!--&lt;!&ndash;导入xxl conf spring配置文件&ndash;&gt;-->
    <!--<import resource="classpath:/spring/applicationContext-XxlConf.xml"></import>-->
    <!--注意,该上下文配置文件只用于 contextLoaderListener,是程序基本上下文,作为父context被其他上下文引用-->
    <!--分工:整个Web应用程序需要共享的一些组件,比如DAO,数据库的ConnectionFactory等,mybatis,等等-->


    <!--

    net.w2p.local.Shared.mybatis.TypeHandlers =》 自定义mybatis数据类型转换,譬如,数组类型,布尔值类型等。

    net.w2p.local.plugins.BeanConfiguration=》自定义的java类作为configuration的方法,包含了数据库datasource源
    -->
    <context:component-scan
            base-package="
            net.w2p.Shared.mybatis.TypeHandlers,
            net.w2p.local.plugins.BeanConfiguration
"/>



</beans>

入口程序编写配置说明

入口程序在:
在这里插入图片描述

代码为:

package net.w2p.BaseServiceApp;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.concurrent.Semaphore;

public class Application {
    public static void main(String[] args){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        context.start();
        //--用信号量阻塞主线程。
        Semaphore stop=new Semaphore(0);
        try{
            stop.acquire();
        }
        catch (Exception ed){
            ed.printStackTrace();
        }
        System.out.println("服务关闭");

    }
}

配置xxl-conf

配置过程其实跟web模块的一样的,直接抄即可。

编译配置文件

首先,请执行:

 gradle -q compileConfig -Denv=test

先执行命令生成xxl-conf的配置properties文件:
在这里插入图片描述

生成的配置文件内容如下:

在这里插入图片描述

然后,在FileServerWebApp项目下面的BeanConfiguration添加xxl-conf的配置以及初始化:
在这里插入图片描述

代码如下:

package net.w2p.local.plugins.BeanConfiguration;
import com.xxl.conf.core.spring.XxlConfFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;

/***配置中心配置***/
@Configuration
public class ConfCenter {

    /***xxl-conf配置工厂***/
    @Bean(name="xxlConfFactory")
    public XxlConfFactory xxlConfFactory(){
        /****
         * 读取本地配置文件
         * ***/
        Properties config=new Properties();
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("conf/xxl-conf.properties");
        try {
            InputStreamReader is = new InputStreamReader(in, "utf-8");
            config.load(is);
            is.close();
            in.close();
        }
        catch (Exception ed){
            ed.printStackTrace();
        }
        String adminAddress=config.getProperty("xxl.conf.admin.address");
		String env=config.getProperty("xxl.conf.env");
		String accessToken=config.getProperty("xxl.conf.access.token");
		String mirrorfile=config.getProperty("xxl.conf.mirrorfile");
		XxlConfFactory xxlConf = new XxlConfFactory();
        xxlConf.setAdminAddress(adminAddress);
        xxlConf.setEnv(env);
        xxlConf.setAccessToken(accessToken);
        xxlConf.setMirrorfile(mirrorfile);

        return xxlConf;
    }

}

java application程序的测试

ps!!!java application的spring的测试与web的spring测试大部分一样,但是只有一点要记住,不能应用@WebAppConfiguration属性否则会报错:
在这里插入图片描述

错误代码如下:

org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.test.context.web.WebDelegatingSmartContextLoader]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: javax/servlet/ServletContext

	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:184)
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:122)
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:152)
	at org.springframework.test.context.support.AbstractTestContextBootstrapper.resolveContextLoader(AbstractTestContextBootstrapper.java:457)
	at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:348)
	at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:294)
	at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildTestContext(AbstractTestContextBootstrapper.java:108)

意思是无法初始化webContext----额,java application不是web。。。
好了,下面进行配置测试:
首先,新建一个测试基础类,以后的测试都要继承自这个基础类进行测试,譬如,就叫BaseTest
在这里插入图片描述

内容如下:

package main;


import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

/***注意,跟spring+web整合的测试不同点在于:
 * 1、没有WebAppConfiguration
 * 2、没有spring-mvc.xml这个配置文件
 *
 * ***/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
        "classpath*:applicationContext.xml"
}
)
public class BaseTest {
    Date beginDate;
    Long begin=null;
    Long end=null;
    Date endDate=null;
    @Before
    public void init() {
        //--初始化spring上下文
        System.out.println("初始化spring上下文中......");
        //在运行测试之前的业务代码
        beginDate = new Date();
        begin = beginDate.getTime();
        System.out.println("任务开始时间:" + beginDate);
    }
    @After
    public void after() {
        //在测试完成之后的业务代码
        endDate = new Date();
        end = endDate.getTime();
        System.out.println("任务结束时间:" + endDate + "");
        System.out.println("任务话费时间:" + (end - begin) + "毫秒");
    }

    /***用于测试最大并发***/
    public void runMultiThreadTest(int totalThreadCount, int threadPoolSize, Runnable runnable){
        {
            final int threadSize= totalThreadCount;
            ExecutorService executor= Executors.newFixedThreadPool(threadPoolSize);
            final AtomicInteger lockCount=new AtomicInteger(threadSize);
            final AtomicInteger successCount=new AtomicInteger(0);
            try {
                for (int i = 0; i < threadSize; i++) {
                    final int theThreadNumber = i;
                    executor.submit(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                runnable.run();
                                successCount.incrementAndGet();
                            }
                            catch (Exception ed){
                                ed.printStackTrace();
                            }
                            finally {
                                lockCount.decrementAndGet();
                            }
                        }
                    });
                }



                while(true){
                    synchronized (this){
                        if(lockCount.intValue()>0){
                            ;
                        }
                        else{
                            break;
                        }
                    }
                }

                System.out.println("注意当前线程池最大线程数量为"+threadPoolSize+"个");
                System.out.println("共运行线程"+threadSize+"个,成功运行线程:"+successCount.get()+"个");
            }
            catch (Exception ed){
                ed.printStackTrace();
            }
        }
    }

    /***用于测试任务阻塞的任务队列执行下的性能***/
    public void runMultiThreadByBlockQueue(int threadCount,TaskProducer producer,TaskConsumer consumer){
        final LinkedBlockingQueue<TaskOutLine> queue=new LinkedBlockingQueue<>(threadCount);
        final int threadSize=threadCount;
        ExecutorService executor= Executors.newFixedThreadPool(threadSize);
        final AtomicInteger lockCount=new AtomicInteger(threadSize);
        final AtomicInteger successCount=new AtomicInteger(0);
        try {
            /***线程池同时产生任务队列***/

            for (int i = 0; i < threadSize; i++) {
                final int theThreadNumber = i;
                TaskOutLine tmpOutLine=new TaskOutLine();
                tmpOutLine.taskIndex=theThreadNumber;
                executor.submit(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            tmpOutLine.taskData=producer.produce();
                            queue.put(tmpOutLine);
                        }
                        catch (Exception ed){
                            ed.printStackTrace();
                        }
                        finally {

                        }
                    }
                });
            }
            /***另起一个线程用于消费队列**/
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (lockCount.get()>0){
                        try{
                            TaskOutLine currentObj=queue.take();
                            consumer.consume(currentObj);
                            successCount.incrementAndGet();
                        }
                        catch (Exception ed){

                        }
                        finally {
                            lockCount.decrementAndGet();
                        }


                    }

                }
            }).start();



            while(true){
                synchronized (this){
                    if(lockCount.intValue()>0){
                        ;
                    }
                    else{

                        break;
                    }
                }
            }
            System.out.println("共运行线程"+threadSize+"个,成功运行线程:"+successCount.get()+"个");
        }
        catch (Exception ed){
            ed.printStackTrace();
        }


    }


    public interface TaskProducer{
        public Object produce();
    }
    public interface TaskConsumer{
        public void consume(TaskOutLine taskOutLine);
    }

    public class TaskOutLine{
        public int taskIndex=0;
        public Object taskData=new Object();

        public int getTaskIndex() {
            return taskIndex;
        }

        public void setTaskIndex(int taskIndex) {
            this.taskIndex = taskIndex;
        }

        public Object getTaskData() {
            return taskData;
        }

        public void setTaskData(Object taskData) {
            this.taskData = taskData;
        }
    }
}

测试xxl-conf配置情况

编写测试代码:
在这里插入图片描述

代码为:

package other;

import com.xxl.conf.core.XxlConfClient;
import main.BaseTest;
import net.w2p.WebExt.Plugins.RedisPlugin;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;

import java.util.Date;

public class TestCase1 extends BaseTest {

    @Test
    public void printConf(){
        String str=	 XxlConfClient.get("default.key01", null);
        System.out.println("从配置中心获取default.key01的值是:"+str);
    }
}

测试结果:
在这里插入图片描述

测试完成。

注意,假如运行application的话,会看到:
在这里插入图片描述

程序一直阻塞,那是因为信号量一直阻塞主线程了。

猜你喜欢

转载自blog.csdn.net/cdnight/article/details/86732474
今日推荐