当前位置: 首页 > article >正文

Java必修课——Spring框架

目录

  • 一、Spring框架概述
  • 二、IOC概念和原理
    • 2.1、什么是IOC
    • 2.2、IOC接口
  • 三、深入理解Java基础中的集合框架
    • 3.1、Collection
    • 3.2、Map
    • 3.3、集合工具类
  • 四、练习写一个SpringMVC框架
    • 1、介绍
    • 2、程序实践
    • 3、总结
  • 五、Java开发者必备10大数据工具和框架

一、Spring框架概述

Spring是轻量级的开源的JAVAEE框架
Spring可以解决企业应用开发的复杂性
Spring有两个核心部分:IOC和Aop

IOC:控制反转,把创建对象的过程交个Spring进行管理
Aop:面向切面,不修改源代码进行功能增强

Spring特点

方便解耦,简化开发
Aop编程支持
方便程序测试
方便和其他框架进行整合
方便进行事务操作
降低API的使用难度

IOC容器

IOC底层原理
IOC接口(BeanFactory)
IOC操作Bean管理(基于XML)
IOC操作Bean管理(基于注解)

二、IOC概念和原理

2.1、什么是IOC

控制反转,把对象创建和对象之间调用过程,交给Spring进行管理

使用IOC目的:为了耦合度降低

IOC底层原理
xml解析,工厂模式,反射
在这里插入图片描述
在这里插入图片描述

2.2、IOC接口

  1. IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
  2. Spring提供IOC容器实现两种方式:(两个接口)
    2.1 BeanFactory:
    IOC容器基本实现方式,是spring内部使用接口,不提供开发人员进行使用
    加载配置文件不会创建对象,在获取对象才去创建对象
    2.2 ApplicationContext:
    BeanFactory接口的子接口,提供更多更强大的功能,一般是由开发人员进行使用
    加载配置文件时候就会把配置文件对象进行创建
  3. 使用ApplicationContext把加载过程交给启动服务器,不要留给运行中。
  4. ApplicationContext接口有实现类

在这里插入图片描述
盘路径 类路径

IOC操作Bean管理

  1. 什么是Bean管理
    Spring创建对象
    Spring注入属性
  2. Bean管理操作有两种方式
    基于xml配置文件方式实现
    基于注解方式实现

IOC操作Bean管理(xml)

基于xml方式创建队形
在这里插入图片描述

  1. 在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
  2. 在bean标签有很多属性,常用属性:
    id属性:唯一标识
    class属性:类全路径
  3. 创建对象时候,默认是执行无参构造

基于xml方式注入属性

  1. DI:依赖注入,注入属性
    使用set方法注入
    属性:类全路径
  2. 创建对象时候,默认是执行无参构造

三、深入理解Java基础中的集合框架

Java集合框架 (Java Collections Framework, JCF) 也称容器,这里可以类比 C++ 中的 STL,在市面上似乎还没能找到一本详细介绍的书籍。在这里主要对如下部分进行源码分析,及在面试中常见的问题。

例如,在阿里面试常问到的 HashMap 和 ConcurrentHashMap 原理等等。

Java集合框架提供了数据持有对象的方式,提供了对数据集合的操作。Java 集合框架位于java.util包下,主要有三个大类:Collection(接口)、Map(接口)、集合工具类。

3.1、Collection

  • ArrayList:线程不同步。默认初始容量为 10,当数组大小不足时容量扩大为 1.5 倍。为追求效率,ArrayList 没有实现同步(synchronized),如果需要多个线程并发访问,用户可以手动同步,也可使用 Vector 替代。
  • LinkedList:线程不同步。双向链接实现。LinkedList 同时实现了 List 接口和 Deque 接口,也就是说它既可以看作一个顺序容器,又可以看作一个队列(Queue),同时又可以看作一个栈(Stack)。这样看来,LinkedList 简直就是个全能冠军。当你需要使用栈或者队列时,可以考虑使用 LinkedList,一方面是因为 Java 官方已经声明不建议使用 Stack 类,更遗憾的是,Java 里根本没有一个叫做 Queue 的类(它是个接口名字)。关于栈或队列,现在的首选是 ArrayDeque,它有着比 LinkedList(当作栈或队列使用时)有着更好的性能。
  • Stack and Queue:Java 里有一个叫做 Stack 的类,却没有叫做 Queue 的类(它是个接口名字)。当需要使用栈时,Java 已不推荐使用 Stack,而是推荐使用更高效的 ArrayDeque;既然 Queue 只是一个接口,当需要使用队列时也就首选 ArrayDeque 了(次选是 LinkedList )。
  • Vector:线程同步。默认初始容量为 10,当数组大小不足时容量扩大为 2 倍。它的同步是通过Iterator方法加synchronized实现的。
  • Stack:线程同步。继承自 Vector,添加了几个方法来完成栈的功能。现在已经不推荐使用 Stack,在栈和队列中有限使用 ArrayDeque,其次是 LinkedList。
  • TreeSet:线程不同步,内部使用NavigableMap操作。默认元素 “自然顺序” 排列,可以通过Comparator改变排序。TreeSet 里面有一个 TreeMap(适配器模式)
  • HashSet:线程不同步,内部使用 HashMap 进行数据存储,提供的方法基本都是调用 HashMap 的方法,所以两者本质是一样的。集合元素可以为 NULL。
  • Set:Set 是一种不包含重复元素的 Collection,Set 最多只有一个 null 元素。Set 集合通常可以通过 Map 集合通过适配器模式得到。
  • PriorityQueue:Java 中 PriorityQueue 实现了 Queue 接口,不允许放入 null 元素;其通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值),也就意味着可以通过数组来作为 PriorityQueue 的底层实现。
  • 优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java 的优先队列每次取最小元素,C++ 的优先队列每次取最大元素)。这里牵涉到了大小关系,元素大小的评判可以通过元素本身的自然顺序(natural ordering),也可以通过构造时传入的比较器(Comparator,类似于 C++ 的仿函数)。
  • NavigableSet:添加了搜索功能,可以对给定元素进行搜索:小于、小于等于、大于、大于等于,放回一个符合条件的最接近给定元素的 key。
  • EnumSet:线程不同步。内部使用 Enum 数组实现,速度比HashSet快。只能存储在构造函数传入的枚举类的枚举值。

3.2、Map

  • TreeMap:线程不同步,基于红黑树(Red-Black tree)的 NavigableMap 实现,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用 Iterator 遍历 TreeMap 时,得到的记录是排过序的。
  • TreeMap 底层通过红黑树(Red-Black tree)实现,也就意味着containsKey(),get(),put(),remove()都有着log(n)的时间复杂度。其具体算法实现参照了《算法导论》。
    HashTable:线程安全,HashMap 的迭代器 (Iterator) 是fail-fast迭代器。HashTable 不能存储 NULL 的 key 和 value。
  • HashMap:线程不同步。根据key的hashcode进行存储,内部使用静态内部类Node的数组进行存储,默认初始大小为 16,每次扩大一倍。当发生 Hash 冲突时,采用拉链法(链表)。JDK 1.8中:当单个桶中元素个数大于等于8时,链表实现改为红黑树实现;当元素个数小于6时,变回链表实现。由此来防止hashCode攻击。
Java HashMap 采用的是冲突链表方式。
HashMap 是 Hashtable 的轻量级实现,可以接受为 null 的键值 (key) 和值 (value),而 Hashtable 不允许。
  • LinkedHashMap:保存了记录的插入顺序,在用 Iterator 遍历 LinkedHashMap 时,先得到的记录肯定是先插入的。也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比 HashMap 慢,不过有种情况例外,当 HashMap 容量很大,实际数据较少时,遍历起来可能会比 LinkedHashMap 慢,因为 LinkedHashMap 的遍历速度只和实际数据有关,和容量无关,而 HashMap 的遍历速度和他的容量有关。
  • WeakHashMap:从名字可以看出它是某种 Map。它的特殊之处在于 WeakHashMap 里的 entry 可能会被 GC 自动删除,即使程序员没有调用remove()或者clear()方法。 WeakHashMap 的存储结构类似于HashMap
既然有 WeekHashMap,是否有 WeekHashSet 呢?答案是没有!不过 Java Collections 工具类给出了解决方案,Collections.newSetFromMap(Map<E,Boolean> map)方法可以将任何 Map包装成一个Set。

3.3、集合工具类

  • Collections、Arrays:集合类的一个工具类帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

  • Comparable、Comparator:一般是用于对象的比较来实现排序,两者略有区别。

类设计者没有考虑到比较问题而没有实现 Comparable 接口。这是我们就可以通过使用 Comparator,这种情况下,我们是不需要改变对象的。
一个集合中,我们可能需要有多重的排序标准,这时候如果使用 Comparable 就有些捉襟见肘了,可以自己继承 Comparator 提供多种标准的比较器进行排序。
说明:线程不同步的时候可以通过,Collections.synchronizedList() 方法来包装一个线程同步方法

在这里插入图片描述
在这里插入图片描述

四、练习写一个SpringMVC框架

1、介绍

熟悉SpringMVC框架的同学一定清楚下面这张图,

在这里插入图片描述

这张图就是 SpringMVC 在处理 http 请求的整个流程中所做的一些事情。

  • 1、用户发送请求至前端控制器DispatcherServlet
  • 2、DispatcherServlet收到请求调用HandlerMapping处理器映射器。
  • 3、处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
  • 4、DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
  • 5、执行处理器(Controller,也叫后端控制器)。
  • 6、Controller执行完成返回ModelAndView
  • 7、HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  • 8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  • 9、ViewReslover解析后返回具体View
  • 10、DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
  • 11、DispatcherServlet响应用户。
    DispatcherServlet 主要承担接收请求、响应结果、转发等作用,剩下的就交给容器来处理!

基于上面的流程,我们可以编写出一款简化版的Spring MVC框架。

2、程序实践

首先上图!
在这里插入图片描述

这个就是我们简易版的Spring MVC框架的实现流程图!

1、首先创建一个DispatcherServlet类,在服务启动的时候,读取要扫描的包路径,然后通过反射将类信息存储到ioc容器,同时通过@Autowired注解,实现自动依赖注入,最后读取@RequestMapping注解中的方法,将映射路径与类的关系存储到映射容器中。

2、当用户发起请求的时候,通过请求路径到映射容器中找到对应的执行类,然后调用具体的方法,发起逻辑处理,最后将处理结果返回给前端用户!

以下是具体实践过程!

2.1、创建扫描注解
因为Spring MVC基本全部都是基于注解开发,因此我们事先也需要创建对应的注解,各个含义与Spring MVC一致!

控制层注解

/**
 * 控制层注解
 * @Controller 
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {

    String value() default "";
}

请求路径注解

/**
 * 请求路径注解
 * @RequestMapping
 */
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {

    String value() default "";
}

参数注解

/**
 * 参数注解
 * @RequestParam
 */
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {

    String value() default "";
}

服务层注解

/**
 * 服务层注解
 * @Controller
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {

    String value() default "";
}

自动装载注解

/**
 * 自动装载注解
 * @Autowrited
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

    String value() default "";
}

2.2、编写 DispatcherServlet 类
DispatcherServlet是一个Servlet类,主要承担的任务是:接受前端用户的请求,然后进行转发,最后响应结果给前端用户!

详细代码如下:

/**
 * servlet跳转层
 */
@WebServlet(name = "DispatcherServlet",urlPatterns = "/*", loadOnStartup = 1, initParams = {@WebInitParam(name="scanPackage", value="com.example.mvc")})
public class DispatcherServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class);

    /**请求方法映射容器*/
    private static List<RequestHandler> handlerMapping = new ArrayList<>();

    /**
     * 服务启动的时候,进行初始化,流程如下:
     * 1、扫描指定包下所有的类
     * 2、通过反射将类实例,放入ioc容器
     * 3、通过Autowired注解,实现自动依赖注入,也就是set类中的属性
     * 4、通过RequestMapping注解,获取需要映射的所有方法,然后将类信息存放到容器中
     * @param config
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        try {
            //1、扫描指定包下所有的类
            String scanPackage = config.getInitParameter("scanPackage");
            //1、扫描指定包下所有的类
            List<String> classNames = doScan(scanPackage);
            //2、初始化所有类实例,放入ioc容器,也就是map对象中
            Map<String, Object> iocMap = doInstance(classNames);
            //3、实现自动依赖注入
            doAutowired(iocMap);
            //5、初始化方法mapping
            initHandleMapping(iocMap);
        } catch (Exception e) {
            logger.error("dispatcher-servlet类初始化失败!",e);
            throw new ServletException(e.getMessage());
        }
    }


    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        doPost(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //跳转
        doDispatch(request, response);
    }

    /**
     * 扫描指定包下的类文件
     * @param packageName
     * @return
     */
    private List<String> doScan(String packageName){
        if(StringUtils.isBlank(packageName)){
            throw new RuntimeException("mvc配置文件中指定扫描包名为空!");
        }
        return PackageHelper.getClassName(packageName);
    }

    private Map<String, Object> doInstance(List<String> classNames) {
        Map<String, Object> iocMap = new HashMap<>();
        if(!CollectionUtils.isNotEmpty(classNames)){
            throw new RuntimeException("获取的类为空!");
        }
        for (String className : classNames) {
            try {
                //通过反射机制构造对象
                Class<?> clazz = Class.forName(className);
                if(clazz.isAnnotationPresent(Controller.class)){
                    //将类名第一个字母小写
                    String baneName = firstLowerCase(clazz.getSimpleName());
                    iocMap.put(baneName, clazz.newInstance());
                }else if(clazz.isAnnotationPresent(Service.class)){
                    //服务层注解判断
                    Service service = clazz.getAnnotation(Service.class);
                    String beanName = service.value();
                    //如果该注解上没有自定义类名,则默认首字母小写
                    if(StringUtils.isBlank(beanName)){
                        beanName = clazz.getName();
                    }
                    Object instance = clazz.newInstance();
                    iocMap.put(beanName, instance);
                    //如果注入的是接口,可以巧妙的用接口的类型作为key
                    Class<?>[] interfaces = clazz.getInterfaces();
                    for (Class<?> clazzInterface : interfaces) {
                        iocMap.put(clazzInterface.getName(), instance);
                    }
                }
            } catch (Exception e) {
                logger.error("初始化mvc-ioc容器失败!",e);
                throw new RuntimeException("初始化mvc-ioc容器失败!");
            }
        }
        return iocMap;
    }

    /**
     * 实现自动依赖注入
     * @throws Exception
     */
    private void doAutowired(Map<String, Object> iocMap) {
        if(!MapUtils.isNotEmpty(iocMap)){
            throw new RuntimeException("初始化实现自动依赖失败,ioc为空!");
        }
        for(Map.Entry<String, Object> entry : iocMap.entrySet()){
            //获取对象下所有的属性
            Field[] fields = entry.getValue().getClass().getDeclaredFields();
            for (Field field : fields) {
                //判断字段上有没有@Autowried注解,有的话才注入
                if(field.isAnnotationPresent(Autowired.class)){
                    try {
                        Autowired autowired = field.getAnnotation(Autowired.class);
                        //获取注解上有没有自定义值
                        String beanName = autowired.value().trim();
                        if(StringUtils.isBlank(beanName)){
                            beanName = field.getType().getName();
                        }
                        //如果想要访问到私有的属性,我们要强制授权
                        field.setAccessible(true);
                        field.set(entry.getValue(), iocMap.get(beanName));
                    } catch (Exception e) {
                        logger.error("初始化实现自动依赖注入失败!",e);
                        throw new RuntimeException("初始化实现自动依赖注入失败");
                    }
                }
            }
        }
    }

    /**
     * 初始化方法mapping
     */
    private void initHandleMapping(Map<String, Object> iocMap){
        if(!MapUtils.isNotEmpty(iocMap)){
            throw new RuntimeException("初始化实现自动依赖失败,ioc为空");
        }
        for(Map.Entry<String, Object> entry:iocMap.entrySet()){
            Class<?> clazz = entry.getValue().getClass();
            //判断是否是controller层
            if(!clazz.isAnnotationPresent(Controller.class)){
                continue;
            }
            String baseUrl = null;
            //判断类有没有requestMapping注解
            if(clazz.isAnnotationPresent(RequestMapping.class)){
                RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
                baseUrl= requestMapping.value();
            }
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                //判断方法上有没有requestMapping
                if(!method.isAnnotationPresent(RequestMapping.class)){
                    continue;
                }
                RequestMapping requestMethodMapping = method.getAnnotation(RequestMapping.class);
                //"/+",表示将多个"/"转换成"/"
                String regex = (baseUrl + requestMethodMapping.value()).replaceAll("/+", "/");
                Pattern pattern = Pattern.compile(regex);
                handlerMapping.add(new RequestHandler(pattern, entry.getValue(), method));
            }
        }
    }

    /**
     * servlet请求跳转
     * @param request
     * @param response
     * @throws IOException
     */
    private void doDispatch(HttpServletRequest request, HttpServletResponse response) throws IOException {
        try {
            request.setCharacterEncoding("UTF-8");
            response.setHeader("Cache-Control", "no-cache");
            response.setHeader("Pragma", "no-cache");
            response.setDateHeader("Expires", -1);
            response.setContentType("text/html");
            response.setHeader("content-type", "text/html;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            RequestHandler handle = getHandleMapping(request);
            if(Objects.isNull(handle)){
                //异常请求地址
                logger.warn("异常请求地址!地址:" + request.getRequestURI());
                response.getWriter().append("error request url");
                return;
            }
            //获取参数列表
            Object[] paramValues = RequestParamHelper.buildRequestParam(handle, request, response);
            Object result = handle.getMethod().invoke(handle.getController(), paramValues);
            if(result != null){
                PrintWriter out = response.getWriter();
                out.println(result);
                out.flush();
                out.close();
            }
        } catch (Exception e) {
            logger.error("接口请求失败!",e);
            PrintWriter out = response.getWriter();
            out.println("请求异常,请稍后再试");
            out.flush();
            out.close();
        }
    }

    /**
     * 将类名第一个字母小写
     * @param clazzName
     * @return
     */
    private String firstLowerCase(String clazzName){
        char[] chars = clazzName.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }


    /**
     * 获取用户请求方法名
     * 与handlerMapping中的路径名进行匹配
     * @param request
     * @return
     */
    private RequestHandler getHandleMapping(HttpServletRequest request){
        if(CollectionUtils.isNotEmpty(handlerMapping)){
            //获取用户请求路径
            String url = request.getRequestURI();
            String contextPath = request.getContextPath();
            String serviceUrl = url.replace(contextPath, "").replaceAll("/+", "/");
            for (RequestHandler handle : handlerMapping) {
                //正则匹配请求方法名
                Matcher matcher = handle.getPattern().matcher(serviceUrl);
                if(matcher.matches()){
                    return handle;
                }
            }
        }
        return null;
    }
}

这里要重点介绍一下初始化阶段所做的操作!

DispatcherServlet在服务启动阶段,会调用init方法进行服务初始化,此阶段所做的事情主要有以下内容:

  • 1、扫描指定包下所有的类信息,返回的结果主要是包名 + 类名
  • 2、通过反射机制,将类进行实例化,将类实例化对象存储到ioc容器中,其中key是类名(小些驼峰),value是类对象
  • 3、通过Autowired注解找到类对象中的属性,通过小驼峰从ioc容器中寻找对应的属性值,然后进行set操作
  • 4、通过Controller和RequestMapping注解寻找需要暴露的方法,并获取对应的映射路径,最后将映射路径
  • 5、最后,当前端用户发起一个请求时,DispatcherServlet获取到请求路径之后,通过与RequestMapping中的路径进行匹配,找到对应的controller类中的方法,然后通过invoke完成方法调用,将调用结果返回给前端!

2.3、编写 controller 类
当DispatcherServlet编写完成之后,紧接着我们需要编写对应的controller控制类来接受前端用户请求,下面我们以用户登录为例,程序示例如下:

编写一个LoginController控制类,接受前端用户调用

@Controller
@RequestMapping("/user")
public class LoginController {

    @Autowired
    private UserService userService;

    /**
     * 用户登录
     * @param request
     * @param response
     * @param userName
     * @param userPwd
     * @return
     */
    @RequestMapping("/login")
    public String login(HttpServletRequest request, HttpServletResponse response,
                        @RequestParam("userName") String userName,
                        @RequestParam("userPwd") String userPwd){
        boolean result = userService.login(userName, userPwd);
        if(result){
            return "登录成功!";
        } else {
            return "登录失败!";
        }
    }
}

编写一个UserService服务类,用于判断账户、密码是否正确

public interface UserService {

    /**
     * 登录
     * @param userName
     * @param userPwd
     * @return
     */
    boolean login(String userName, String userPwd);
}

最后,将项目打包成war,通过tomcat启动服务!

在浏览器中访问http://localhost:8080/user/login?userName=hello&userPwd=123,结果显示如下:
在这里插入图片描述
当我们将userName和userPwd换成正确的数据,访问地址如下:http://localhost:8080/user/login?userName=zhangsan&userPwd=123456
在这里插入图片描述

可以很清晰的看到,服务调用正常!

3、总结

本文主要以Spring MVC框架为背景,手写了一个简易版的Spring MVC框架,虽然功能简陋了一点,但是基本无张俱全,里面讲解了ioc和自动依赖注入的实现过程,还有前端发起一个路径请求,是如何映射到对应的controller类中的方法上!

当然实际的Spring MVC框架的跳转流程比这个复杂很多很多,里面包括各种拦截器、权限安全管理等等。

在这里插入图片描述

五、Java开发者必备10大数据工具和框架

根据外媒的一项调查报告,中软卓越专家列出了Java程序员在过去12个月内一直使用的一些工具或框架,或许会对你有意义。

先来看看大数据的概念。根据维基百科,大数据是庞大或复杂的数据集的广义术语,因此传统的数据处理程序不足以支持如此庞大的体量。

在许多情况下,使用SQL数据库存储/检索数据都是很好的选择。而现如今的很多情况下,它都不再能满足我们的目的,这一切都取决于用例的变化。

现在来讨论一些不同的非SQL存储/处理数据工具,例如,NoSQL数据库,全文搜索引擎,实时流式处理,图形数据库等。

1、MongoDB——最受欢迎的,跨平台的,面向文档的数据库。

MongoDB是一个基于分布式文件存储的数据库,使用C++语言编写。旨在为Web应用提供可扩展的高性能数据存储解决方案。应用性能高低依赖于数据库性能,MongoDB则是非关系数据库中功能最丰富,最像关系数据库的,随着MongDB 3.4版本发布,其应用场景适用能力得到了进一步拓展。

MongoDB的核心优势就是灵活的文档模型、高可用复制集、可扩展分片集群。你可以试着从几大方面了解MongoDB,如实时监控MongoDB工具、内存使用量和页面错误、连接数、数据库操作、复制集等。

2、Elasticsearch ——为云构建的分布式RESTful搜索引擎。

ElasticSearch是基于Lucene的搜索服务器。它提供了分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是比较流行的企业级搜索引擎。

ElasticSearch不仅是一个全文本搜索引擎,还是一个分布式实时文档存储,其中每个field均是被索引的数据且可被搜索;也是一个带实时分析功能的分布式搜索引擎,并且能够扩展至数以百计的服务器存储及处理PB级的数据。ElasticSearch在底层利用Lucene完成其索引功能,因此其许多基本概念源于Lucene。

3、Cassandra——开源分布式数据库管理系统。

最初是由Facebook开发的,旨在处理许多商品服务器上的大量数据,提供高可用性,没有单点故障。

Apache Cassandra是一套开源分布式NoSQL数据库系统。集Google BigTable的数据模型与Amazon Dynamo的完全分布式架构于一身。于2008开源,此后,由于Cassandra良好的可扩展性,被Digg、Twitter等Web 2.0网站所采纳,成为了一种流行的分布式结构化数据存储方案。

因Cassandra是用Java编写的,所以理论上在具有JDK6及以上版本的机器中都可以运行,官方测试的JDK还有OpenJDK 及Sun的JDK。 Cassandra的操作命令,类似于我们平时操作的关系数据库,对于熟悉MySQL的朋友来说,操作会很容易上手。

4、Redis ——开源(BSD许可)内存数据结构存储,用作数据库,缓存和消息代理。

Redis是一个开源的使用ANSI C语言编写的、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。Redis 有三个主要使其有别于其它很多竞争对手的特点:Redis是完全在内存中保存数据的数据库,使用磁盘只是为了持久性目的; Redis相比许多键值数据存储系统有相对丰富的数据类型; Redis可以将数据复制到任意数

5、Hazelcast ——基于Java的开源内存数据网格。

Hazelcast 是一种内存数据网格 in-memory data grid,提供Java程序员关键任务交易和万亿级内存应用。虽然Hazelcast没有所谓的“Master”,但是仍然有一个Leader节点(the oldest member),这个概念与ZooKeeper中的Leader类似,但是实现原理却完全不同。同时,Hazelcast中的数据是分布式的,每一个member持有部分数据和相应的backup数据,这点也与ZooKeeper不同。

Hazelcast的应用便捷性深受开发者喜欢,但如果要投入使用,还需要慎重考虑。

6、Ehcache——广泛使用的开源Java分布式缓存。

主要面向通用缓存、Java EE和轻量级容器。

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是hibernate中默认的CacheProvider。主要特性有:快速简单,具有多种缓存策略;缓存数据有两级,内存和磁盘,因此无需担心容量问题;缓存数据会在虚拟机重启的过程中写入磁盘;可以通过RMI、可插入API等方式进行分布式缓存;具有缓存和缓存管理器的侦听接口;支持多缓存管理器实例,以及一个实例的多个缓存区域;提供Hibernate的缓存实现。

7、Hadoop ——用Java编写的开源软件框架。

用于分布式存储,并对非常大的数据用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群进行高速运算和存储。Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,MapReduce则为海量的数据提供了计算。

8、Solr ——开源企业搜索平台,用Java编写,来自Apache Lucene项目。

Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出查找请求,并得到XML格式的返回结果。

与ElasticSearch一样,同样是基于Lucene,但它对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化。

9、Spark ——Apache Software Foundation中最活跃的项目,是一个开源集群计算框架。

Spark 是一种与 Hadoop 相似的开源集群计算环境,但是两者之间还存在一些不同之处,这些不同之处使 Spark 在某些工作负载方面表现得更加优越,换句话说,Spark 启用了内存分布数据集,除了能够提供交互式查询外,它还可以优化迭代工作负载。

Spark 是在 Scala 语言中实现的,它将 Scala 用作其应用程序框架。与 Hadoop 不同,Spark 和 Scala 能够紧密集成,其中的 Scala 可以像操作本地集合对象一样轻松地

10、Memcached ——通用分布式内存缓存系统。

Memcached是一套分布式快取系统,当初是Danga Interactive为了LiveJournal所发展的,但被许多软件(如MediaWiki)所使用。Memcached作为高速运行的分布式缓存服务器,具有以下的特点:协议简单,基于libevent的事件处理,内置内存存储方式。


http://www.kler.cn/a/324932.html

相关文章:

  • SpringBoot如何集成WebSocket
  • IC 脚本之VIM 记录
  • 【弱监督视频异常检测】2024-ESWA-基于扩散的弱监督视频异常检测常态预训练
  • Day18 Nim游戏
  • FFmpeg源码:avio_read_partial函数分析
  • 在Node.js中如何使用TypeScript
  • 深度学习:残差网络(ResNet)的原理及优缺点
  • OpenCV-图像透视变换
  • Web 3.0 介绍
  • Docker实践与应用举例
  • MPI程序实例:自适应数值积分
  • k8s中,pod生命周期,初始化容器,容器探针,事件处理函数,理解其设计思路及作用
  • 字段映射和数据转换为什么是数据集成的关键?
  • 数据结构:栈 及其应用
  • 汽车总线之---- LIN总线
  • 一文上手SpringSecurity【二】
  • Flink 结合kafka 实现端到端的一致性原理
  • 一文说完c++全部基础知识,IO流(二)
  • 2、Java 基础 - 面向对象基础
  • Qt 信号重载问题--使用lambda表达式--解决方法
  • 国庆节快乐|中国何以成为中国
  • 在Spring项目中使用MD5对数据库加密
  • QT中基于QMatrix4x4与QVector3D的三维坐标变换类实现
  • 理想汽车使用无仪表盘设计的原因和弊端
  • 传统行业选择企业大文件传输系统需要注意哪些?
  • 【C语言刷力扣】2079.给植物浇水