1

I have a class that gets created within server startup. It serves as entry method for the client application. I cannot change this behaviour.

Though I'd like to use Spring @Autowired inside this unmanaged class. I read that aspectj weaving might be the way to go. It seems to already execute accoding to logs:

2014-01-28 13:11:10,156 INFO org.springframework.context.weaving.DefaultContextLoadTimeWeaver: Using a reflective load-time weaver for class loader: org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader

But still my injected Dao service is null. What might be missing?

@WebListener
public class MyContextListener implements ServletContextListener {
        @Override
            public void contextInitialized(ServletContextEvent sce) {
            new TestService().run(); //throws NPE
        }
}

@Configurable
class TestService extends AbstractLegacyService {       
    @Autowired
    private Dao dao;

    @Override
    public void run() {
        //dao is always null
        dao.find();
    }
}


@Component
class Doa dao;

enable weaving (tomcat):

@Configuration
@EnableLoadTimeWeaving
@EnableSpringConfigured
public class AppConfig {
}
membersound
  • 81,582
  • 193
  • 585
  • 1,120
  • Can you show the `web.xml`? Especially the part where the context listeners are registered. – René Link Jan 28 '14 at 12:58
  • it's registered by annotation. The web.xml does not define any listeners. – membersound Jan 28 '14 at 13:01
  • I think you still need to have a bean definition for TestService to use as a template. Also don't forget your component scan. – Sotirios Delimanolis Jan 28 '14 at 13:03
  • @SotiriosDelimanolis OP uses the load-time weaver. The load-time weaver injects objects created with the `new` operator if the are `@Configurable`. It's for bean whose lifecycle is managed outside the spring container. – René Link Jan 28 '14 at 13:13
  • @RenéLink And according to the [documentation](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-atconfigurable) `Spring will configure new instances of the annotated type ( Account in this case) using a bean definition (typically prototype-scoped) with the same name as the fully-qualified type name ( com.xyz.myapp.domain.Account).` – Sotirios Delimanolis Jan 28 '14 at 13:16
  • @RenéLink Also, `@ComponentScan` is missing so `@Autowired` wouldn't be picked up. – Sotirios Delimanolis Jan 28 '14 at 13:16
  • Of course `Dao` is annotated with `@Component` so it should be picked up by spring. – membersound Jan 28 '14 at 13:38
  • @SotiriosDelimanolis I just tried a small setup with a main class, a spring context xml (without component scan) and an bean like the one defined by membersound (@Configurable, @Autowired) and it works. Sadly I have not way to show you that code since this questions is not about this. – René Link Jan 28 '14 at 13:38
  • @RenéLink I'll try it when I get to work as well. – Sotirios Delimanolis Jan 28 '14 at 13:44
  • @SotiriosDelimanolis Ok. Do you know if there is another way to share some code on stackoverflow than through questions? – René Link Jan 28 '14 at 13:46
  • @RenéLink Made a chat room: http://chat.stackoverflow.com/rooms/46240/spring-load-time-weaving – Sotirios Delimanolis Jan 28 '14 at 13:48
  • @membersound I think your problem has something to do with the listener order. If the `MyContextListener`s `contextInitialized` gets invoked before the `ContextLoaderListener` has a chance to start the spring container than the LTW can not access the spring container. I m not really sure but I would give it a try. Maybe you can set breakpoints in `ContextLoaderListener` and `MyContextListener`. Then you will see which one gets invoked first. – René Link Jan 28 '14 at 13:50
  • Maybe we're getting closer with this: I don't have any `ContextLoaderListener` defined. Only listener defined is the `@WebListener`. But I think `@Configuration` is the annotation-based replacement for `ContextLoaderListener`? – membersound Jan 28 '14 at 13:51
  • @membersound come to the chat that Sotirios Delimanolis opened – René Link Jan 28 '14 at 13:59

1 Answers1

1

You must make sure that the ContextLoaderListener is invoked before the MyContextListener gets invoked.

The ContextLoaderListener initializes the spring container and the load-time weaver can only inject the dependencies of the TestService if the spring container is initialized.

René Link
  • 48,224
  • 13
  • 108
  • 140
  • 1
    I just discovered that if I change the implementation to `@WebListener class MyContextListener extends ContextLoaderListener` and override init & destroy methods accordingly similar to my post, the whole spring injection just works as expected. – membersound Jan 28 '14 at 14:16
  • 1
    Yes ok, that is also a solution. Depending on what the `MyContextListener` does and if you want to use it in another context (maybe a non spring context) it makes sense to extend from `ContextLoaderListener` or not. – René Link Jan 28 '14 at 14:20