[英]How Spring knows bean to inject with @Bean and method call
我正在尝试使用Spring Framework做一些事情,我想知道当使用Java配置时,Spring如何通过方法调用注入单例依赖?
范例:
@Configuration
public class AppConfiguration {
@Bean
public BlogRepository blogRepository() {
return new BlogRepositoryImpl();
}
@Bean
@Scope("prototype")
public BlogService blogService() {
return new BlogServiceImpl(blogRepository());
}
@Bean
public AuthorService authorService() {
return new AuthorServiceImpl(blogRepository());
}
}
我知道该类也是一个bean,它由Spring代理,但是,由于我从该类内部调用blogRepository()
,因此代理不能处理该调用,因此Spring如何始终获取现有的BlogRepository
单例?
当使用@Configuration
注释类时,使用@Bean
注释的方法由CGLIB
代理包装。
如果它是对此方法的第一次调用,则将执行原始方法的主体并将结果对象存储在Spring
上下文中。 所有后续调用仅返回从上下文中检索到的bean。
是什么让您认为代理无法处理呼叫?
Spring 可以生成类似于此子类的代理:
class AppConfigurationProxy extends AppConfiguration {
private BlogRepository blogRepository;
@Override
public BlogRepository blogRepository() {
if (blogRepository == null)
blogRepository = super.blogRepository();
return blogRepository;
}
// same for the other two @Bean methods
}
现在,无论AppConfiguration
的方法调用它自己的blogRepository()
方法多少次,它都将始终获得相同的对象。
更新:以上证明行之有效。
简单的Bean接口
public interface BlogRepository {
}
public interface BlogService {
}
public interface AuthorService {
}
简单的Bean类
它们没有任何实际逻辑,只是一个toString()
实现可以显示对象的“身份”,类似于类Object
的默认toString()
实现。
public class BlogRepositoryImpl implements BlogRepository {
@Override
public String toString() {
return "BlogRepositoryImpl@" + Integer.toHexString(hashCode());
}
}
public class BlogServiceImpl implements BlogService {
private BlogRepository blogRepository;
public BlogServiceImpl(BlogRepository blogRepository) {
this.blogRepository = blogRepository;
}
@Override
public String toString() {
return "BlogServiceImpl@" + Integer.toHexString(hashCode()) + "[blogRepository=" + this.blogRepository + "]";
}
}
public class AuthorServiceImpl implements AuthorService {
private BlogRepository blogRepository;
public AuthorServiceImpl(BlogRepository blogRepository) {
this.blogRepository = blogRepository;
}
@Override
public String toString() {
return "AuthorServiceImpl@" + Integer.toHexString(hashCode()) + "[blogRepository=" + this.blogRepository + "]";
}
}
配置类
如问题中所定义。
public class AppConfiguration {
public BlogRepository blogRepository() {
return new BlogRepositoryImpl();
}
public BlogService blogService() {
return new BlogServiceImpl(blogRepository());
}
public AuthorService authorService() {
return new AuthorServiceImpl(blogRepository());
}
}
像String这样的代理类可能已经实现了它
与答案顶部相同,仅使用所有方法即可完成。
public class AppConfigurationProxy extends AppConfiguration {
private BlogRepository blogRepository;
private BlogService blogService;
private AuthorService authorService;
@Override
public BlogRepository blogRepository() {
if (this.blogRepository == null)
this.blogRepository = super.blogRepository();
return this.blogRepository;
}
@Override
public BlogService blogService() {
if (this.blogService == null)
this.blogService = super.blogService();
return this.blogService;
}
@Override
public AuthorService authorService() {
if (this.authorService == null)
this.authorService = super.authorService();
return this.authorService;
}
}
测试
public class Test {
public static void main(String[] args) {
// Show result without proxy
AppConfiguration config = new AppConfiguration();
System.out.println(config.blogRepository());
System.out.println(config.blogService());
System.out.println(config.authorService());
// Show how only one BlogRepository is craeted when proxy is used
config = new AppConfigurationProxy();
System.out.println(config.blogRepository());
System.out.println(config.blogService());
System.out.println(config.authorService());
}
}
输出量
BlogRepositoryImpl@1e81f4dc
BlogServiceImpl@7960847b[blogRepository=BlogRepositoryImpl@6a6824be]
AuthorServiceImpl@2c13da15[blogRepository=BlogRepositoryImpl@77556fd]
BlogRepositoryImpl@9e89d68
BlogServiceImpl@3b192d32[blogRepository=BlogRepositoryImpl@9e89d68]
AuthorServiceImpl@16f65612[blogRepository=BlogRepositoryImpl@9e89d68]
可以看出,第一部分没有使用代理,最后以BlogRepositoryImpl
3个不同实例BlogRepositoryImpl
。
通过使用代理的,只有一个实例BlogRepositoryImpl
创建和共享即使blogService()
调用blogRepository()
“直接”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.