我正在尝试使用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()
单例,因此代理可以呢?无法接听电话?
答案 0 :(得分:2)
用@Configuration
注释类时,用@Bean
注释的方法由CGLIB
包裹。
如果是第一次调用此方法,则将执行原始方法的主体并将结果对象存储在Spring
上下文中。所有后续调用仅返回从上下文中检索到的bean。
答案 1 :(得分:0)
是什么让您认为代理无法处理呼叫?
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()
实现来显示对象的“身份”,类似于类toString()
中的默认Object
实现。
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
直接“调用” blogService()
,也只能创建和共享blogRepository()
的一个实例。