• springboot深入学习(一)-----springboot核心、配置文件加载、日志配置


    在创建spring项目的时候,最烦的就是各种xml配置,通常有一个小坑可能会耽误好久时间,现在springboot已经改变了这种现象,让你告别xml配置,并且只要启动一个java类,搭配上嵌入式的web容器,简直爽歪歪。

    springboot的思想就是“约定大于配置”,也就是说对于同一件事件或是操作,大部分开发者的做法都相同,那springboot就默认提供这种方式,这样大部分人就不需要手动配置,当然你有特殊项目要求,也可以自己手动配置。

    创建一个springboot的项目

    直接选择default的就好,点击next;

    创建工程名:MyProject

    这地方有很多的模块可以选择,包括spring cloud中的模块,本人先选择了其中的两个模块;

    建好项目之后,本人准备new一个Java文件,但是发现右键的时候没有新建java class的按钮,如下:

    遇到这种问题呢,也不要慌张,解决方法如下:

    点击file-->project structure

    点击modules

    将整个项目中的包对应source、resource等一一对应好;

    然后点击apply、ok

    搞定了。

    下面新建几个包,完善一下项目结构:

     

    建议将所有的包与主类放在同一层级,这样后面可以减少很多的手工导入以及配置。

    @SpringBootApplication

    @SpringBootApplication是spring boot的核心注解,源码如下:

    相当于:@Configuration+@EnableAutoConfiguration+@ComponentScan

    @Configuration:此类是一个配置

    @EnableAutoConfiguration:让springboot根据类路径中的jar包依赖为当前项目进行自动配置

    @ComponentScan:springboot自动扫描入口类所在包以及其子包里的bean

    另外springboot也可以关闭特定的自动配置:@SpringBootApplication(exlude = {DataSourceAutoConfiguration.class})

    SpringBoot配置文件

    1、application.properties或application.yml

    SpringBoot的全局配置文件为applicaiton.properties或者application.yml,通常放在src/main/resources/下,如下:

    同样也可以使用yml编写,示例如下(将tomcat默认端口修改为8001、将默认访问路径修改为/index):

    A、application.properties

    server.port=8001

    server.context-path=/index

    B、application.yml

    server:

      port:8001

      context-path: /index

    2、加载xml

    springboot提倡零配置,但是项目中难免需要使用xml配置,引入方式如下:

    @ImportResource({"classpath:some-context.xml", "classpath:another-context.xml"})

    外部配置

    1、常规属性配置

    在spring的项目中,通过@PropertySource指明properties文件的位置,然后可以通过@Value注入值。在SpringBoot里,只需要在appllication.properties文件中定义属性,直接使用@Value即可

    示例:

    application.properties文件增加属性:

    运行结果:

    注意点:

    A、@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})  ----------------------->项目启动的时候会报错,提示没有数据源,因此在初始化bean的时候,排除这个bean

    B、项目运行地址是不需要项目名的,直接使用http://localhost:8080/index,而不是http://localhost:8080/项目名称/index

     2、类型安全的配置

    通过@Value的方式配置属性也可以,但是当属性过多时,会写许多个@Value,同时也不美观,因此springboot还提供了@ConfigurationProperties将属性与一个bean关联,示例如下:

    运行结果:

    注意点:

    A、使用lombok的@Data可以省去写get、set方法

    B、有时候会提示一个错误:Spring Boot Annotion processor not found in classpath

    这时需要添加一个依赖,如下:

    C、在加载application.properties中的属性时,不需要指定location,如果是在其他自定义的properties文件中去加载属性,则需要加上location(1.5.1以上版本取消)

    @ConfigurationProperties(prefix = "xxx", locations = {"classpath:/xxx.properties"})

    如果springboot版本高于1.5.1,则可以使用这种方式(将类注册为@component,并且使用@ConfigurationProperties+@PropertySource):

    日志配置

    springboot支持log4j、logback等等作为日志框架,但是默认日志框架使用的是logback,示例如下:

    配置日志文件:

    logging.file=D:/mylog/log.log

    配置日志级别:

    logging.level.org.springframework.web=DEBUG

    1、log4j

    a、引入依赖

    在创建Spring Boot工程时,我们引入了 spring-boot-starter ,其中包含了 spring-boot-starterlogging,该依赖内容就是Spring Boot默认的日志框架Logback,所以我们在引入log4j之前,需要先排除该包的依赖,再引用log4j的依赖。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j</artifactId>
    </dependency>

    b、配置log4j.properties

    在src/main/resources目录下加入log4j.properties配置文件。

    控制台输出:

    # 控制台输出
    # LOG4J配置
    log4j.rootCategory=INFO, stdout
    # 控制台输出
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n

    输出到文件:

    # 输出到文件
    log4j.rootCategory=INFO, stdout, file
    # root⽇志输出
    log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.file.file=logs/all.log
    log4j.appender.file.DatePattern='.'yyyy-MM-dd
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n

    2、将log4j日志写入到mongodb

    思路:log4j提供的输出器实现自Appender接口,要自定义appender输出到mongodb,只需要继承AppenderSkeleton,并实现几个方法即可。

    a、引入依赖

    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongodb-driver</artifactId>
        <version>3.2.2</version>
    </dependency>

    b、继承AppenderSkeleton

    public class MongoAppender extends AppenderSkeleton {
        //mongodb的连接客户端
        private MongoClient mongoClient;
        //记录日志的数据库
        private MongoDatabase mongoDatabase;
        //记录日志的集合
        private MongoCollection<BasicDBObject> logsCollection;
        //连接mongodb的串
        private String connectionUrl;
        //数据库名
        private String databaseName;
        //集合名
        private String collectionName;
        
        @Override
        protected void append(LoggingEvent loggingEvent) {
            if(mongoDatabase == null) {
                MongoClientURI connectionString = new MongoClientURI(connectionUrl);
                mongoClient = new MongoClient(connectionString);
                mongoDatabase = mongoClient.getDatabase(databaseName);
                logsCollection = mongoDatabase.getCollection(collectionName, BasicDBObject.class);
            }
            logsCollection.insertOne((BasicDBObject) loggingEvent.getMessage());
        }
        
        @Override
        public void close() {
            if(mongoClient != null) {
                mongoClient.close();
            }
        }
        
        @Override
        public boolean requiresLayout() {
            return false;
        }
        // 省略getter和setter
    }

    c、配置log4j.properties

    # 记录INFO级别⽇志
    log4j.logger.mongodb=INFO, mongodb
    # mongodb输出
    # appender实现为com.didispace.log.MongoAppende
    log4j.appender.mongodb=com.didispace.log.MongoAppender
    # mongodb连接地址:mongodb://localhost:27017
    log4j.appender.mongodb.connectionUrl=mongodb://localhost:27017
    # mongodb数据库名:logs
    log4j.appender.mongodb.databaseName=logs
    # mongodb集合名:logs_request
    log4j.appender.mongodb.collectionName=logs_request

    d、通过切面实现

    @Aspect
    @Order(1)
    @Component
    public class WebLogAspect {
        private Logger logger = Logger.getLogger("mongodb");
        
        @Pointcut("execution(public * com.didispace.web..*.*(..))")
        public void webLog(){}
        
        @Before("webLog()")
        public void doBefore(JoinPoint joinPoint) throws Throwable {
            // 获取HttpServletRequest有两种方式:
        
    //一:在controller层中将HttpServletRequest一层层的传下去。
         //二:((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()获得 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 获取要记录的⽇志内容 BasicDBObject logInfo = getBasicDBObject(request, joinPoint); logger.info(logInfo); } private BasicDBObject getBasicDBObject(HttpServletRequest request, JoinPoint joinPoint) { // 基本信息 BasicDBObject r = new BasicDBObject(); r.append("requestURL", request.getRequestURL().toString()); r.append("requestURI", request.getRequestURI()); r.append("queryString", request.getQueryString()); r.append("remoteAddr", request.getRemoteAddr()); r.append("remoteHost", request.getRemoteHost()); r.append("remotePort", request.getRemotePort()); r.append("localAddr", request.getLocalAddr()); r.append("localName", request.getLocalName()); r.append("method", request.getMethod()); r.append("headers", getHeadersInfo(request)); r.append("parameters", request.getParameterMap()); r.append("classMethod", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); r.append("args", Arrays.toString(joinPoint.getArgs())); return r; } private Map<String, String> getHeadersInfo(HttpServletRequest request) { Map<String, String> map = new HashMap<>(); Enumeration headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String key = (String) headerNames.nextElement(); String value = request.getHeader(key); map.put(key, value); } return map; } }
  • 相关阅读:
    18 | 案例篇:内存泄漏了,我该如何定位和处理?
    17 | 案例篇:如何利用系统缓存优化程序的运行效率?
    16 | 基础篇:怎么理解内存中的Buffer和Cache?
    Scrapyd 改进第一步: Web Interface 添加 charset=UTF-8, 避免查看 log 出现中文乱码
    scrapy_redis 相关: 将 jobdir 保存的爬虫进度转移到 Redis
    lxml.etree.HTML(text) 解析HTML文档
    CSS/Xpath 选择器 第几个子节点/父节点/兄弟节点
    scrapy_redis 相关: 查看保存的数据
    scrapy 通过FormRequest模拟登录再继续
    python2 python3 转换,兼容
  • 原文地址:https://www.cnblogs.com/alimayun/p/10235726.html
Copyright © 2020-2023  润新知