Java Spring JPA Crudepository Autowired对象与Apache Commons Tailer一起使用时为空

Java Spring JPA Crudepository Autowired对象与Apache Commons Tailer一起使用时为空,java,spring-boot,spring-data-jpa,apache-commons,Java,Spring Boot,Spring Data Jpa,Apache Commons,我正在开发一个小应用程序,可以指向ApacheHTTP服务器日志,在Linux中跟踪日志a la'tail-f',并将条目写入Oracle数据库表 我设置了Spring Boot/Spring Data JPA应用程序,并为我的实体、Crudepository接口、接口服务创建了类,尽管我认为这在技术上对该实现是不必要的,并且创建了启动该过程的运行程序。我还设置了TailerListenerAdapter来执行日志文件解析的提升。我将在下面发布所有这些代码 问题是,在启动Tailer侦听器之前,

我正在开发一个小应用程序,可以指向ApacheHTTP服务器日志,在Linux中跟踪日志a la'tail-f',并将条目写入Oracle数据库表

我设置了Spring Boot/Spring Data JPA应用程序,并为我的实体、Crudepository接口、接口服务创建了类,尽管我认为这在技术上对该实现是不必要的,并且创建了启动该过程的运行程序。我还设置了TailerListenerAdapter来执行日志文件解析的提升。我将在下面发布所有这些代码

问题是,在启动Tailer侦听器之前,我可以成功地将测试记录写入数据库。但是,当侦听器运行时,TailerListenerAdapter中的自动连线服务为null并引发异常

java.lang.NullPointerException
    at sbx.demo.logauditor.util.AccessListener.handle(AccessListener.java:49)
    at org.apache.commons.io.input.Tailer.readLines(Tailer.java:525)
    at org.apache.commons.io.input.Tailer.run(Tailer.java:457)
    at sbx.demo.logauditor.LogAuditRunner.run(LogAuditRunner.java:40)
    {... more stack trace ...}
这里是使用的类,我可能有一些不必要的注释在那里从实验中遗留下来-

LogAuditRunner.java

AccessService.java

AccessListener.java

最后是LogauditorApplication.java

另外,我注意到,如果我手动实例化AccessService而不是依赖自动连接,我可以调用它,但是在自动连接的AccessRepository接口上会发生NullPointerException。我很清楚这和自动布线有关,我只是不明白为什么


我知道有很多方法可以通过命令行跟踪和发送日志,这将在Linux环境中运行,但我想确保它足够健壮,可以在死机时重新启动,处理日志翻转等,我计划写入一些额外的验证,以确保条目不会重叠,即在应用程序重新启动并重新读取整个文件的情况下。但是,我想先让它工作起来。我认为这会很简单,因为Tailer只需要很少的代码,而且我已经习惯了Spring。

我能够通过将AccessService作为AccessListener构造函数的参数来实现这一点。然后,我不得不将@Transactional注释添加到AccessService中的save方法中,以便在线程内处理每一行之后提交事务

新AccessListener.java


什么是Spring启动版本?您可以在AccessListener中创建一个构造函数,使用AccessService参数,并根据Spring引导省略@Autowired。输出是什么?@Boris Spring启动版本是2.2.4.0版本。我按照您的建议做了,并使AccessService成为AccessListener构造函数的一部分。我现在能够在没有NullPointerException的情况下执行应用程序,并且可以在日志中看到SQL调试。但是,数据没有提交到数据库。我假设事务保持打开状态?@Boris我可以通过向AccessService保存方法添加@Transactional注释来修复它。
package sbx.demo.logauditor;

import java.io.File;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import javax.transaction.Transactional;

import org.apache.commons.io.input.Tailer;
import org.apache.commons.io.input.TailerListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import lombok.var;
import sbx.demo.logauditor.model.AccessRecord;
import sbx.demo.logauditor.service.AccessService;
import sbx.demo.logauditor.util.AccessListener;

@Component
public class LogAuditRunner implements CommandLineRunner {
    @Autowired
    AccessService accServ;
    final String datePattern = "dd/MMM/yyyy:HH:mm:ss Z";
    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(datePattern);

    @Override
    @Transactional
    public void run(String... args) throws Exception {

        // This test code works if uncommented
        //LocalDateTime TS = LocalDateTime.from(formatter.parse("31/Jan/2020:14:28:32 -0500"));     
        //var logTest = new AccessRecord("10.154.103.2",Timestamp.valueOf(TS),"/cs/resources/layouts/Top%20Menus/Oracle/tree_T_collection_closed.gif","304");
        //System.out.println("Testing repository with " + logTest.toString());
        //accServ.save(logTest);

        TailerListener listener = new AccessListener();    
        Tailer tailer = new Tailer(new File("D:\\access_log"), listener);        
        tailer.run();
    }

}
package sbx.demo.logauditor.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Service;

import sbx.demo.logauditor.model.AccessRecord;
import sbx.demo.logauditor.repository.AccessRepository;

@Service
@Configurable
public class AccessService {

    @Autowired(required = true)
    AccessRepository accessRepo;

    public void save(AccessRecord ar) {
        try {
            System.out.println("Writing record to database: " + ar.toString());
            accessRepo.save(ar);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public List<AccessRecord> findAll() {
        List<AccessRecord> recList = new ArrayList<AccessRecord>();
        try {
            System.out.println("Searching database for all access records");

            for(AccessRecord ar : accessRepo.findAll()) {
                recList.add(ar);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return recList;
    }
}
package sbx.demo.logauditor.repository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import sbx.demo.logauditor.model.AccessRecord;

@Repository
public interface AccessRepository extends CrudRepository<AccessRecord, Long>{
}
package sbx.demo.logauditor.model; 

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;

@Entity
@Table(name="ACCESS_LOG")
@Data
public class AccessRecord {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;
    @Column(name="PROXY_AGENT")
    private String agent;
    @Column(name="SOURCE_IP")
    private String sourceip;
    @Column(name="ACCESS_TS")
    private Timestamp reqts;
    @Column(name="URI")
    private String requri;
    @Column(name="HTTP_STATUS")
    private String respcode;

    public AccessRecord() {}

    public AccessRecord(String source, Timestamp ts, String uri, String status) {
        this.sourceip = source;
        this.reqts = ts;
        this.requri = uri;
        this.respcode = status;

        try {
            InetAddress ip = InetAddress.getLocalHost();
            String hostname = ip.getHostName();
            this.agent = hostname;
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public String toString() {
        String record = "Record: [" +  agent + "] [" + sourceip + "] [" + reqts +  "] [" + requri +  "] [" + respcode + "]";

        return record;
    }
}
package sbx.demo.logauditor.util;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.transaction.Transactional;

import org.apache.commons.io.input.TailerListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import lombok.var;
import sbx.demo.logauditor.model.AccessRecord;
import sbx.demo.logauditor.repository.AccessRepository;
import sbx.demo.logauditor.service.AccessService;

@Component
public class AccessListener extends TailerListenerAdapter {
    final String regex = "^(\\S+) (\\S+) (\\S+) " + 
            "\\[([\\w:/]+\\s[+\\-]\\d{4})\\] \"(\\S+)" + 
            " (\\S+)\\s*(\\S+)?\\s*\" (\\d{3}) (\\S+)"; 
    final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
    final String datePattern = "dd/MMM/yyyy:HH:mm:ss Z";
    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(datePattern);

    @Autowired
    AccessService accServ;

    @Override
    @Transactional
    public void handle(String line) {
        LogRecorder lr = new LogRecorder();
        try {
            final Matcher matcher = pattern.matcher(line);
            if (matcher.find()) {
                String IP = matcher.group(1);
                //String TS = matcher.group(4);
                String URL = matcher.group(6);
                String STATUS = matcher.group(8);

                LocalDateTime TS = LocalDateTime.from(formatter.parse(matcher.group(4)));


                var ar = new AccessRecord(IP,Timestamp.valueOf(TS),URL,STATUS);
                accServ.save(ar);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }       
    }
}
package sbx.demo.logauditor;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LogauditorApplication {

    public static void main(String[] args) {
        SpringApplication.run(LogauditorApplication.class, args);
    }

}
package sbx.demo.logauditor.util;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.input.TailerListenerAdapter;

import sbx.demo.logauditor.model.AccessRecord;
import sbx.demo.logauditor.service.AccessService;

public class AccessListener extends TailerListenerAdapter {
    final String regex = "^(\\S+) (\\S+) (\\S+) " + 
            "\\[([\\w:/]+\\s[+\\-]\\d{4})\\] \"(\\S+)" + 
            " (\\S+)\\s*(\\S+)?\\s*\" (\\d{3}) (\\S+)"; 
    final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
    final String datePattern = "dd/MMM/yyyy:HH:mm:ss Z";
    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(datePattern);
    private AccessService accServ;

    public AccessListener(AccessService as) {
        this.accServ = as;
    }

//  @Autowired
//  AccessService accServ;

    @Override
    public void handle(String line) {
        try {
            final Matcher matcher = pattern.matcher(line);
            if (matcher.find()) {
                String IP = matcher.group(1);
                String URL = matcher.group(6);
                String STATUS = matcher.group(8);

                LocalDateTime TS = LocalDateTime.from(formatter.parse(matcher.group(4)));


                AccessRecord ar = new AccessRecord(IP,Timestamp.valueOf(TS),URL,STATUS);
                accServ.save(ar);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }       
    }
}