JavaWeb 笔记

1. 配置

web.xml配置Sample

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
<context-param>
<param-name>ContextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>

<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>

Spring MVC配置步骤

1. 新建一个Module,添加Web支持

2. 确定导入了SpringMVC的依赖

3. 配置web.xml, 注册DispatcherServlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 关联一个SpringMVC的配置文件:[servlet-name]-servlet.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 启动级别:1-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- / 表示匹配所有的请求,(不包括.jsp) -->
<!-- * 表示匹配所有的请求,(包括.jsp) -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

4. 编写SpringMVC的配置文件!名称:springmvc-servlet.xml,这里的名称要求是按照官方来的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">


<!-- 处理器映射器 HandlerMapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 处理器适配器 HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
</bean>

<!-- Handler -->
<bean id="/hello" class="cn.geekhall.controller.HelloController"/>

</beans>

5. SpringMVC配置文件中添加处理器映射器

1
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

6. SpringMVC配置文件中添加处理器适配器

1
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

7. SpringMVC配置文件中添加视图解析器

1
2
3
4
5
6
7
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
</bean>

8. 编写我们要去操作业务的Controller,要么实现Controller接口,要么增加注解;需要返回一个ModelAndView,装数据,封视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package cn.geekhall.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloController implements Controller {

public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ModelAndView 视图
ModelAndView mv = new ModelAndView();

// 封装对象,放在ModelAndView中,Model
mv.addObject("msg", "HelloSpringMVC!");

// 封装要跳转的视图,放在ModelAndView。
mv.setViewName("hello"); // : /WEB-INF/jsp/hello.jsp
return mv;
}
}


9. 将自己的类交给SpringIOC容器,注册bean

1
2
<!-- Handler -->
<bean id="/hello" class="cn.geekhall.controller.HelloController"/>

10. 编写要跳转的jsp页面,显示ModelandView存放的数据,以及我们的正常页面

hello.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>

${msg}

</body>
</html>


11. 配置Tomcat启动测试

SpringMVC的执行流程

  1. 解析URL
    • 我们假设请求的url为:http://localhost:8080/SpringMVC/hello
    • 如上url拆分成三部分:
      • localhost:8080 表示服务器域名
      • SpringMVC表示部署在服务器上的web站点
      • hello表示控制器
    • 通过分析,如上URL表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello 控制器。
  2. HandleMapping为处理器映射器,DispatcherServlet调用HandlerMapping,HandlerMapping根据请求URL查找Handler。
  3. HandlerExecution表示具体的Handler,其主要作用是根据URL查找控制器,如上URL被查找控制器为:hello。
  4. HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
  5. HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
  6. Handler让具体的Controller执行。
  7. Controller将具体的执行信息封装在ModelAndView中返回给HandlerAdapter。
  8. HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
  9. DispatcherServlet调用视图解析起(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
  10. 视图解析器将解析的逻辑视图名传给DispatcherServlet。
  11. DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
  12. 最终视图呈现给用户。

注解方式

1
2
3
4
@Component      组件
@Service service
@Controller controller
@Repository dao

改了Java代码 => 重新发布
改了配置文件 => 需要Reload
改了前端页面 => 刷新浏览器即可

方法级别的注解变体有如下几个:组合注解

1
2
3
4
5
6
7
@GetMapping
等价于@RequestMapping(method=RequestMethod.GET)
@PostMapping
等价于@RequestMapping(method=RequestMethod.POST),下同
@PutMapping
@DeleteMapping
@PatchMapping

json

  • JSON字符串转换为JavaScript对象:
1
2
var obj = JSON.parse('{"a": "Hello", "b": "Json"}');

  • JavaScript 对象转换为Json字符串:
1
var json = JSON.stringify({a: 'Hello', b:'Json'});

SpringMVC 处理拦截器

SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理,开发者可以自己定义一些拦截器来实现特定的功能。

  • 过滤器
    • servlet规范中的一部分,任何java web工程都可以使用。
    • 在url-pattern中配置了/* 之后,可以对所有要访问的资源进行拦截。
  • 拦截器
    • 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用。
    • 拦截器只会拦截访问的控制器方法,如果访问的是jsp/html/css/image/js是不会进行拦截的。

拦截器是AOP思想的具体实现。

如何实现拦截器

想要自定义拦截器,必须实现HandlerInterceptor接口。

MyBatis 笔记

1. 配置

获取SqlSessionFactory对象

resources 文件夹下新建mybatis-config.xml配置文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3316/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
<property name="username" value="mybatis"/>
<property name="password" value="yy123456"/>
</dataSource>
</environment>
</environments>
</configuration>

代码中初始化获取SqlSessionFactory对象:

1
2
3
4
5
6
7
8
9
10

try {
// 获取SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}

从SqlSessionFactory中获取SqlSession:

1
2


常见错误

  1. org.apache.ibatis.binding.BindingException: Type interface cn.geekhall.dao.UserMapper is not known to the MapperRegistry.

大多数原因都是应为没有添加mappers或者mapper配置的不对,添加即可:

1
2
3
<mappers>
<mapper class="cn.geekhall.dao.UserMapper"/>
</mappers>

配置解析

核心配置文件:mybatis-config.xml

  • configuration(配置)
  • properties(属性)
  • settings(设置)
  • typeAliases(类型别名)
1
2
3
4
5
6
<!--    类型别名是为Java类型设置一个短的名字,只和XML配置有关,存在的意义仅在于用来减少类完全限定名的冗余-->
<typeAliases>
<typeAlias type="cn.geekhall.pojo.User" alias="User"/>
<!-- 也可以指定一个包名, MyBatis会在包名下面搜索需要的JavaBean。-->
<package name="cn.geekhall.pojo"/>
</typeAliases>

也可以使用注解来定义别名

1
2
@Alias("use")
public class User {}
  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
  • environments(环境配置)
  • environment(环境变量)
  • transactionManager(事务管理器)
  • dataSource(数据源)
  • databaseIdProvider(数据库厂商标识)
  • mappers(映射器)

日志

注意配置文件中的logImpl和STDOUT_LOGGING必须完全正确才可以,否则配置会出错不生效。

1
2
3
4
<!-- mybatis 日志功能  -->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
  • STDOUT_LOGGING : 标准日志工厂实现

使用Log4j

分页

Mybatis默认分页

使用RowBounds实现分页

使用注解开发

1
2
3
4
5
@Select("select * from user")
List<User> getUserList();

@Select("select * from user where id = #{uid}")
User getUserById(@Param("uid") int id);

配置mybatis-config.xml绑定接口

1
2
3
<mappers>
<mapper class="cn.geekhall.dao.UserMapper"/>
</mappers>

@Param() 注解

  • 基本类型的参数或者String类型,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话可以忽略,但是建议都加上
  • SQL中使用的就是@Param中设定的属性名

关于#{} 和 ${}

{} 可以防止SQL注入,${}不可以

Lombok

常用注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass

Lombok config system
Code inspections
Refactoring actions (lombok and delombok)

一对多和多对一

  1. 关联 - association (多对一)
  2. 集合 - collection (一对多)
  3. JavaType & ofType
    • JavaType用来制定实体类中的属性的类型
    • ofType用来指定映射到List或者集合中的pojo的类型,(范型中的约束类型)

动态SQL

使用绑定变量根据不同的条件生成不同的SQL

  • if
1
2
3
4
5
6
7
8
9
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog where 1=1
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
  • where

where 标签只会在至少有一个子元素的条件返回SQL子句的情况下才去插入WHERE子句。例如,上面的if可以不用where 1=1而改写为

1
2
3
4
5
6
7
8
9
10
11
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
  • choose

choose有点类似与java中的switch和case语句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
  • set

set语句会动态包含需要更新的列,而舍去其他的,同时会删除无关的逗号。

1
2
3
4
5
6
7
8
9
10
11
12
<update id="updateBlog" parameterType="map">
update mybatis.blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</set>
where id = #{id}
</update>
  • foreach
1
select * from user where 1=1 and (id=1 or id=2 or id=3)

变成

1
2
3
4
<foreach item="item" index="index" collection="list"
open="(" separator="or" close=")">
#{item}
</foreach>

动态SQL的一个常用操作需求是对一个集合进行遍历,通常是在构建IN条件语句的时候。

1
2
3
4
5
6
7
8
9
<select id="selectPostIn" resultType="domain.blog.Post">
select *
from post p
where id in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
  • sql片段

使用sql标签抽取公共的部分

1
2
3
4
5
6
7
8
<sql id="if-title-author">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>

在需要使用的地方使用include标签引用即可。

1
2
3
4
5
6
<select id="queryBlogIF2" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<include refid="if-title-author"/>
</where>
</select>

MySQL面试高频

  • MySQL引擎
  • InnoDB底层原理
  • 索引
  • 索引优化

缓存

  • 映射语句文件中所有select语句的结果将会被缓存;
  • 映射语句文件中所有insert、update和delete语句将会刷新缓存;
  • 缓存会默认使用最近最少使用算法(LRU,Least Recently Used)算法来清除不需要的缓存。
  • 缓存会不定时进行刷新。
  • 缓存会保存列表或者对象的1024个引用。
  • 一级缓存(本地的会话缓存)默认开启的,只在sqlsession有效。

开启全局缓存:

1
2
3
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>

在需要使用二级缓存的mapper.xml文件中开启,也可以自定义一些参数。

1
2
3
<mapper namespace="sample">
<cache/>
</mapper>

Spring 笔记

IoC本质

控制反转IoC(Inversion of Control) 是一种设计思想,DI(依赖注入)是实现IoC的一种方法。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

Spring 容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从IoC容器中取出需要的对象。

Spring官方配图:

Bean的自动装配

自动装配是Spring满足bean依赖的一种方式!

Spring会在上下文中自动寻找,并自动给bean装配属性!

在Spring中有三种装配的方式:

  1. 在xml中显示的配置
  2. 在java中显示配置
  3. 隐式的自动装配bean【重要】

Spring4之后,如果要使用注解开发,必须要倒入aop的包和context的约束和注解支持。

常用注解

@Autowired

1
2
<!-- 自动装配需要这一行,否则注解@Autowired会报空指针异常。-->
<context:annotation-config/>

@Nullable

标记了字段可以为null,例如:

1
2
3
public Person(@Nullable String name) {
this.name = name;
}

@Qualifier

可以使用Qualifier注解来指定自动装配的bean。

1
2
3
4
5
6
7
@Autowired
@Qualifier(value = "cat222")
private Cat cat;
@Autowired
@Qualifier(value = "dog111")
private Dog dog;

@Resource

也可以使用java原生的@Resource注解,先通过名字进行自动绑定,再通过类型进行自动绑定

1
2
3
4
5
@Resource(name = "cat111")
private Cat cat;

@Resource
private Dog dog;

@Resource 和 @Autowired 的区别

  • 都是用来自动装配的,都可以放在属性字段;
  • @Autowired通过bytype方式实现,而且必须要求对象存在,否则报空指针;
  • @Resource默认通过byname方式实现,如果找不到名字,则通过bytype实现!如果两个都找不到的情况下,就报错!【常用】
  • 执行顺序不同:@Autowired通过byType方式实现。

@Component

组件,放在类上,说明这个类被Spring管理了,就是bean!

1
2
3
4
@Component
public class User {
private String name;
}

Component 还有一些衍生的注解 :

  • @Repository:一般用于Dao层
  • @Service:一般用于service层
  • @Controller:一般用于Controller层
    上面三个注解与Component的左右基本相同,都是代表把某个类装配到Spring中。

@Value

用于属性注入的方法

@Scope

作用域。等价于配置文件中的scope

@Configuration

java类的方式配置Spring

XML与注解

  • XML:更加万能,适用于任何场合,维护方便简单。
  • 注解:不是自己的类使用补了,维护相对复杂。

最佳实践:

  • xml用来管理bean
  • 注解只负责完成属性的注入;

使用Java的方式配置Spring

JavaConfig是Spring的一个子项目,可以完全不适用Spring的xml配置。

AOP

  • 横切关注点:跨越应用程序多个模块的方法或者功能。即,与我们业务逻辑无关的,但是我们都需要关注的部分,如:日志、缓存、安全、事务等等。
  • 切面(Aspect):横切关注点被模块化的特殊对象。即,它是一个类。
  • 通知(Advice):切面必须要完成的工作。即:类中的方法。
  • 目标(Target):被通知的对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知执行的“地点”的定义。
  • 连接点(JointPoint):与切入点匹配的执行点。

需要倒入aspectj依赖包

1
2
3
4
5
6
<!-- 使用Spring的AOP需要倒入下面的依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
  • 方式一:使用Spring的API接口,【主要SpringAPI接口实现】
1
2
3
4
5
6
7
8
9
10
11
12
13
<aop:config>
<!--
切入点 :
expression:表达式;
execution(要执行的位置! * * * * *)
-->
<aop:pointcut id="pointcut" expression="execution(* cn.geekhall.service.UserServiceImpl.*(..))"/>

<!-- 执行环绕增加 -->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>

  • 方式二:自定义类实现AOP 【主要是切面定义】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
      <bean id="diy" class="cn.geekhall.diy.DiyPointCut"/>
<aop:config>
<!-- 自定义切面 , ref: 要引用的类 -->
<aop:aspect ref="diy">
<!--
切入点
第一个*号: 表示返回类型, *号表示所有的类型。
包名:表示需要拦截的包名,后面的两个据点表示当前包的所有子包,子孙包下所有类的方法。
第二个*号:表示类名:*号表示所有的类
*.(..): 表示方法名,*号表示所有的方法,后面括号里面表示方法的参数,两个点表示任何参数。
-->
<aop:pointcut id="point" expression="execution(* cn.geekhall.service.UserServiceImpl.*(..))"/>
<!-- 通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>

</aop:aspect>
</aop:config>
  • 方式三:使用注解实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Aspect   // 标注这个类是一个切面
public class AnnotationPointCut {

@Before("execution(* cn.geekhall.service.*.*(..))")
public void before(){
System.out.println("++++++++++++++++++ 方法执行前 ++++++++++++++++++");
}

@After("execution(* cn.geekhall.service.*.*(..))")
public void after(){
System.out.println("++++++++++++++++++ 方法执行后 ++++++++++++++++++");
}

// 在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点。
@Around("execution(* cn.geekhall.service.*.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("++++++++++++++++++ before around ++++++++++++++++++");

Signature signature = joinPoint.getSignature();
System.out.println(signature);
Object proceed = joinPoint.proceed();

System.out.println("++++++++++++++++++ after around ++++++++++++++++++");
}
}

1
2
3
4
5
6
7
8
<!--    方式三: 使用注解-->
<bean id="diy" class="cn.geekhall.diy.AnnotationPointCut"/>
<!--
开启AOP注解支持
proxy-target-class="false" 表示使用JDK实现,true表示使用cglib实现,默认为false。
-->
<aop:aspectj-autoproxy proxy-target-class="false"/>
<!-- <aop:aspectj-autoproxy/>-->

整合Mybatis

步骤:

  1. 导入相关jar包

    • junit
    • mybatis
    • mysql
    • spring
    • aop
    • mybatis-spring
  2. 编写配置文件

  3. 测试

MyBatis-Spring

什么是MyBatis-Spring

MyBatis-Spring会帮助你将MyBatis代码无缝地整合到Spring中,它将允许MyBatis参与到Spring的事务管理中,创建映射器Mapper和SqlSession并注入到Bean中,以及将MyBatis的异常转换为Spring的DataAccessException,最终,可以做到应用代码不依赖MyBatis,Spring或者MyBatis-Spring。

官方

步骤

  1. Model类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class User {
private String id;
private String name;
private String pwd;

@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
  1. 编写数据源配置

使用Spring-jdbc配置数据源:

1
2
3
4
5
6
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3316/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
<property name="username" value="mybatis"/>
<property name="password" value="yy123456"/>
</bean>

也可以使用DBCP连接池等其他方法配置:

1
2
3
4
5
6
7
8
9
10
11
<bean id="dataSourceDbcp" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close" scope="singleton">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3316/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
<property name="username" value="mybatis"/>
<property name="password" value="yy123456"/>
<property name="initialSize" value="5"/>
<property name="maxTotal" value="80"/>
<property name="maxIdle" value="50"/>
<property name="minIdle" value="45"/>
<property name="maxWaitMillis" value="7000"/>
</bean>
  1. sqlSessionFactory
1
2
3
4
5
6
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 绑定Mybatis配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:cn/geekhall/mapper/UserMapper.xml"/>
</bean>

UserMapper.xml:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.geekhall.mapper.UserMapper">

<select id="getUsers" resultType="user">
select * from mybatis.user
</select>

</mapper>
  1. sqlSessionTemplate

SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSession。 SqlSessionTemplate 是线程安全的,可以被多个 DAO 或映射器所共享使用。

当调用 SQL 方法时(包括由 getMapper() 方法返回的映射器中的方法),SqlSessionTemplate 将会保证使用的 SqlSession 与当前 Spring 的事务相关。 此外,它管理 session 的生命周期,包含必要的关闭、提交或回滚操作。另外,它也负责将 MyBatis 的异常翻译成 Spring 中的 DataAccessExceptions。

由于模板可以参与到 Spring 的事务管理中,并且由于其是线程安全的,可以供多个映射器类使用,你应该总是用 SqlSessionTemplate 来替换 MyBatis 默认的 DefaultSqlSession 实现。在同一应用程序中的不同类之间混杂使用可能会引起数据一致性的问题。

1
2
3
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
  1. 需要给接口加实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

public interface UserMapper {
List<User> getUsers();
}

public class UserMapperImpl implements UserMapper {

// 我们的所有操作,都使用sqlSession来执行,在原来,现在都使用SqlSessionTemplate。
private SqlSessionTemplate sqlSession;

public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}

public List<User> getUsers() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.getUsers();
}
}

  1. 将自己写的实现类,注入到Spring中
1
2
3
<bean id="userMapper" class="cn.geekhall.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>

也可以使UserMapperImpl 类继承SqlSessionDaoSupport类来实现:

1
2
3
4
5
6
7
8
9
10
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {

public List<User> getUsers() {
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.getUsers();
}
}


  1. 测试使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class AppTest {

@Test
public void test() throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
List<User> users = userMapper.getUsers();

for (User user : users) {
System.out.println(user);
}


// 继承SqlSessionDaoSupport类的测试代码
UserMapper userMapper2 = context.getBean("userMapper2", UserMapper.class);
List<User> users2 = userMapper2.getUsers();

for (User user : users2) {
System.out.println(user);
}
}
}


回顾事务

  • 把一组业务当成一个业务来做,要么都成功,要么都失败。
  • 事务在项目开发中,十分的重要,涉及到数据一致性的问题,不能马虎。
  • 确保ACID::原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)

Spring中的事务管理分为两种:

  • 声明式事物:AOP方式,交给容器去管理事务;
  • 编程式事物:需要在代码中手工进行事务管理;
1
2
3
4
5
6
7
TransactionStatus txStatus = TransactionManager.getTransaction(new DefaultTransactionDefinition());
try {
userMapper.insertUser(user);
} catch (Exception e){
transactionManager.rollback(txStatus);
throw e;
}

Propagation

在声明式的事务处理中,要配置一个切面,其中就用到了propagation,表示打算对这些方法怎么使用事务,是用还是不用,其中propagation有七种配置,REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。默认是REQUIRED。

  • REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。

  • MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。

  • REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。

  • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

  • NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

  • NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。

React 笔记

脚手架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 安装
npm install -g create-react-app

# 创建React脚手架工程
create-react-app react_test

# 开启服务器
yarn start

# 前端生成静态文件
yarn build

#
yarn test

#
yarn eject

React 生成的文件

1
2
3
4
5
6
7
8
App.css
App.test.js
index.js
reportWebVitals.js
App.js
index.css
logo.svg
setupTests.js

Nacos教程

Nacos简介


Nacos 是阿里巴巴团队开源的一款动态服务发现、配置和管理平台。
项目源码地址:https://github.com/alibaba/nacos

三大注册中心对比:

名称 配置中心 注册中心 依赖 访问协议 版本迭代 集成支持 上手程度
Eureka 不支持 支持 不依赖其他组件 HTTP 无版本升级 SpringCloud集成 容易,英文界面
Consul 支持 支持 不依赖其他组件 HTTP/DNS 版本迭代中 SpringCloud、K8S 容易,英文界面
Nacos 支持 支持 不依赖其他组件 HTTP/动态DNS/UDP 版本迭代中 Dubbo、SpringCloud、K8S 容易、中文社区文档

主要特性
特性:

  • 服务发现:支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用 原生SDK、OpenAPI、或一个独立的 Agent TODO 注册 Service 后,服务消费者可以使用 DNS TODO 或 HTTP&API 查找和发现服务。
  • 服务健康监测:提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。
  • 动态配置服务:动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。
  • 动态 DNS 服务:动态 DNS 服务支持权重路由,使用者更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。
  • 服务及其元数据管理:Nacos 能让使用者从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。

Nacos的安装

可以通过源码和发行包两种方式来安装Nacos

方式一:源码安装

1
2
3
4
5
6
7
git clone https://github.com/alibaba/nacos.git
cd nacos/
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
ls -al distribution/target/

// change the $version to your actual path
cd distribution/target/nacos-server-$version/nacos/bin

方式二:下载编译后的压缩包

1
2
unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
cd nacos/bin

服务启动停止

Linux/Unix/Mac:

1
2
3
4
5
6
cd nacos/bin
# 启动:standalone代表单机非集群模式运行
sh startup.sh -m standalone

# 停止
sh shutdown.sh

Windows:

1
2
3
4
5
6
cd nacos/bin
# standalone代表单机非集群模式运行
startup.cmd -m standalone

# 停止
shutdown.cmd

服务启动后可以通过 : http://localhost:8848/nacos/ 来访问,默认账号密码: nacos nacos

服务配置

1
2
3
4
5
6
7
8
9
10
11
# 服务注册
curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'

# 服务发现
curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName'

# 发布配置
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"

# 获取配置
curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"

Nacos 服务注册实例

启动Nacos server,到控制台添加一个命名空间

服务注册:分别注册两个服务,服务1有两个实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package cn.geekhall.main;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;

import java.io.IOException;
import java.util.List;
import java.util.Properties;

/**
* ServerResigter.java
*
* @author yiny
*/
public class ServerResigter {
public static void main(String[] args) throws NacosException, IOException {
Properties properties = new Properties();
properties.setProperty("serverAddr", "http://localhost:8848");
// 这里使用服务控制台里的命名空间ID。
properties.setProperty("namespace", "42b7fa25-199f-4ba6-b683-b67edcb07526");
NamingService namingService = NacosFactory.createNamingService(properties);

// 同一个服务注册两个实例
namingService.registerInstance("serverProvider_1", "127.0.0.1", 8881);
namingService.registerInstance("serverProvider_2", "127.0.0.1", 8882);
namingService.registerInstance("serverProvider_2", "127.0.0.1", 8883);

// 获取服务名为serverProvider_1 的实例信息
List<Instance> serverProvider = namingService.getAllInstances("serverProvider_1");
System.out.println(JSONArray.toJSONString(serverProvider, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat));
System.in.read();

}
}

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
nacos-config-spring-boot-autoconfigure-0.2.7.jar:/Users/yiny/.m2/repository/com/alibaba/boot/nacos-spring-boot-base/0.2.7/nacos-spring-boot-base-0.2.7.jar cn.geekhall.main.ServerResigter
[
{
"clusterName":"DEFAULT",
"enabled":true,
"ephemeral":true,
"healthy":true,
"instanceHeartBeatInterval":5000,
"instanceHeartBeatTimeOut":15000,
"instanceId":"127.0.0.1#8881#DEFAULT#DEFAULT_GROUP@@serverProvider_1",
"instanceIdGenerator":"simple",
"ip":"127.0.0.1",
"ipDeleteTimeout":30000,
"metadata":{},
"port":8881,
"serviceName":"DEFAULT_GROUP@@serverProvider_1",
"weight":1.0
}
]

执行后可以在Nacos控制台看到服务注册结果:

服务订阅:获取所有服务提供者,然后进行订阅,并添加一个事件用于监听订阅成功后的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package cn.geekhall.main;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;

import javax.naming.event.NamingEvent;
import java.io.IOException;
import java.util.List;
import java.util.Properties;

/**
* ServerCustomer.java
*
* @author yiny
*/
public class ServerCustomer {
public static void main(String[] args) throws NacosException, IOException {
Properties properties = new Properties();
properties.setProperty("serverAddr", "http://localhost:8848");
properties.setProperty("namespace", "42b7fa25-199f-4ba6-b683-b67edcb07526");
NamingService namingService = NacosFactory.createNamingService(properties);
List<String> serverList = namingService.getServicesOfServer(1, Integer.MAX_VALUE).getData();
System.out.println("得到服务提供者列表:" + JSONArray.toJSONString(serverList));
for (String server : serverList){

// 订阅serverProvider服务 并添加一个监听器用来监听服务状态
namingService.subscribe(server, new EventListener() {
public void onEvent(Event event) {
NamingEvent namingEvent = (NamingEvent) event;
System.out.println(JSONObject.toJSONString(namingEvent, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat));
}
});
}
System.in.read();

}
}

执行结果:

1
2
3
nacos-config-spring-boot-autoconfigure-0.2.7.jar:/Users/yiny/.m2/repository/com/alibaba/boot/nacos-spring-boot-base/0.2.7/nacos-spring-boot-base-0.2.7.jar cn.geekhall.main.ServerCustomer
得到服务提供者列表:["serverProvider_1","serverProvider_2"]

服务停止后:

Nacos SpringBoot

新建一个SpringBoot项目:

并添加依赖。

1
2
3
4
5
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-config-spring-boot-starter</artifactId>
<version>0.2.7</version>
</dependency>

ZooKeeper教程

Zookeeper简介

ZooKeeper 是 Apache 软件基金会的一个软件项目,它为大型分布式计算提供开源的分布式配置服务、同步服务和命名注册。

ZooKeeper 的架构通过冗余服务实现高可用性。

简单来说zookeeper=文件系统的数据模型结构+监听通知机制(Watch)

Zookeeper的数据模型结构很像数据结构当中的树,也很像文件系统中的目录。

树是由所有节点组成,Zookeeper的数据存储也同样是基于节点,这种节点叫做Znode

但是,不同于树的节点,Znode的引用方式是路径引用,类似于文件系统,通过路径进行访问数据,而redis是根据key值来访问数据

Zookeeper的安装

官网地址-> Zookeeper

安装、启动命令:

1
2
3
4
5
6
tar xvf apache-zookeeper-3.7.0-bin.tar.gz
cd apache-zookeeper-3.7.0-bin
cd conf
cp zoo_sample.cfg zoo.cfg
cd ../bin
sh zkServer.sh start

执行后,服务启动成功

查看服务状态

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/tmp/zookeeper
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60

默认端口号是2181

zookeeper 数据结构

zookkeeper 提供的名称空间非常类似于标准文件系统,整体结构类似于 linux 文件系统的模式以树形结构存储。其中根路径以 / 开头。所有存储的数据是由 znode 组成的,节点也称为 znode,并以 key/value 形式存储数据。
zookeeper 名称空间中的每个节点都是由一个路径标识.

进入 zookeeper 安装的 bin 目录,通过sh zkCli.sh打开命令行终端,执行 “ls /“ 命令显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
./zkCli.sh
# 查看节点
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]

# 创建节点/yiny并赋值 123,创建节点时,必须要带上全路径
[zk: localhost:2181(CONNECTED) 1] create -e /yiny 123
Created /yiny

# 再次查看节点,确认除了zookeeper节点以外新增了yiny节点
[zk: localhost:2181(CONNECTED) 2] ls /
[yiny, zookeeper]

# 查看/zookeeper节点的内容
[zk: localhost:2181(CONNECTED) 4] ls /zookeeper
[config, quota]

# 使用get命令获取节点存储的数据
[zk: localhost:2181(CONNECTED) 5] get /yiny
123

# 使用set命令修改节点存储的数据
[zk: localhost:2181(CONNECTED) 6] set /yiny abc
[zk: localhost:2181(CONNECTED) 7] get /yiny
abc

# 使用delete命令删除节点
[zk: localhost:2181(CONNECTED) 8] delete /yiny
[zk: localhost:2181(CONNECTED) 9] ls /yiny
Node does not exist: /yiny

ZooKeeper的基本操作

命令 功能
create 创建节点
delete 删除节点
exists 判断节点是否存在
getData 获得一个节点的数据
setData 设置一个节点的数据
getChildren 获取节点下的所有节点

Dubbo教程

Dubbo-admin简介

Dubbo-admin是Dubbo RPC框架的“管理端”,可以对注册的服务(provider)和服务调用方(comsumer)进行服务治理,包括路由、监控、配置等功能;

Dubbo一般都是使用zookeeper来进行管理服务注册,而dubbo-admin查看哪些注册了哪些服务,也是需要从zk上查询的,所以Dubbo-admin需要依赖于zookeeper;

另外,Dubbo-admin是一个web项目(spring-boot),提供了管理端页面,页面是使用vue框架,所以需要安装node环境;

对于zookeeper和node的相关安装配置,这里就不在阐述。

Dubbo-admin项目

github地址:https://github.com/apache/dubbo-admin

在项目目录下打包dubbo-admin

1
mvn clean package -Dmaven.test.skip=true

这是一个SpringBoot项目,也可以导入到IDEA中,双击Maven面板中的package按钮来进行构建。
构建之后的结果文件生成在:project-dir/dubbo-admin-distribution/target/dubbo-admin-0.3.0-SNAPSHOT.jar

运行

运行Dubbo-Admin前需要先启动ZooKeeper:

1
2
# 启动ZooKeeper
/Users/yiny/soft/apache-zookeeper-3.7.0-bin/bin/zkServer.sh start

这里需要注意的是,需要修改ZooKeeper使用的默认端口,否则在启动Dubbo-admin的时候会出现端口被占用的情况。修改方法为修改zoo.cfg,在最后添加:

1
admin.serverPort=38080

然后再次使用lsof -i tcp:38080来查看端口占用情况。

1
2
3
# 启动Dubbo-Admin
# java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/bin/java -jar /Users/yiny/Sites/dubbo-admin/dubbo-admin-distribution/target/dubbo-admin-0.3.0-SNAPSHOT.jar

然后使用浏览器访问:http://localhost:8080
用户名密码都是root/root
即可看到Dubbo-Admin界面了。

使用Docker搭建Dubbo-Admin环境

1
docker pull apache/dubbo-admin:latest

微服务两种架构方案的比较

  • Spring Boot + Spring Cloud 组件多,功能完备, Http通讯,俗称SpringCloud全家桶 ->微服务架构解决方案一

  • Spring Boot+Dubbo+Zookeeper 组件少,功能非完备 Alibaba Dubbo ->RPC通讯框架 ->微服务架构解决方案二

微服务架构是一种思想,实现方案是分布式系统,分布式系统最大的问题 -> 网络是不可靠的。

什么是分布式锁

Zookeeper 分布式协调服务: 解决分布式系统当中多个进程之间的同步控制,让他们有序的访问某种临界资源,防止造成脏数据的后果。

为了防止分布式系统中的多个进程之间相互干扰,用分布式协调技术对这种进程进行调度,而分布式协调技术的核心就是分布式锁

分布式锁: 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行。

Dubbo-Admin + ZooKeeper 服务注册与发现配置

  1. 新建dubbo-zk-api的Maven项目
1
2
3
4
5
6
7
8
9
@Component
public interface TicketService {
String getTicket();
}

@Component
public interface UserService {
String sayHi();
}
  1. 新建provider的SpringBoot服务项目,并导入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!-- 导入依赖 Dubbo + ZooKeeper -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>

<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>

<!-- 排除这个slf4j-log4j12 -->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.geekhall</groupId>
<artifactId>dubbo-zk-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

properties配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 端口
server.port=8001

# 服务应用名字
dubbo.application.name=dubbo-zk-provider

# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

# 哪些服务要被注册
dubbo.scan.base-packages=cn.geekhall.service

dubbo.application.protocol=dubbo

新建服务接口实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package cn.geekhall.service;

import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;

@Service //这里的Service注解是Dubbo的,可以被扫描到,在项目一启动就自动注册到注册中心
@Component
public class TicketServiceImpl implements TicketService {
@Override
public String getTicket() {
return "极客堂";
}
}

@Service
@Component
public class UserServiceImpl implements UserService {
@Override
public String sayHi() {
return "Hi geek!";
}
}

启动服务后,在Dubbo-admin后台即可看到服务:

  1. 新建Consumer的SpringBoot服务项目,并导入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!-- 导入依赖 Dubbo + ZooKeeper -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>

<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>

<!-- 排除这个slf4j-log4j12 -->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.geekhall</groupId>
<artifactId>dubbo-zk-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

application.properties配置:

1
2
3
4
5
6
7
8
# 服务端口
server.port=8002

# 消费者去哪里拿服务需要暴露自己的名字
dubbo.application.name=dubbo-zk-consumer

# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

Customer代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package cn.geekhall.service;

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

@Service // 这里的Service是Spring的,放到容器中即可
public class UserService {

// 想拿到provider提供的票,要去注册中心拿到服务
@Reference(timeout = 30000) // 引用 , Pom坐标,可以定义路径相同的接口名
TicketService ticketService;

public void buyTicket(){
String ticket = ticketService.getTicket();
System.out.println("在注册中心拿到 ====> " + ticket);
}
}

运行Consumer,得到运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2021-08-08 14:22:05.029  INFO 54035 --- [           main] c.g.DubboZkConsumerApplicationTests      : Starting DubboZkConsumerApplicationTests using Java 1.8.0_251 on MacBook-Pro with PID 54035 (started by yiny in /Users/yiny/Sites/java_demo/dubbo-zk-consumer)
2021-08-08 14:22:05.052 INFO 54035 --- [ main] c.g.DubboZkConsumerApplicationTests : No active profile set, falling back to default profiles: default
2021-08-08 14:22:05.440 INFO 54035 --- [ main] .a.d.c.s.c.a.DubboConfigBindingRegistrar : The dubbo config bean definition [name : org.apache.dubbo.config.ApplicationConfig#0, class : org.apache.dubbo.config.ApplicationConfig] has been registered.
2021-08-08 14:22:05.441 INFO 54035 --- [ main] .a.d.c.s.c.a.DubboConfigBindingRegistrar : The BeanPostProcessor bean definition [org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor] for dubbo config bean [name : org.apache.dubbo.config.ApplicationConfig#0] has been registered.
2021-08-08 14:22:05.441 INFO 54035 --- [ main] .a.d.c.s.c.a.DubboConfigBindingRegistrar : The dubbo config bean definition [name : org.apache.dubbo.config.RegistryConfig#0, class : org.apache.dubbo.config.RegistryConfig] has been registered.
2021-08-08 14:22:05.441 INFO 54035 --- [ main] .a.d.c.s.c.a.DubboConfigBindingRegistrar : The BeanPostProcessor bean definition [org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor] for dubbo config bean [name : org.apache.dubbo.config.RegistryConfig#0] has been registered.
2021-08-08 14:22:05.622 INFO 54035 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration' of type [org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration$$EnhancerBySpringCGLIB$$8b980fda] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-08 14:22:05.727 INFO 54035 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration' of type [org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration$$EnhancerBySpringCGLIB$$1c5234aa] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-08 14:22:05.748 INFO 54035 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'relaxedDubboConfigBinder' of type [org.apache.dubbo.spring.boot.autoconfigure.BinderDubboConfigBinder] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-08 14:22:05.763 INFO 54035 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'relaxedDubboConfigBinder' of type [org.apache.dubbo.spring.boot.autoconfigure.BinderDubboConfigBinder] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-08 14:22:06.026 INFO 54035 --- [ main] .f.a.DubboConfigBindingBeanPostProcessor : The properties of bean [name : org.apache.dubbo.config.ApplicationConfig#0] have been binding by prefix of configuration properties : dubbo.application
2021-08-08 14:22:06.034 INFO 54035 --- [ main] .f.a.DubboConfigBindingBeanPostProcessor : The properties of bean [name : org.apache.dubbo.config.RegistryConfig#0] have been binding by prefix of configuration properties : dubbo.registry
2021-08-08 14:22:06.035 INFO 54035 --- [ main] o.a.d.c.s.b.f.a.ReferenceBeanBuilder : The configBean[type:ReferenceBean] has been built.
2021-08-08 14:22:06.137 INFO 54035 --- [ main] o.a.c.f.imps.CuratorFrameworkImpl : Starting
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:zookeeper.version=3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:host.name=macbook-pro
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.version=1.8.0_251
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.vendor=Oracle Corporation
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.class.path=/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar:/Applications/IntelliJ IDEA.app/Contents/plugins/junit/lib/junit-rt.jar:/Applications/IntelliJ IDEA.app/Contents/plugins/junit/lib/junit5-rt.jar:/Users/yiny/.m2/repository/org/junit/platform/junit-platform-launcher/1.7.2/junit-platform-launcher-1.7.2.jar:/Users/yiny/.m2/repository/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.jar:/Users/yiny/.m2/repository/org/junit/platform/junit-platform-engine/1.7.2/junit-platform-engine-1.7.2.jar:/Users/yiny/.m2/repository/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar:/Users/yiny/.m2/repository/org/junit/platform/junit-platform-commons/1.7.2/junit-platform-commons-1.7.2.jar:/Users/yiny/.m2/repository/org/junit/vintage/junit-vintage-engine/5.7.2/junit-vintage-engine-5.7.2.jar:/Users/yiny/.m2/repository/junit/junit/4.13/junit-4.13.jar:/Users/yiny/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/tools.jar:/Users/yiny/Sites/java_demo/dubbo-zk-consumer/target/test-classes:/Users/yiny/Sites/java_demo/dubbo-zk-consumer/target/classes:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter-web/2.5.3/spring-boot-starter-web-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter/2.5.3/spring-boot-starter-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot/2.5.3/spring-boot-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.5.3/spring-boot-autoconfigure-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.5.3/spring-boot-starter-logging-2.5.3.jar:/Users/yiny/.m2/repository/ch/qos/logback/logback-classic/1.2.4/logback-classic-1.2.4.jar:/Users/yiny/.m2/repository/ch/qos/logback/logback-core/1.2.4/logback-core-1.2.4.jar:/Users/yiny/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.14.1/log4j-to-slf4j-2.14.1.jar:/Users/yiny/.m2/repository/org/apache/logging/log4j/log4j-api/2.14.1/log4j-api-2.14.1.jar:/Users/yiny/.m2/repository/org/slf4j/jul-to-slf4j/1.7.32/jul-to-slf4j-1.7.32.jar:/Users/yiny/.m2/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar:/Users/yiny/.m2/repository/org/yaml/snakeyaml/1.28/snakeyaml-1.28.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.5.3/spring-boot-starter-json-2.5.3.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.12.4/jackson-databind-2.12.4.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.12.4/jackson-annotations-2.12.4.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.12.4/jackson-core-2.12.4.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.12.4/jackson-datatype-jdk8-2.12.4.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.12.4/jackson-datatype-jsr310-2.12.4.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.12.4/jackson-module-parameter-names-2.12.4.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/2.5.3/spring-boot-starter-tomcat-2.5.3.jar:/Users/yiny/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.50/tomcat-embed-core-9.0.50.jar:/Users/yiny/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/9.0.50/tomcat-embed-el-9.0.50.jar:/Users/yiny/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.50/tomcat-embed-websocket-9.0.50.jar:/Users/yiny/.m2/repository/org/springframework/spring-web/5.3.9/spring-web-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-beans/5.3.9/spring-beans-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-webmvc/5.3.9/spring-webmvc-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-aop/5.3.9/spring-aop-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-context/5.3.9/spring-context-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-expression/5.3.9/spring-expression-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter-test/2.5.3/spring-boot-starter-test-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-test/2.5.3/spring-boot-test-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-test-autoconfigure/2.5.3/spring-boot-test-autoconfigure-2.5.3.jar:/Users/yiny/.m2/repository/com/jayway/jsonpath/json-path/2.5.0/json-path-2.5.0.jar:/Users/yiny/.m2/repository/net/minidev/json-smart/2.4.7/json-smart-2.4.7.jar:/Users/yiny/.m2/repository/net/minidev/accessors-smart/2.4.7/accessors-smart-2.4.7.jar:/Users/yiny/.m2/repository/org/ow2/asm/asm/9.1/asm-9.1.jar:/Users/yiny/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/2.3.3/jakarta.xml.bind-api-2.3.3.jar:/Users/yiny/.m2/repository/jakarta/activation/jakarta.activation-api/1.2.2/jakarta.activation-api-1.2.2.jar:/Users/yiny/.m2/repository/org/assertj/assertj-core/3.19.0/assertj-core-3.19.0.jar:/Users/yiny/.m2/repository/org/hamcrest/hamcrest/2.2/hamcrest-2.2.jar:/Users/yiny/.m2/repository/org/junit/jupiter/junit-jupiter/5.7.2/junit-jupiter-5.7.2.jar:/Users/yiny/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.7.2/junit-jupiter-api-5.7.2.jar:/Users/yiny/.m2/repository/org/junit/jupiter/junit-jupiter-params/5.7.2/junit-jupiter-params-5.7.2.jar:/Users/yiny/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.7.2/junit-jupiter-engine-5.7.2.jar:/Users/yiny/.m2/repository/org/mockito/mockito-core/3.9.0/mockito-core-3.9.0.jar:/Users/yiny/.m2/repository/net/bytebuddy/byte-buddy/1.10.22/byte-buddy-1.10.22.jar:/Users/yiny/.m2/repository/net/bytebuddy/byte-buddy-agent/1.10.22/byte-buddy-agent-1.10.22.jar:/Users/yiny/.m2/repository/org/objenesis/objenesis/3.2/objenesis-3.2.jar:/Users/yiny/.m2/repository/org/mockito/mockito-junit-jupiter/3.9.0/mockito-junit-jupiter-3.9.0.jar:/Users/yiny/.m2/repository/org/skyscreamer/jsonassert/1.5.0/jsonassert-1.5.0.jar:/Users/yiny/.m2/repository/com/vaadin/external/google/android-json/0.0.20131108.vaadin1/android-json-0.0.20131108.vaadin1.jar:/Users/yiny/.m2/repository/org/springframework/spring-core/5.3.9/spring-core-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-jcl/5.3.9/spring-jcl-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-test/5.3.9/spring-test-5.3.9.jar:/Users/yiny/.m2/repository/org/xmlunit/xmlunit-core/2.8.2/xmlunit-core-2.8.2.jar:/Users/yiny/.m2/repository/org/apache/dubbo/dubbo-spring-boot-starter/2.7.3/dubbo-spring-boot-starter-2.7.3.jar:/Users/yiny/.m2/repository/org/apache/dubbo/dubbo-spring-boot-autoconfigure/2.7.3/dubbo-spring-boot-autoconfigure-2.7.3.jar:/Users/yiny/.m2/repository/org/apache/dubbo/dubbo-spring-boot-autoconfigure-compatible/2.7.3/dubbo-spring-boot-autoconfigure-compatible-2.7.3.jar:/Users/yiny/.m2/repository/org/apache/dubbo/dubbo/2.7.3/dubbo-2.7.3.jar:/Users/yiny/.m2/repository/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar:/Users/yiny/.m2/repository/io/netty/netty-all/4.1.66.Final/netty-all-4.1.66.Final.jar:/Users/yiny/.m2/repository/com/google/code/gson/gson/2.8.7/gson-2.8.7.jar:/Users/yiny/.m2/repository/com/github/sgroschupf/zkclient/0.1/zkclient-0.1.jar:/Users/yiny/.m2/repository/log4j/log4j/1.2.14/log4j-1.2.14.jar:/Users/yiny/.m2/repository/org/apache/curator/curator-framework/2.12.0/curator-framework-2.12.0.jar:/Users/yiny/.m2/repository/org/apache/curator/curator-client/2.12.0/curator-client-2.12.0.jar:/Users/yiny/.m2/repository/com/google/guava/guava/16.0.1/guava-16.0.1.jar:/Users/yiny/.m2/repository/org/apache/curator/curator-recipes/2.12.0/curator-recipes-2.12.0.jar:/Users/yiny/.m2/repository/org/apache/zookeeper/zookeeper/3.4.14/zookeeper-3.4.14.jar:/Users/yiny/.m2/repository/org/slf4j/slf4j-api/1.7.32/slf4j-api-1.7.32.jar:/Users/yiny/.m2/repository/com/github/spotbugs/spotbugs-annotations/3.1.9/spotbugs-annotations-3.1.9.jar:/Users/yiny/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar:/Users/yiny/.m2/repository/jline/jline/0.9.94/jline-0.9.94.jar:/Users/yiny/.m2/repository/org/apache/yetus/audience-annotations/0.5.0/audience-annotations-0.5.0.jar:/Users/yiny/.m2/repository/io/netty/netty/3.10.6.Final/netty-3.10.6.Final.jar:/Users/yiny/Sites/java_demo/dubbo-zk-api/target/classes:/Users/yiny/.m2/repository/junit/junit/4.13.2/junit-4.13.2.jar:/Users/yiny/.m2/repository/org/hamcrest/hamcrest-core/2.2/hamcrest-core-2.2.jar:/Users/yiny/.m2/repository/javax/servlet/javax.servlet-api/4.0.1/javax.servlet-api-4.0.1.jar:/Users/yiny/.m2/repository/javax/servlet/jsp/javax.servlet.jsp-api/2.3.3/javax.servlet.jsp-api-2.3.3.jar:/Users/yiny/.m2/repository/jstl/jstl/1.2/jstl-1.2.jar:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.library.path=/Users/yiny/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.io.tmpdir=/var/folders/7p/r7xrt8r50l1cd6dh0dtz2n940000gp/T/
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.compiler=<NA>
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:os.name=Mac OS X
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:os.arch=x86_64
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:os.version=10.16
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:user.name=yiny
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:user.home=/Users/yiny
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:user.dir=/Users/yiny/Sites/java_demo/dubbo-zk-consumer
2021-08-08 14:22:06.157 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Initiating client connection, connectString=127.0.0.1:2181 sessionTimeout=60000 watcher=org.apache.curator.ConnectionState@252f626c
2021-08-08 14:22:06.175 INFO 54035 --- [localhost:2181)] org.apache.zookeeper.ClientCnxn : Opening socket connection to server localhost/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
2021-08-08 14:22:06.192 INFO 54035 --- [localhost:2181)] org.apache.zookeeper.ClientCnxn : Socket connection established to localhost/127.0.0.1:2181, initiating session
2021-08-08 14:22:06.217 INFO 54035 --- [localhost:2181)] org.apache.zookeeper.ClientCnxn : Session establishment complete on server localhost/127.0.0.1:2181, sessionid = 0x1000146c20c0007, negotiated timeout = 40000
2021-08-08 14:22:06.221 INFO 54035 --- [ain-EventThread] o.a.c.f.state.ConnectionStateManager : State change: CONNECTED
2021-08-08 14:22:07.663 INFO 54035 --- [ main] c.g.DubboZkConsumerApplicationTests : Started DubboZkConsumerApplicationTests in 2.957 seconds (JVM running for 3.913)
在注册中心拿到 ====> 极客堂-941311334
2021-08-08 14:22:08.094 INFO 54035 --- [extShutdownHook] .b.c.e.AwaitingNonWebApplicationListener : [Dubbo] Current Spring Boot Application is about to shutdown...
2021-08-08 14:22:08.129 INFO 54035 --- [tor-Framework-0] o.a.c.f.imps.CuratorFrameworkImpl : backgroundOperationsLoop exiting
2021-08-08 14:22:08.151 INFO 54035 --- [ain-EventThread] org.apache.zookeeper.ClientCnxn : EventThread shut down for session: 0x1000146c20c0007
2021-08-08 14:22:08.151 INFO 54035 --- [extShutdownHook] org.apache.zookeeper.ZooKeeper : Session: 0x1000146c20c0007 closed
2021-08-08 14:22:08.159 INFO 54035 --- [extShutdownHook] f.a.ReferenceAnnotationBeanPostProcessor : org.apache.dubbo.common.bytecode.proxy0@a69919e was destroying!
2021-08-08 14:22:08.159 INFO 54035 --- [extShutdownHook] f.a.ReferenceAnnotationBeanPostProcessor : class org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor was destroying!

Process finished with exit code 0

微服务笔记

框架

微服务条目 落地技术
服务开发 Spring、SpringMVC、SpringBoot
服务配置与管理 Netflix的Archaius、阿里的Diamond等
服务注册与发现 Eureka、Consul、Zookeeper
服务调用 Rest、RPC、gRPC
服务熔断器 Hystrix、Envoy等
负载均衡 Ribbon、Nginx等
服务接口调用 Feign等
消息队列 Kafka、RabbitMQ、ActiveMQ等
服务配置中心管理 SpringCloudConfig、Chef等
服务路由(API网关) Zuul等
服务监控 Zabbix、Nagios、Metrics、Specatator等
全链路追踪 Zipkin、Brave、Dapper等
服务部署 Docker、OpenStack、Kubernetes等
数据流操作开发包 SpringCloudStream(封装与Redis、Rabbit、Kafka等发送接收消息
消息事件总线 SpringCloud Bus

SpringMVC

SpringMVC执行过程

Maven教程

maven的安装

maven下载地址:maven官网

下载后解压到一个固定位置,比如我这里直接解压到:/Users/yiny/soft/apache-maven-3.8.1

然后更改.bash_profile (如果使用zsh的话需要修改.zshrc),将maven的环境变量添加进去:

1
2
export M2_HOME="/Users/yiny/soft/apache-maven-3.8.1"
export PATH="$M2_HOME/bin:$PATH"

然后在命令行执行mvn -v,如果命令成功返回显示了maven的版本号,就说明maven已经安装成功了。
如果不成功,比如提示找不到mvn命令等,一般是JDK或者maven安装的有问题。

修改maven的默认配置

修改本地仓库地址

安装成功后,需要到maven的安装目录下的conf/setting.xml文件中修改一下默认的repository存储位置和下载镜像。

1
2
3
4
5
6
7
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->
<localRepository>/Users/yiny/soft/apache-maven-3.8.1/repo</localRepository>

修改localRepository节点的值,配置本地仓库存储地址。

修改镜像地址

还需要配置下载源为阿里源,提高下载速度,在mirrors节点下添加如下mirror配置:

1
2
3
4
5
6
7
8
9
10
<mirrors>
...
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>

创建maven工程

这里以java的jar格式工程说明mvn的工程目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
➜  mvntest1 tree
.
├── pom.xml # maven 配置文件
├── src # 源码文件根目录
│   ├── main # 源码
│   │   ├── java
│   │   │   └── cn
│   │   │   └── geekhall
│   │   │   └── main
│   │   │   └── Main.java
│   │   └── resourses
│   └── test # 测试代码
│   └── java
└── target # 生成的目标文件根目录
├── classes
│   └── cn
│   └── geekhall
│   └── main
│   └── Main.class
└── maven-status
└── maven-compiler-plugin
└── compile
└── default-compile
├── createdFiles.lst
└── inputFiles.lst

然后在pom.xml文件中添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>cn.geekhall</groupId>
<artifactId>maventest1</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>

按照上面的目录格式常见好目录结构和源码文件后,在工程的根目录执行mvn compile 就会对工程进行编译,生成的文件存放在target目录下。第一次会下载全量依赖包,时间会比较长,第二次以后再次运行的时候就会比较快了。

然后执行: mvn -e exec:java -Dexec.mainClass="cn.geekhall.main.Main" 即可运行工程看到执行结果。

pom.xml文件格式

maven是使用pom.xml文件来找到各种依赖包、插件的地址,解决依赖问题的。
具体的pom.xml文件格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<!--在这里配置本工程的mvn地址信息。 -->
<groupId>cn.geekhall</groupId>
<artifactId>maventest02</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>maventest02 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>https://www.geekhall.cn</url>

<!-- 这里可以配置参数信息、比如编码格式、版本号信息等 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<junit.version>4.11</junit.version>
<servlet-version>4.0.1</servlet-version>
<jsp-version>2.3.3</jsp-version>
<jstl-version>1.2</jstl-version>
<spring-version>5.1.11.RELEASE</spring-version>
<aspectjweaver-version>1.9.4</aspectjweaver-version>
<mybatis-version>3.5.2</mybatis-version>
<mybatis-spring-version>2.0.2</mybatis-spring-version>
<log4j-version>1.2.17</log4j-version>
<mysql-connector-java-version>5.1.48</mysql-connector-java-version>
<jackson-version>2.9.9</jackson-version>
<commons-fileupload-version>1.3.1</commons-fileupload-version>
</properties>

<!-- 这里配置各种依赖信息 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>${jsp-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl-version}</version>
</dependency>
</dependencies>

<!-- 执行profile环境 -->
<profiles>
<profile>
<id>dev</id>
<properties>
<env>dev</env>
</properties>
<acctivation>
<activeByDefault>true</activeByDefault>
</acctivation>
</profile>
</profile>

<build>
<finalName>maventest02</finalName>
<!-- plugins配置各种插件 -->
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>6060</port>
<path>/my</path>
</configuration>
</plugin>
</plugins>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

maven常用命令

maven命令格式为:mvn [plugin-name]:[goal-name],表示执行plugin-name插件的goal-name目标,

常用命令有:

  • mvn -version / mvn -v : 显示版本信息。
  • mvn clean : 清理项目产生的临时文件,一般是模块下的target目录。
  • mvn compile : 编译源代码,一般编译模块下的src/main/java目录。
  • mvn package : 项目打包工具,会在模块下的target目录生成jar或者war等文件。
  • mvn test : 测试命令,会执行src/test/java目录下的测试用例。
  • mvn install : 将打包的jar或者war文件复制到你的本地仓库中,供其他模块使用。
  • mvn deploy : 将打包的jar或者war文件发布到远程仓库,提供其他人员进行下载依赖。
  • mvn site : 生成项目相关信息的网站。
  • mvn eclipse:eclipse : 将项目转化为Eclipse项目。
  • mvn dependency:tree : 打印出项目的整个依赖树。
  • mvn archetype:generate : 创建maven的普通java项目。
  • mvn tomcat7:run : 在tomcat容器中运行web应用。
  • mvn jetty:run: 调用jetty的run目标在Jetty Servlet容器中启动web应用。

需要注意的是:运行maven命令的时候,首先需要定位在maven项目所在的目录,也就是项目pom.xml文件所在的目录。否则需要使用参数执行项目的目录。

还可以使用-D指定属性参数,例如:mvn package -Dmaven.test.skip=true 可以指定打包的时候跳过单元测试。

IDEA集成maven环境

在工具的 preferences -> Build,Extension,Deployment -> Build Tools ->Maven 目录下配置maven。

在Maven home directory:目录下配置当前使用的maven,这里使用了IDEA自带的maven。

创建java项目

创建普通java项目

web项目要选择maven-archetype-webapp

编辑运行配置

compile

package

maven仓库

对于maven来说,仓库分为两类:本地仓库和远程仓库。maven根据坐标去寻找构件的时候,它会首先查看本地仓库,若存在则直接使用,不存在再去远程仓库下载。
远程仓库分为三种:中央仓库(国外,访问量大,速度慢),私服(一般公司内部搭建),其他公共库(阿里等)。

mavenrepository.com

maven的配置可以从
https://mvnrepository.com/上找到。

C语言笔记

C语言简介

C 语言是一种通用的、面向过程式的计算机程序设计语言。1972 年,为了移植与开发 UNIX 操作系统,丹尼斯·里奇在贝尔电话实验室设计开发了 C 语言。

C 语言是一种广泛使用的计算机语言,它与 Java 编程语言一样普及,二者在现代软件程序员之间都得到广泛使用。

当前最新的 C 语言标准为 C18 ,在它之前的 C 语言标准有 C17、C11…C99 等。

第一个C程序

1
2
3
4
5
6
#include <stdio.h>
int main()
{
printf("Hello, World! \n");
return 0;
}

开发环境

Unix/Linux/Mac环境

如果是使用Unix/Linux/Mac环境,可以使用gcc -v命令检查本地是否安装了gcc环境。

Windows环境

需要先安装Cygwin

使用VSCode和Code Runner插件

使用VSCode的Code Runner插件可以方便地编译和运行C程序

基础语法

  • 分号:在 C 程序中,分号是语句结束符。也就是说,每个语句必须以分号结束。它表明一个逻辑实体的结束。

  • 注释

    • 单行注释
    • 多行注释
  • 标识符:
    标识符是用来标识变量、函数,或任何其他用户自定义项目的名称。一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9)。

    C 标识符内不允许出现标点字符,比如 @、$ 和 %。C 是区分大小写的编程语言。因此,在 C 中,Manpower 和 manpower 是两个不同的标识符。

  • 关键字

  • 空格:只包含空格的行,被称为空白行,可能带有注释,C 编译器会完全忽略它。在 C 中,空格用于描述空白符、制表符、换行符和注释。

数据类型

变量

常量

存储类

  • auto
  • register
  • static
  • extern

运算符

判断

循环

函数

作用域规则

数组

枚举

指针

函数指针与回调函数

字符串

结构体

共用体

位域

typedef

输入&输出

文件读写

预处理

头文件

强制类型转换

错误处理

递归

可变参数

内存管理

命令行参数

常用数据结构和算法

gdb和程序调试

gdb常用命令

  • attach
  • break/b
  • continue/c
  • info
  • set print pretty

makefile和工程

堆和栈

程序的结构-ELF文件

程序的结构-中间文件、可执行程序、静态库、动态库

栈溢出

程序漏洞、pwn