I wanna make a logging system using HTTP requests and responses. After processing some data, I want to finally save it to the database. But repository injection is not possible.
class LogFilter() : OncePerRequestFilter() {
private val log: Logger = LoggerFactory.getLogger(LogFilter::class.java)
// @Autowired
// lateinit var actionLogRepository: ActionLogRepository // <- injection failed
@Throws(ServletException::class, IOException::class)
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain,
) {
val uri = request.requestURI
var contentRequest = request
var contentResponse = response
if (uri.startsWith("/swagger-ui", true) ||
uri.startsWith("/v3/api-docs", true)
|| uri.startsWith("/api/health-check", true)
) {
filterChain.doFilter(request, response)
return
}
val start: Long = System.currentTimeMillis()
try {
contentRequest = ContentCachingRequestWrapper(request)
contentResponse = ContentCachingResponseWrapper(response)
filterChain.doFilter(contentRequest, contentResponse)
} finally {
val actionLog = ActionLog()
logRequest(contentRequest, actionLog)
logResponse(contentRequest, contentResponse, actionLog)
actionLog.saveSpentTime(System.currentTimeMillis() - start)
// actionLogRepository.save(actionLog) // <- it's face error by null injection
}
}
fun logRequest(request: HttpServletRequest, actionLog: ActionLog)
fun logResponse(request: HttpServletRequest, actionLog: ActionLog)
}
I can't even do constructor injection. How can this work?
CodePudding user response:
There is not much code, but what I can see is that there is no @Component
annotation here.
You have to add this class to Spring context, so the Spring can find it, and inject dependencies. There is couple of ways to do that. In your case, I would prefer the first option:
- The simplest way is to mark this class with
@Component
annotation. Then Spring will find the class, create an instance and make any required dependency injection. - You can create
@Configuration
class with@Bean
method. In this method you can create an instance of your filter. In this case, you can make some initial configuration to the created class if required. But in this case, you have to inject the dependency to this filter by yourself. Spring can inject it to your@Configuration
class or method parameter, example:
@Configuration
public class LoggingFilterConfig {
@Bean
fun createLogFilter(actionLogRepository: ActionLogRepository): LogFilter {
return LogFilter(actionLogRepository)
}
}
The method parameter actionLogRepository
will be injected by Spring.
As a side note, I can add, that marking the field with @Autowired
annotation is not the preferred way of doing dependency injection. If the dependency is required better make it through constructor (in this case, you don't have to mark it as @Autowired
)
CodePudding user response:
I understand that you are reading data from the server and trying to write it to the database. But you need to upload your specific example because of the complexity. You should create your example on github and tag it in the question