Here is my code:
@SpringBootApplication
public abstract class DIApp {
public static void main(String[] args) {
SpringApplication.run(DIApp.class);
}
@Bean
@Scope("prototype")
public HelloService helloService(){
return new HelloService() {
@Override
public void print(String name) {
System.out.println("hello:"+name);
}
};
}
@Bean
CommandLineRunner run2(){
return args -> {
for (int i = 0; i < 5; i++) {
HelloService service = helloService();
service.print("prototype@"+service);
}
};
}
}
it works fine. for every call, a new HelloService instance is created. but, after i changing HelloService bean to lamda style, it's not ok:
@Bean
@Scope("prototype")
public HelloService helloService(){
return name -> System.out.println("hello:"+name);
}
Does lamda not surpport prototype scope?
Comment From: hhfdna
HelloService is just a plain interface:
public interface HelloService {
void print(String name);
}
Comment From: quaff
works fine with latest version 5.3.2, but every created instance is identical, I think it's reused by JVM not spring.
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
public class Main {
public static void main(String[] args) throws Exception {
try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfiguration.class)) {
System.out.println(ctx.getBean(Service.class));
//printed: Main$MyConfiguration$$Lambda$69/1658926803@1d548a08
}
}
@Configuration
@ComponentScan
static class MyConfiguration {
@Bean
@Scope("prototype")
public Service service() {
return () -> {
};
}
}
static interface Service {
void test();
}
}
Comment From: quaff
Very interesting, lambda expression will be identical, but method reference will not.
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
public class Main {
public static void main(String[] args) throws Exception {
Service s1 = createService();
Service s2 = createService();
System.out.println(s1 == s2); // true created by lambda expression
try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfiguration.class)) {
Service service1 = ctx.getBean(Service.class);
Service service2 = ctx.getBean(Service.class);
System.out.println(service1 == service2); // false created by method reference
}
}
static Service createService() {
return s -> {
System.out.println(s);
};
}
@Configuration
@ComponentScan
static class MyConfiguration {
@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Service service() {
return System.out::println;
}
}
static interface Service {
void print(String name);
}
}
Comment From: mdeinum
This is due to method-references being treated differently then lambda expression by the compiler/runtime are handled.
See: https://stackoverflow.com/a/29290314/2696260
Comment From: quaff
This is due to method-references being treated differently then lambda expression by the compiler/runtime are handled.
See: https://stackoverflow.com/a/29290314/2696260
Thanks, but it still not explain such difference.
Comment From: hhfdna
so, the conclusion is that if i want a prototype-scoped bean, anonymouse inner class and method reference works, but lamda can't? but why?
Comment From: hhfdna
for inner anonymouse class:
@Bean
@Scope("prototype")
public HelloService helloService(){
return new HelloService() {
@Override
public void print(String name) {
System.out.println("hello:"+name);
}
};
}
i get defferent instances for every call:
hello:prototype@com.bocsoft.demo.DIApp$1@35a3d49f
hello:prototype@com.bocsoft.demo.DIApp$1@389b0789
hello:prototype@com.bocsoft.demo.DIApp$1@13d9cbf5
hello:prototype@com.bocsoft.demo.DIApp$1@478db956
hello:prototype@com.bocsoft.demo.DIApp$1@6ca18a14
but for lamda style
@Bean
@Scope("prototype")
public HelloService helloService(){
return name -> System.out.println("hello:"+name);
}
i get the same instance for every call:
hello:prototype@com.bocsoft.demo.DIApp$$Lambda$164/41489123@34b9f960
hello:prototype@com.bocsoft.demo.DIApp$$Lambda$164/41489123@34b9f960
hello:prototype@com.bocsoft.demo.DIApp$$Lambda$164/41489123@34b9f960
hello:prototype@com.bocsoft.demo.DIApp$$Lambda$164/41489123@34b9f960
hello:prototype@com.bocsoft.demo.DIApp$$Lambda$164/41489123@34b9f960
Comment From: quaff
for inner anonymouse class:
java @Bean @Scope("prototype") public HelloService helloService(){ return new HelloService() { @Override public void print(String name) { System.out.println("hello:"+name); } }; }i get defferent instances for every call:
shell hello:prototype@com.bocsoft.demo.DIApp$1@35a3d49f hello:prototype@com.bocsoft.demo.DIApp$1@389b0789 hello:prototype@com.bocsoft.demo.DIApp$1@13d9cbf5 hello:prototype@com.bocsoft.demo.DIApp$1@478db956 hello:prototype@com.bocsoft.demo.DIApp$1@6ca18a14but for lamda style
java @Bean @Scope("prototype") public HelloService helloService(){ return name -> System.out.println("hello:"+name); }i get the same instance for every call:
shell hello:prototype@com.bocsoft.demo.DIApp$$Lambda$164/41489123@34b9f960 hello:prototype@com.bocsoft.demo.DIApp$$Lambda$164/41489123@34b9f960 hello:prototype@com.bocsoft.demo.DIApp$$Lambda$164/41489123@34b9f960 hello:prototype@com.bocsoft.demo.DIApp$$Lambda$164/41489123@34b9f960 hello:prototype@com.bocsoft.demo.DIApp$$Lambda$164/41489123@34b9f960
It's prototype from spring perspective, use method reference or inner class instead if you really care identity.
Comment From: hhfdna
ok, thx @quaff
Comment From: sbrannen
Please note that questions like this are often better suited for Stack Overflow.
Closing this issue since the question has been answered in the comments above.