简体   繁体   中英

How do I inject a logger into a field in the sample spring boot application?

What I want is to make spring autowire a logger. So, in other words, I want to have this working:

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MainController {

    @Autowired
    private Logger logger;
    
    @RequestMapping("/")
    public String enterSite(HttpServletResponse response) {
        logger.info("site entered");
        return "welcome";
    }
}

Right now it throws an exception at startup: "No qualifying bean of type [org.slf4j.Logger] found for dependency...".

My pom.xml dependencies:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.0.M1</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>

        <dependency>
            <groupId>postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.1-901.jdbc4</version>
        </dependency>
        <!-- <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> 
            </dependency> -->
    </dependencies>

I read this: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-logging

It says if you use one of the starter poms (I do) Logback is used - but for internal logging. Can it be autowired in my classes?

If the objective here is code reduction then try Project Lombok . You then don't even need to declare the logger - just add an annotation and use log instead of logger

So your above code will now look like this:

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
// import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
public class MainController {

    @RequestMapping("/")
    public String enterSite(HttpServletResponse response) {
        log.info("site entered");
        return "welcome";
    }
}

Although it is not the usual way you can add a logger bean directly in your context reproducing the classic bind:

private final Logger logger = LoggerFactory.getLogger(MainController.class);

simply inserting in the spring context:

<bean id="logger" scope="prototype" class="org.slf4j.LoggerFactory" factory-method="getLogger">
    <constructor-arg name="name" value="youLoggerName" />
</bean>

then you can simply inject your logger:

@Autowired
private Logger logger;

Solution using @Bean :

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class LoggerConfiguration {

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Logger logger(InjectionPoint injectionPoint){
        return LoggerFactory.getLogger(injectionPoint.getMethodParameter().getContainingClass());
    }

}

After that, just inject the Logger using Constructor Injection ( field injection will not work ):

@Service
class SomeService {

    private Logger logger;

    public SomeService(Logger logger;) {
        this.logger = logger;
    }

    public void someMethod() {
        logger.error("Some log");
    }  
}

You can have Spring autowire a Logger instance, but it would be a very unusual thing to do (you'd need a bean of type Logger to be in your application context). The far more usual approach is to initialise the logger where it's declared, configuring it with the class that will be using it for logging:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MainController {

    private final Logger logger = LoggerFactory.getLogger(MainController.class);

}

This is how I got it working for field injection

LoggingConfiguration.java

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

    @Configuration
    public class LoggingConfiguration {

        @Bean
        public Logger log() {
            var log = LoggerFactory.getLogger("com.bitsmonkey.dummy");
            return log;
        }
    }

Now inside the controller

DummyController.java

@Controller
public class DummyController {

@Autowired
private Logger log;

//......

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM