Spring如何知道使用@Bean和方法调用进行注入的bean

时间:2019-09-10 20:45:21

标签: java spring dependency-injection

我正在尝试使用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()单例,因此代理可以呢?无法接听电话?

2 个答案:

答案 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()的一个实例。