10

I have a runnable task where i am trying to Autowire field but when i do it the task doesn't run . When i Autowire the field outside the runnable it works fine . Why is this happening ? Also is there any other cleaner way to get new instances of a autowired field inside runnable other than Autowiring it inside ?

Here's my runnable method `

Runnable task = new Runnable() {

                @Autowired
                ICruxPanelClientService CruxPanelClientService;

                public void run (){
            CruxPanelClientService.setCruxWebServiceBaseURL("http://10.41.181.23:8080");
            CronCruxModel m = new CronCruxModel();
            m = model1.get(model_var);
            System.out.println("EXECUTING");
            System.out.println(m.getService_status() + " ---------EXEexecution");
            System.out.println(m.getCat_name() + "Executing Name ");
        //  time = m.getService_time();
            UpdateCategoryRequest updateCategoryRequest = new UpdateCategoryRequest();
            CategoryModel categoryModel = new CategoryModel();
            categoryModel.setColor(m.getCat_color());
            categoryModel.setIcon(m.getCat_icon());
            categoryModel.setIconWhite(m.getCat_icon_white());
            categoryModel.setName(m.getCat_name());
            categoryModel.setId(m.getCat_id());
            categoryModel.setKey(m.getCat_catkey());
            categoryModel.setIndexOrder(m.getCat_indexOrder());
            updateCategoryRequest.setCategory(categoryModel);
            CruxPanelClientService.updateCategory(updateCategoryRequest);
            GetServiceDataIdByCategoryIdRequest request1 = new GetServiceDataIdByCategoryIdRequest();    
            request1.setId(m.getCat_id());
            GetServiceDataIdByCategoryIdResponse response1 = CruxPanelClientService.getServiceDataIdByCategoryId(request1);
            ArrayList<ServiceModel> service = new ArrayList<ServiceModel>();
            service = response1.getServiceModels();

            JSONArray json = new JSONArray();
            if(m.getService_order_succ_msg()==null)
            {
                json = new JSONArray();
            }
            else {

                 json = new JSONArray(m.getService_order_succ_msg());
            }
            String message = m.getService_order_succ_msg();

            for (int j=0;j<service.size();j++)
            {   
                UpdateServiceMasterRequest req = new UpdateServiceMasterRequest();
                ServiceModel s = new ServiceModel();
                s=service.get(j);
                ;
                JSONObject obj = new JSONObject();

                if(json.length()==0 ) 
                {
                    String ms = null;
                    s.setOrderSuccessMessage(ms);
                    req.setServiceModel(s);

                }

                else {

                    String message1 = json.get(j).toString();

                    if(message1.equals(null) || message1.equals("")) {
                        String ms = null;
                        s.setOrderSuccessMessage(ms);
                        req.setServiceModel(s);

                    }
                    else {
                        s.setOrderSuccessMessage(message1);

                        req.setServiceModel(s);

                    }
                }
                CruxPanelClientService.updateServiceMaster(req);

            }
            m.setService_status("executed");
            UpdateCronCruxRequest q = new UpdateCronCruxRequest();
            q.setCronCruxModel(m);
            CruxPanelClientService.updateCronCrux(q);

                }
            };`
Evan Root
  • 279
  • 1
  • 5
  • 19

4 Answers4

15

The problem is spring doesn't control creation of your runnable. There are couple possible solutions:

  1. Put you runnable creation in some service, repository, controller, component or what ever handled by spring:

Example:

@Service
public class SomeService {

    @Autowired
    private ICruxPanelClientService cruxPanelClientService;

    public Runnable newRunnable() {

        return new Runnable() {

            public void run() {
                cruxPanelClientService <- will be visible here and injected
            }
        }
    }

}
  1. Create runnable as bean with prototype scope

Example:

@Configuration
public class Runnableconfiguration {

    @Bean
    @Scope("prototype")
    public Runnable newRunnbale(final ICruxPanelClientService cruxPanelClientService) {
        return new Runnable() {
            public void run() {
                cruxPanelClientService <- will be visible here
            }
        }
    }
}
alexey28
  • 5,170
  • 1
  • 20
  • 25
5

@Autowire can't be used for anonymous classes (because you call new, not Spring), you can autowire a field in outer class and then use that field inside your Runnable.

Or make the Runnable a full blown class (not anonymous) and make it a bean (and autowire, e.g. using the id)

Krzysztof Krasoń
  • 26,515
  • 16
  • 89
  • 115
  • 1
    If `Runnable` is defined as full blown class, it needs to be declared as bean to make `@Autowire` work, and in this case the bean scope should be `Prototype`. So you need to autowire prototype bean in the singleton bean then, here are some details how to do it: http://stackoverflow.com/questions/14880847/howto-generate-prototype-objects-with-in-a-singleton-bean-using-spring-java-conf/14881193#14881193 – Vladimir Vagaytsev Jun 25 '16 at 08:55
3

Spring does not @autowire anything into unmanaged instances (instances you create with new, in contrast to instances created and managed by Spring).

This leaves you following options:

  • @autowire the dependency outside and pass it to the Runnable (or make it accessible to the Runnable).
  • create a new class subclassing Runnable, and @autowire it where you need it.
  • Instead of having the dependency injected, look it up (applicationContext.getBean(..)) when needing it.

Be careful with scopes and lazy initialization when using Threads, as some of the Spring scopes (e.g. "request" or "session" scope) are thread-local bound (e.g. when using a lazy request-scoped dependency in a new Thread, which when executed is no longer associated with the current request).

Peter Walser
  • 15,208
  • 4
  • 51
  • 78
0

In addition to all mentioned above, maybe it is better to inject the service from outside your runnable and not use @Autowired inside your runnable. So in your case:

Runnable task = new Runnable() {

                @Autowired
                ICruxPanelClientService CruxPanelClientService;

would become:

@Autowired
private ICruxPanelClientService CruxPanelClientService;

Runnable task = new Runnable() {
...
}             
ACV
  • 9,964
  • 5
  • 76
  • 81