Java Spring JPA Crudepository Autowired对象与Apache Commons Tailer一起使用时为空
我正在开发一个小应用程序,可以指向ApacheHTTP服务器日志,在Linux中跟踪日志a la'tail-f',并将条目写入Oracle数据库表 我设置了Spring Boot/Spring Data JPA应用程序,并为我的实体、Crudepository接口、接口服务创建了类,尽管我认为这在技术上对该实现是不必要的,并且创建了启动该过程的运行程序。我还设置了TailerListenerAdapter来执行日志文件解析的提升。我将在下面发布所有这些代码 问题是,在启动Tailer侦听器之前,我可以成功地将测试记录写入数据库。但是,当侦听器运行时,TailerListenerAdapter中的自动连线服务为null并引发异常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侦听器之前,
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();
}
}
}