[SPRING] 자바 주석을 사용하여 로거 의존성 삽입
SPRING자바 주석을 사용하여 로거 의존성 삽입
@Loggable 어노테이션을 허용하기 위해 aspect-j 어노테이션 지원과 함께 spring을 사용하고있다. 이렇게하면 구성에 따라 클래스에 자동 로깅이 가능합니다.
어떻게 든이 주석을 사용하여 slf4j 로거 변수를 직접 사용하기 위해 클래스에 노출시킬 수 있는지 궁금해서 그 결과를 위해 뭔가 할 필요가 없습니다.
Logger logger = LoggerFactory.getLogger(MyClass.class);
주석이 주석으로 인해 위와 같이 암시 적으로 사용 가능하면 logger.debug ( "...")를 수행하면 좋을 것입니다. 선언없이. 이것이 가능한지 확실하지 않습니다.
해결법
-
==============================
1.BeanPostProcessor 인터페이스를 사용할 수 있습니다.이 인터페이스는 작성된 모든 bean에 대해 ApplicationContext에서 호출되므로 적절한 특성을 채울 수 있습니다.
BeanPostProcessor 인터페이스를 사용할 수 있습니다.이 인터페이스는 작성된 모든 bean에 대해 ApplicationContext에서 호출되므로 적절한 특성을 채울 수 있습니다.
나는 다음과 같은 간단한 구현을 만들었다.
import java.lang.reflect.Field; import java.util.List; import net.vidageek.mirror.dsl.Mirror; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; @Component public class LoggerPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { List<Field> fields = new Mirror().on(bean.getClass()).reflectAll().fields(); for (Field field : fields) { if (Logger.class.isAssignableFrom(field.getType()) && new Mirror().on(field).reflect().annotation(InjectLogger.class) != null) { new Mirror().on(bean).set().field(field).withValue(LoggerFactory.getLogger(bean.getClass())); } } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
ApplicationContext는 BeanPostProcessor 인스턴스를 인식하고 자동으로 등록 할 수 있기 때문에 복잡한 등록 단계를 수행 할 필요가 없습니다.
@InjectLogger 주석은 다음과 같습니다.
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface InjectLogger { }
그런 다음 주석을 쉽게 사용할 수 있습니다.
public static @InjectLogger Logger LOGGER; ... LOGGER.info("Testing message");
미러 라이브러리를 사용하여 주석 필드를 찾았지만이 추가 종속성을 피하기 위해 수동 조회를 수행 할 수도 있습니다.
실제로 반복되는 코드는 피하는 것이 좋습니다. 클래스 매개 변수를 변경하는 것을 잊어 버린 경우와 같이 잘못된 로그로 연결되는 경우와 같이 다른 클래스의 로거 정의를 복사하여 붙여 넣는 작은 문제도 있습니다.
-
==============================
2.당신은 어떤면에서 그것을 할 수는 없지만, 롬 보크는 제 생각에 우아한 방식으로 당신을 도울 수 있습니다. @Log 주석을 참조하십시오.
당신은 어떤면에서 그것을 할 수는 없지만, 롬 보크는 제 생각에 우아한 방식으로 당신을 도울 수 있습니다. @Log 주석을 참조하십시오.
-
==============================
3.@Redder의 해결책은 이것을하는 좋은 방법이라고 생각합니다. 그러나 미러 라이브러리를 포함하고 싶지 않았으므로 대신 Java 반영 라이브러리를 사용하는 LoggerPostProcessor 구현을 작성했습니다. 여기있어:
@Redder의 해결책은 이것을하는 좋은 방법이라고 생각합니다. 그러나 미러 라이브러리를 포함하고 싶지 않았으므로 대신 Java 반영 라이브러리를 사용하는 LoggerPostProcessor 구현을 작성했습니다. 여기있어:
package com.example.spring.postProcessor; import com.example.annotation.InjectLogger; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; @Component public class LoggerPostProcessor implements BeanPostProcessor { private static Logger logger = LoggerFactory.getLogger(LoggerPostProcessor.class); /* (non-Javadoc) * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String) */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { List<Field> fields = Arrays.asList(bean.getClass().getDeclaredFields()); for (Field field : fields) { if (Logger.class.isAssignableFrom(field.getType()) && field.getAnnotation(InjectLogger.class) != null) { logger.debug("Attempting to inject a SLF4J logger on bean: " + bean.getClass()); if (field != null && (field.getModifiers() & Modifier.STATIC) == 0) { field.setAccessible(true); try { field.set(bean, LoggerFactory.getLogger(bean.getClass())); logger.debug("Successfully injected a SLF4J logger on bean: " + bean.getClass()); } catch (IllegalArgumentException e) { logger.warn("Could not inject logger for class: " + bean.getClass(), e); } catch (IllegalAccessException e) { logger.warn("Could not inject logger for class: " + bean.getClass(), e); } } } } return bean; } /* (non-Javadoc) * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
-
==============================
4.@ Redder의 솔루션을 약간 개선하고 싶습니다.
@ Redder의 솔루션을 약간 개선하고 싶습니다.
여기 예제 (Java 8에서는 Java 7 / 6 / etc로 다시 작성할 수 있지만 slf4j facade도 사용되지만 다른 로거로 대체 될 수 있음) :
@Component public class LoggerPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { Logger logger = getLogger(bean.getClass()); doWithFields(bean.getClass(), field -> { makeAccessible(field); setField(field, bean, logger); }, field -> field.isAnnotationPresent(Autowired.class) && Logger.class.equals(field.getType())); return bean; } ... } ... //logger injection candidate @Autowired(required = false) private Logger log;
-
==============================
5.CDI (JSR 299 : Context and Dependency Injection)에서 똑같은 일을 시도 할 때이 결과를 얻었으므로,이 링크는 CDI (그리고 Spring을 사용하는 대안)를 사용하여이를 수행하는 간단한 방법을 보여줍니다.
CDI (JSR 299 : Context and Dependency Injection)에서 똑같은 일을 시도 할 때이 결과를 얻었으므로,이 링크는 CDI (그리고 Spring을 사용하는 대안)를 사용하여이를 수행하는 간단한 방법을 보여줍니다.
기본적으로, 당신은 단지 주입해야합니다 :
class MyClass { @Inject private Log log;
로거 팩토리를 다음과 같이 설정하십시오.
@Singleton public class LoggerFactory implements Serializable { private static final long serialVersionUID = 1L; static final Log log = LogFactory.getLog(LoggerFactory.class); @Produces Log createLogger(InjectionPoint injectionPoint) { String name = injectionPoint.getMember().getDeclaringClass().getName(); log.debug("creating Log instance for injecting into " + name); return LogFactory.getLog(name); } }
나는 내가 주입 된 로그에 일시적 (transient)을 추가 할 필요가 있다는 것을 발견했다. 그래서 세션 범위가 제한된 bean에서 비활성화 영역 예외를 얻지 못했다.
@Named() @SessionScoped() public class MyBean implements Serializable { private static final long serialVersionUID = 1L; @Inject private transient Log log;
-
==============================
6.다음은 모든 코드를 포함하는 완전한 예제가 포함 된 블로그 게시물입니다. Spring을 사용하여 로거 삽입
다음은 모든 코드를 포함하는 완전한 예제가 포함 된 블로그 게시물입니다. Spring을 사용하여 로거 삽입
-
==============================
7.Herald는 모든 마술을 처리하는 매우 간단한 BeanPostProcessor를 제공합니다. Herald가이 필드에서 적절한 로거를 삽입 할 수 있도록 @Log 주석으로 봄 빈의 모든 필드에 주석을 달 수 있습니다.
Herald는 모든 마술을 처리하는 매우 간단한 BeanPostProcessor를 제공합니다. Herald가이 필드에서 적절한 로거를 삽입 할 수 있도록 @Log 주석으로 봄 빈의 모든 필드에 주석을 달 수 있습니다.
지원되는 로깅 프레임 워크 :
다른 로깅 프레임 워크를 추가하는 것도 가능합니다.
Github 레포 : https://github.com/vbauer/herald
from https://stackoverflow.com/questions/6351082/using-java-annotation-to-inject-logger-dependency by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring, JPA, Hibernate - 동시성 문제없이 카운터를 증가시키는 방법 (0) | 2019.03.03 |
---|---|
[SPRING] Spring의 계층 구조를 사용하고 객체 지향 구조를 따르는 법? (0) | 2019.03.03 |
[SPRING] GWT 애플리케이션을위한 REST 백엔드를 빌드해야합니까? (0) | 2019.03.03 |
[SPRING] 봄 mvc 양식에서 얻은 모든 문자열을 다듬을 수 있습니까? (0) | 2019.03.03 |
[SPRING] Spring Boot - 클래스 경로 자원에 정의 된 이름 'dataSource'로 bean 생성 오류 (0) | 2019.03.03 |