IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> starter+AOP拦截+RestTemplate实现日志服务 -> 正文阅读

[Java知识库]starter+AOP拦截+RestTemplate实现日志服务

首先需要创建一个日志收集 starter,如果对自定义starter不了解的可以参考自定starter实现

log的starter的目录结构:

首先引入依赖

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

创建日志starter的properties的配置类——LogProperties.java

package org.mystarter.logstringbootstarter.properties;


import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;


/**
 *
 * properties配置文件类
 *
 */
@ConfigurationProperties(prefix = "spring.log")
@Data
public class LogProperties {

    //默认的请求地址
    private String host = "http://127.0.0.1:9000";


}

LogService.java :

package org.mystarter.logstringbootstarter.server;

import org.mystarter.logstringbootstarter.properties.LogProperties;

/**
 * service  将properties 注入到ioc 需要用到
 */
public class LogService {

//    service 定义 LogProperties 的属性
    public LogProperties dp;

}

?LogProxy :

package org.mystarter.logstringbootstarter.proxy;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.mystarter.logstringbootstarter.properties.LogProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.Executor;

/**
 * AOP 切面
 */

@Aspect
@Slf4j
public class LogProxy {

    @Autowired
    RestTemplate rt;

    @Autowired
    LogProperties lp;

    /**
     * 使用ioc的自定义线程,单独处理日志上传服务器
     * logExecutor 线程的名字
     */
    @Qualifier("logExecutor")
    @Autowired
    Executor executor;

    /**
     * 切点
     * 扫描所有  @RequestMapping  注解类  (因为每个控制层都会有@RequestMapping注解,所以直接拦截被这个注解标注的类)
     */
    @Pointcut("@within(org.springframework.web.bind.annotation.RequestMapping)")
    public void request(){

    }

    /**
     * 环绕通知
     * @param point
     * @return
     */
    @Around("request()")
    public Object logAround(ProceedingJoinPoint point) {
        Object proceed = null;
        try {
//            通过ProceedingJoinPoint获取Request
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();

            /**
             * 通过HttpServletRequest获取请求url、方法本身
             * 还可以获取很多-常见的有
             *  getMethod()  :获取请求提交的方式
             *  getProtocol()  :获取请求的协议
             *  getContextPath()  :获取项目名称
             *  getServletPath()  :获取servlet路径
             *  getRequestURI()、getRequestURL()  :获取请求路径
             */
            String getRequestURL = request.getRequestURL().toString();

//            这里需要我们执行拦截方法本身的代码(最后返回)
             proceed = point.proceed();
//             声明一个map 放入日志信息
            LinkedMultiValueMap<String, Object> mv = new LinkedMultiValueMap<String, Object>();
            mv.add("RequestURL",getRequestURL);
            mv.add("return",proceed);

//            打印map
            log.info(String.valueOf(mv));

            /**
             * 异步上传服务器
             * 上传的路径是LogProperties的host 值
             */
            executor.execute(() -> rt.postForObject(lp.getHost()+"log",mv,String.class));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }


        return proceed;
    }



}

LogAutoConfiguration:

package org.mystarter.logstringbootstarter.configuration;

import lombok.extern.slf4j.Slf4j;
import org.mystarter.logstringbootstarter.properties.LogProperties;
import org.mystarter.logstringbootstarter.proxy.LogProxy;
import org.mystarter.logstringbootstarter.server.LogService;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 自动配置类
 */
@Configuration
@EnableConfigurationProperties({LogProperties.class})
@Slf4j
public class LogAutoConfiguration {


    /**
     * 服务对象
     * @param logProperties
     * @return
     */
    @Bean
    LogService logBean(LogProperties logProperties){
        LogService logService = new LogService();
        logService.dp = logProperties;
        return logService;
    }

    /**
     * 将RestTemplate对象 放入ioc
     * @return
     */
    @Bean
    RestTemplate restTemplate(){
        return  new RestTemplate();
    }

    /**
     * 将日志AOP切面对象放入ioc
     * @return
     */
    @Bean
    LogProxy logProxy(){
        return new LogProxy();
    }

    /**
     * 定义一个线程
     * 放入ioc
     * @return
     */
    @Bean("logExecutor")
    Executor executor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数:线程池创建时候初始化的线程数
        executor.setCorePoolSize(5);
        // 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(10);
        // 缓冲队列:用来缓冲执行任务的队列
        executor.setQueueCapacity(50);
        // 允许线程的空闲时间60秒:当超过了核心线程之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        // 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("do-something-");
        // 缓冲队列满了之后的拒绝策略:由调用线程处理(一般是主线程)
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        executor.initialize();
        return executor;
    }

    @Bean
    public void afterPropertiesSet(){
        log.info("日志准备就绪");
    }

}

最后打包成启动器(日志收集starter完成)

准备日志服务(springboot项目)

项目结构:

引入依赖

  <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

日志服务只提供一个接收日志的方法(既然都可以接收到日志,后续就可以对这些日志为所欲为,比如放入redis中)

修改运行端口:

????????application.properties

# 应用服务 WEB 访问端口
server.port=9000

LogServiceController :

package com.example.logservice.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * 接收日志 controller
 * */
@RestController
@RequestMapping("log")
@Slf4j
public class LogServiceController {

    @PostMapping
    public String logService(@RequestParam Map<String,Object> m){
//      这里我只打印接收到的日志
        log.info("接收的日志为"+m);
        return "ok";
    }

}

到此日志服务就准备好了

创建测试项目:

项目结构:

引入依赖:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

<!--      引入日志starter   -->
        <dependency>
            <groupId>org.my</groupId>
            <artifactId>log-spring-boot-starter</artifactId>
            <version>1.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

application.properties中配置:

# 日志服务器的地址 (因为我的logService端口是9000并且在本地所以不用改配置)
spring.log.host=http://127.0.0.1:9000

编写测试controller

package com.example.test.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *  Test controller
 */
@RestController
@RequestMapping("demos")
public class TestController {

    @GetMapping
    List<Map<String,Object>> test(String msg){
//        封装一个返回值并返回
        List l=new ArrayList();
        Map m=new HashMap();
        m.put("key",msg);
        l.add(m);
        return l;
    }


}

到这测试项目也完成了

测试项目:运行日志服务和测试项目,访问测试项目的API,在日志服务控制台中就能看到打印的日志信息

到这里就完成了

设计这个日志收集实现流程为:

??????? 请求项目资源,被LogStarter的AOP拦截器拦截,通过AOP环绕通知中ProceedingJoinPoint获取HttpServletRequest然后拿到请求信息,发送给日志服务器logService,日志服务器收到日志后就可以做相应处理了。

源码:https://gitee.com/feiliangren/log-service.git

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 16:02:30  更:2021-07-15 16:03:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 20:19:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码