3

How can I do to invoke methods in one service each other by spring?

I have one Service, I make it manage by spring by annotation @Service, but I found In this service, methods invoke each other is not manage by spring, So some annotation in spring I use makes no sense.

@Service
class Service {

    method a(){
        b(); // it's not invoked by spring, actually, it's invoked in a common way
    }

    method b(){
    }
}

It's work by using SpringContextHolder.getBean(Service.class).b();.But I wanna to know there is a more convenient way ?

Thank you very much.


update

I found something confused. It's ok to inject itself eventually. And I found something wrong when I use my custom annotation @LogTime over a method, which results in the inject component is null !!!!!

for example:

 //  @LogTime
  public Response execute(Request request) {
    try {
      return okHttp.client.newCall(request).execute();
    } catch (IOException e) {
      log.error("OkHttp wrong", e);
      throw new SystemException("OkHttp wrong", e);
    }
  }

When I use @LogTime annotation I created over this method, the client component is null!!!!!!


update finally

@Component
public class OkHttp {

  private final OkHttpClient client;
  private final OkHttp okHttp;

  public OkHttp(OkHttpClient client, @Lazy OkHttp okHttp) {
    this.client = client;
    this.okHttp = okHttp;
  }
}

summarize:

It's ok to inject self, but it's not ok to use okHttp.client.method(). the okHttp.client is null and client is not null, It's ok to replace okHttp.client.method with client.method() directly. the client is managed by spring, so we can achieve the same goal.

Linuxea
  • 319
  • 1
  • 4
  • 15
  • When do you want `a()` and `b()` to be called? Also do not include `method` in your sources, it is invalid in Java (unless `method` is a return type, but if so it should be capitalised) – cameron1024 Aug 14 '19 at 10:21
  • I don't know why when I inject itself, other inject component all failed (all is null) – Linuxea Aug 14 '19 at 10:32
  • 2
    This sounds like an error in your spring configuration. Check that your components are being scanned `@ComponentScan` annotation. – cameron1024 Aug 14 '19 at 10:33
  • But I do not inject itself then other services is ok – Linuxea Aug 14 '19 at 10:40
  • 3
    In my understanding you are referring to this problem: https://stackoverflow.com/q/3423972/5118762 – brass monkey Aug 14 '19 at 11:00

2 Answers2

2

I found In this service, methods invoke each other is not manage by spring

You need to understand that Spring manages objects and calls made to methods of those objects via proxies ( read official documentation here for more details. In this documentation you will get to know the reason why method to method calls within same class is not "managed" ). These proxies can differ in that they can be Dynamic, CGlib or any other depending on how they are created. You can mentally imagine a proxy in between whenever there is spring managed class method calling another spring managed different class method. However in case of a method calling another method of same class it's pure method call without proxy because there is no opportunity to intercept the call and add behavior.

Shailendra
  • 8,874
  • 2
  • 28
  • 37
  • Yeah, I understand now. thank you. I think It's very natural to combine spring with java at first so I do that. Now I think there are some questions need to be considered when using spring and the code not pure. – Linuxea Aug 15 '19 at 03:45
1

The common way is to use dependency injection, e.g. with @Autowired:

@Service
class MyService {

  @Autowired
  MyService thisService;  // inject a service itself

  public void a() {
    thisService.b();    // now, `b` will be called in a transaction
  }

  @Transactional
  public void b() {
    // ...
  } 

}

Though, this is a poor design: such bean cannot live outside a container.

Alex Salauyou
  • 14,185
  • 5
  • 45
  • 67
  • Injecting a service into itself this way is not necessary. Method `a` can just call method `b` directly; if the service is a Spring bean (i.e. not an unmanaged object created with `new Service`) then this will work normally. – Jesper Aug 14 '19 at 10:37
  • It doesn't work, even if I use setter inject to avoid dependency cycle. – Linuxea Aug 14 '19 at 10:37
  • @Linuxea you have a wrong configuration. I've tested the approach and it works fine – Alex Salauyou Aug 14 '19 at 10:40
  • @Jesper no, it won't. In proxied beans, will be called methods of delegate, not proxy. Annotations like `@ExceptionHandler`, `@Transactional` and so on won't work – Alex Salauyou Aug 14 '19 at 10:57
  • @AlexSalauyou your solution doesn't make any sense!. – Vinay Hegde Aug 14 '19 at 10:58
  • 1
    It is his prerogative to decide whether he feels confident to propose a certain solution or not. It will be the reader's prerogative to decide which solution to propose and to upvote or downvote based on whether the solution works or not. His solution (even though it's generally considered poor design) has been successfully proposed in the past. Do not turn the comments section into a fight, please. – Filippo Possenti Aug 14 '19 at 11:22
  • @AlexSalauyou you are right. And I will update question. Thank u – Linuxea Aug 15 '19 at 03:42