上一篇已经介绍了Nacos的基础知识(
传送门
),也从源码启动了Nacos Server,今天我们探究下项目结构,以便于搭建自己的服务端!
我们先看下源码中Nacos-console 项目的结构:
目录包含了config(配置)、controller(控制层)、exception(自定义异常)、filter(过滤器)、model、security.nacos(安全模块)、utils(工具类),定义习惯也是通用定义,可以从目录结构、类名称直接认识到其实现的功能。下面介绍几个核心文件:
-
config目录下的ConsoleConfig.java:
@Component
@EnableScheduling
@PropertySource("/application.properties")
public class ConsoleConfig {
@Autowired
private ControllerMethodsCache methodsCache;
@PostConstruct
public void init() {
methodsCache.initClassMethod("com.alibaba.nacos.naming.controllers");
methodsCache.initClassMethod("com.alibaba.nacos.console.controller");
methodsCache.initClassMethod("com.alibaba.nacos.config.server.controller");
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.setMaxAge(18000L);
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
关于注解的解释,请移步:Spring 相关注解说明(关注公众号,打开菜单)
这里主要实现了两个方法,init()和corsFilter()
init():主要利用反射的方法初始化了相关类,initClassMethod的实现:
public void initClassMethod(String packageName) {
Reflections reflections = new Reflections(packageName);
Set<Class<?>> classesList = reflections.getTypesAnnotatedWith(RequestMapping.class);
for (Class clazz : classesList) {
initClassMethod(clazz);
}
}
corsFilter():主要为了解决跨域问题,它允许浏览器向跨域服务器发送Ajax请求,打破了Ajax只能访问本站内的资源限制。分布式微服务架构这几乎是一定会遇到的问题。
2.controller目录下的控制器:
HealthController:主要是健康检查、节点检查,具体在那个功能生效,后续再进行说明
NamespaceController:命名空间管理
PermissionController:权限认证
RoleController:角色管理
ServerStateController:节点信息
UserController:用户管理,包含登陆等
这里代码不在详细说明,
3.filter目录下
JwtAuthenticationTokenFilter:
主要功能校验令牌是否有效
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
String jwt = resolveToken(request);
if (StringUtils.isNotBlank(jwt) && SecurityContextHolder.getContext().getAuthentication() == null) {
this.tokenManager.validateToken(jwt);
Authentication authentication = this.tokenManager.getAuthentication(jwt);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
/**
* Get token from header
*/
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(NacosAuthConfig.AUTHORIZATION_HEADER);
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
return bearerToken.substring(7);
}
String jwt = request.getParameter(Constants.ACCESS_TOKEN);
if (StringUtils.isNotBlank(jwt)) {
return jwt;
}
return null;
}
4.security.nacos
主要包含一些具体的实现类,比如用户登录的逻辑(NacosAuthManager),令牌校验和生成的逻辑(JwtTokenManager)
配置本地数据库启动
Nacos 本身在单机模式时nacos使用嵌入式数据库实现数据的存储,在0.7版本增加了支持mysql数据源能力,具体步骤是:
-
1.安装数据库,版本要求:5.6.5+(之前已安装了一主二从数据库)
-
2.初始化mysql数据库,数据库初始化文件:nacos-mysql.sql
-
3.修改conf/application.properties文件,增加支持mysql数据源配置(目前只支持mysql),添加mysql数据源的url、用户名和密码。
spring.datasource.platform=mysql
db.num=3
db.user=root
db.password=123456
db.url.0=jdbc:mysql://192.168.65.129:3000/nacos_config?serverTimezone=GMT%2B8&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.url.1=jdbc:mysql://192.168.65.129:3001/nacos_config?serverTimezone=GMT%2B8&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.url.2=jdbc:mysql://192.168.65.129:3002/nacos_config?serverTimezone=GMT%2B8&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
配置完毕,启动Nacos.java 即可。
Connected to the target VM, address: '127.0.0.1:50380', transport: 'socket'
,--.
,--.'|
,--,: : | Nacos
,`--.'`| ' : ,---. Running in stand alone mode, All function modules
| : : | | ' ,'\ .--.--. Port: 8848
: | \ | : ,--.--. ,---. / / | / / ' Pid: 21524
| : ' '; | / \ / \. ; ,. :| : /`./ Console: http://192.168.19.1:8848/nacos/index.html
' ' ;. ;.--. .-. | / / '' | |: :| : ;_
| | | \ | \__\/: . .. ' / ' | .; : \ \ `. https://nacos.io
' : | ; .' ," .--.; |' ; :__| : | `----. \
| | '`--' / / ,. |' | '.'|\ \ / / /`--' /
' : | ; : .' \ : : `----' '--'. /
; |.' | , .-./\ \ / `--'---'
'---' `--`---' `----'
2020-04-21 23:54:23.186 INFO 21524 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration' of type [org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration$$EnhancerBySpringCGLIB$$f3ad21c2] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-04-21 23:54:23.310 INFO 21524 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'objectPostProcessor' of type [org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-04-21 23:54:23.314 INFO 21524 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler@30f28b5' of type [org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-04-21 23:54:23.315 INFO 21524 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration' of type [org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration$$EnhancerBySpringCGLIB$$1881c474] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-04-21 23:54:23.322 INFO 21524 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'methodSecurityMetadataSource' of type [org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-04-21 23:54:24.281 INFO 21524 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8848 (http)
2020-04-21 23:54:24.449 INFO 21524 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3450 ms
2020-04-21 23:54:31.734 INFO 21524 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-21 23:54:31.930 INFO 21524 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html]
2020-04-21 23:54:32.513 INFO 21524 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/**'], []
2020-04-21 23:54:32.546 INFO 21524 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@3b17759c, org.springframework.security.web.context.SecurityContextPersistenceFilter@6956eb58, org.springframework.security.web.header.HeaderWriterFilter@52fe87e0, org.springframework.security.web.csrf.CsrfFilter@458b4487, org.springframework.security.web.authentication.logout.LogoutFilter@153d14e3, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@6127ef86, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@301f9aa0, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@11cdf948, org.springframework.security.web.session.SessionManagementFilter@4d3a7f83, org.springframework.security.web.access.ExceptionTranslationFilter@73818435]
2020-04-21 23:54:32.638 INFO 21524 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator'
2020-04-21 23:54:32.670 INFO 21524 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService 'taskScheduler'
2020-04-21 23:54:32.781 INFO 21524 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8848 (http) with context path '/nacos'
2020-04-21 23:54:32.790 INFO 21524 --- [ main] c.l.StartingSpringApplicationRunListener : Nacos logs files: C:\Users\back_\nacos\logs\
2020-04-21 23:54:32.790 INFO 21524 --- [ main] c.l.StartingSpringApplicationRunListener : Nacos conf files: C:\Users\back_\nacos\conf\
2020-04-21 23:54:32.790 INFO 21524 --- [ main] c.l.StartingSpringApplicationRunListener : Nacos data files: C:\Users\back_\nacos\data\
2020-04-21 23:54:32.790 INFO 21524 --- [ main] c.l.StartingSpringApplicationRunListener : Nacos started successfully in stand alone mode.
2020-04-21 23:54:32.913 INFO 21524 --- [nio-8848-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-04-21 23:54:32.923 INFO 21524 --- [nio-8848-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 10 ms
访问:http://localhost:8848/nacos/,登录账户/密码:nacos/nacos
随意添加配置,
这时,我们的数据库config_info表中已经添加了这条记录
从库也同步更新
搭建自己的NacosServer
创建新的SpringBoot项目:
项目创建完成后
为了方便测创建试,这里先把功能性代码直接复制到新项目,并解决引入问题
目的是先完成项目启动,并在解决引入问题过程中,熟悉项目依赖和项目结构,以及功能。
把Nacos-console 项目中以下目录完整复制到我们的项目中,
com/alibaba/nacos/console
console/src/main/resources/META-INF
console/src/main/resources/static
整理过的pom.xml 配置:
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>7.0.59</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-config</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-naming</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-core</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>release-nacos</id>
<build>
<finalName>nacos-server</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
在启动类上添加扫描注解:
@ComponentScan("com.reims.main,com.alibaba.nacos")
@SpringBootApplication
public class NacosServerApplication {
public static void main(String[] args) {
SpringApplication.run(NacosServerApplication.class, args);
}
}
设置启动单机模式:
在application.properties中添加mysql数据源:
spring.datasource.platform=mysql
db.num=3
db.user=root
db.password=123456
db.url.0=jdbc:mysql://192.168.65.129:3000/nacos_config?serverTimezone=GMT%2B8&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.url.1=jdbc:mysql://192.168.65.129:3001/nacos_config?serverTimezone=GMT%2B8&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.url.2=jdbc:mysql://192.168.65.129:3002/nacos_config?serverTimezone=GMT%2B8&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
切记,在resources目录下的nacos-default.properties一定要复制过来,因为这里面包含着Nacoe server 核心程序Nacos Config 的默认配置,比如:
useAddressServer=true
# whether open interInterFaceFilter; true:open; false:close; if open, others can't call inner interface. default:false
openInnerInterfaceFilter=false
# quickStart stip dumpAll;only dump change config
isQuickStart=false
# server notify each otherd
notifyConnectTimeout=200
# server notify each other
notifySocketTimeout=8000
# whether health check
isHealthCheck=true
# health check max fail count
maxHealthCheckFailCount=12
下节我们将全部自主搭建的时候再来讲解这个文件的内容,以及怎么去掉这个文件。
此时启动NacosServerApplication,
Connected to the target VM, address: '127.0.0.1:52415', transport: 'socket'
,--.
,--.'|
,--,: : | Nacos
,`--.'`| ' : ,---. Running in stand alone mode, All function modules
| : : | | ' ,'\ .--.--. Port: 8848
: | \ | : ,--.--. ,---. / / | / / ' Pid: 18280
| : ' '; | / \ / \. ; ,. :| : /`./ Console: http://192.168.19.1:8848/nacos/index.html
' ' ;. ;.--. .-. | / / '' | |: :| : ;_
| | | \ | \__\/: . .. ' / ' | .; : \ \ `. https://nacos.io
' : | ; .' ," .--.; |' ; :__| : | `----. \
| | '`--' / / ,. |' | '.'|\ \ / / /`--' /
' : | ; : .' \ : : `----' '--'. /
; |.' | , .-./\ \ / `--'---'
'---' `--`---' `----'
2020-04-23 00:00:56.606 INFO 18280 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration' of type [org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-04-23 00:00:56.717 INFO 18280 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'objectPostProcessor' of type [org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-04-23 00:00:56.719 INFO 18280 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler@2c0c4c0a' of type [org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-04-23 00:00:56.720 INFO 18280 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration' of type [org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-04-23 00:00:56.724 INFO 18280 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'methodSecurityMetadataSource' of type [org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-04-23 00:00:57.606 INFO 18280 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8848 (http)
2020-04-23 00:00:57.717 INFO 18280 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2908 ms
2020-04-23 00:01:04.717 INFO 18280 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-23 00:01:04.823 INFO 18280 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html]
2020-04-23 00:01:05.087 INFO 18280 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/**'], []
2020-04-23 00:01:05.121 INFO 18280 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@189e96af, org.springframework.security.web.context.SecurityContextPersistenceFilter@e3692ca, org.springframework.security.web.header.HeaderWriterFilter@3791af, org.springframework.security.web.csrf.CsrfFilter@578d5d02, org.springframework.security.web.authentication.logout.LogoutFilter@78bce1c4, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5cfe28e1, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@15ee8861, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@45b6c666, org.springframework.security.web.session.SessionManagementFilter@5535e9, org.springframework.security.web.access.ExceptionTranslationFilter@397dfbe8]
2020-04-23 00:01:05.140 INFO 18280 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService 'taskScheduler'
2020-04-23 00:01:05.148 INFO 18280 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator'
2020-04-23 00:01:05.238 INFO 18280 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8848 (http) with context path '/nacos'
2020-04-23 00:01:05.244 INFO 18280 --- [ main] c.l.StartingSpringApplicationRunListener : Nacos logs files: C:\Users\back_\nacos\logs\
2020-04-23 00:01:05.244 INFO 18280 --- [ main] c.l.StartingSpringApplicationRunListener : Nacos conf files: C:\Users\back_\nacos\conf\
2020-04-23 00:01:05.244 INFO 18280 --- [ main] c.l.StartingSpringApplicationRunListener : Nacos data files: C:\Users\back_\nacos\data\
2020-04-23 00:01:05.245 INFO 18280 --- [ main] c.l.StartingSpringApplicationRunListener : Nacos started successfully in stand alone mode.
2020-04-23 00:01:05.590 INFO 18280 --- [nio-8848-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-04-23 00:01:05.598 INFO 18280 --- [nio-8848-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 8 ms
访问:http://localhost:8848/nacos/,使用nacos/nacos 登录,即可看到系统界面
结论:本章从简单解析Nacos console 样例工程,并仿照搭建了自己的Nacos Server,但是现在的逻辑都是基于原始样例,不过本章的目的也不在于直接了解源码写法,而是从使用的角度,先入门,在使用的过程中去深入的了解每个模块之间的结构和实现,了解更深的技术点。达到学得会,也能用自己的角度解释出来。这也是我的观念,先会用,有了场景再去深入,远远比干巴巴的一对技术原理要实用的多,并不是每个人都是技术专家,都能成为技术专家。只有在更多的使用中发现更多的问题,丰富的解决问题的经验也将会是你的财富。
这一章,我从对Nacos源码零了解写出来,中间也遇到了不少问题,就那个切记提到的配置文件,就让我疑惑了好久。不够一个一个问题解决下来,现在我们对整个依赖的机构至少有了个初步的理解不是么?也成功的从整个Nacos-all 体系代码中,单独分离出来了服务端。这样我们以后不管是搭建自己的服务端,还是扩展前端的管理能力,我们对结构都有清晰的认识,怎么做也就有了自己的想法。比如构建自己的前台管理页面融入到现有的管理系统,纯后端做微服务集群来管理,等等。
所以,包括以后,我的文章应该不会直接讲一大堆的技术原理,除非有必要,我一般都会从认知的角度来出发,目的是从知道、了解到达会用,能说的出来,有自己的想法和逻辑。最后达到自己的一套常用的体系架构。并能随意剪切调整,以便应对各种业务情况!
↓扫码关注不迷路,更多操作持续更新中↓
↓扫码关注,优惠先享↓