2

I am trying to autowire SQSFIFOJavaClient under the appender that I have created. I printed out the bean names that are defined in Spring Boot main class and I am able to see SQSFIFOJavaClient bean defined. However the bean is not being autowired in the below listed class. Both SQSAppender and SQSFIFOJavaClient are in different packages but are under the same base package which is added to component-scan. Can you please tell me what I am missing here?

@Component
@DependsOn("SQSFIFOJavaClient")
public class SQSAppender extends AppenderBase<ILoggingEvent> {

    @Autowired
    private SQSFIFOJavaClient sqsClient;

I tried adding DependsOn annotation as well , but still sqsClient is displayed as null.

Punter Vicky
  • 15,954
  • 56
  • 188
  • 315
  • Just in case you did not already check ; Do you use static method ? Do you instanciate it somewhere with a `new sqsClient() ` ? Where do you log sqsClient ? – NayoR Apr 23 '18 at 18:27
  • Thank @NayoR. No , I am not instantiating it with new sqsClient(). – Punter Vicky Apr 23 '18 at 18:28

3 Answers3

2

Log4j2 will create an appender by calling @PluginFactory annotated method (as per this answer). Your appender is probably not created as a Spring bean there, most likely new SQSAppender(...) is called, and @Autowired is not processed.

An example of how to implement a Spring-managed Log4j2 appender can be found in org.springframework.amqp.rabbit.log4j2.AmqpAppender.

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
0

The appender is created before spring initialization. This is the solution I found:

MyCustomAppender.java:

@Plugin(name = "MyCustomAppender", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE)
public class MyCustomAppender extends AbstractAppender {
  ...
  private static MyBean myBean;

  public static void setMyBean(MyBean myBean) {
      MyCustomAppender.MyBean = myBean;
  }

  @PluginFactory
  public static MyCustomAppender createAppender(
        @PluginAttribute("name") String name,
        @PluginAttribute("ignoreExceptions") boolean ignoreExceptions,
        @PluginElement("Layout") Layout layout,
        @PluginElement("Filters") Filter filter,
        @PluginElement("Properties") Property[] properties) {
      return new MyCustomAppender(name, filter, layout, ignoreExceptions, properties);
  }

  @Override
  public void append(LogEvent event) {
      if (myBean != null) {
          myBean.doSomething();
      }
  }

MyBean.java:

@Component
public class MyBean {
  ...
  @PostConstruct
  public void init() {
      MyCustomAppender.setMyBean(this);
  }
  ...
}
0

Additional solution:

MyServiceApplicationContext.java:

@Service
public class MyServiceApplicationContext implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return context;
    }
}

MyCustomAppender.java:

@Plugin(name = "MyCustomAppender", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE)
public class MyCustomAppender extends AbstractAppender {
  
  private MyBean myBean;

  protected MyCustomAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, Property[] properties) {
    super(name, filter, layout, ignoreExceptions, properties);
}

  @PluginFactory
  public static MyCustomAppender createAppender(
        @PluginAttribute("name") String name,
        @PluginAttribute("ignoreExceptions") boolean ignoreExceptions,
        @PluginElement("Layout") Layout layout,
        @PluginElement("Filters") Filter filter,
        @PluginElement("Properties") Property[] properties) {
      return new MyCustomAppender(name, filter, layout, ignoreExceptions, properties);
  }

  @Override
  public void append(LogEvent event) {
      if (myBean == null) {
        // the appender is called before spring initialization
        ApplicationContext context = MyServiceApplicationContext.getApplicationContext();
        if (context != null) {
            myBean = context.getBean(MyBean.class);
        }
    
    }
      if (myBean != null) {
          myBean.doSomething();
      }
  }