应用依赖注入的正确弹簧引导方式是什么

时间:2017-04-22 12:55:09

标签: java spring spring-boot dependency-injection

我目前正在开发一个弹簧启动应用程序,它通过以下方式将一些bean连接在一起(大大简化的示例):

Component

然而,实际的bean需要比此处所示更多的配置和设置,并且在使用内部Lazy Bean方法时,它在PlayingFieldByBeans类中需要很多行代码。所以我使用@Component @Order(1) public class PlayingFieldByComponents implements CommandLineRunner { @Autowired private PlayerComponent playerComponent; @Override public void run(String... arg0) throws Exception { List<String> names = new ArrayList<>(); names.add("Alex"); names.add("Benedict"); names.add("Chloe"); System.out.println("Printing from component variant: "); names.forEach(n -> { System.out.println(playerComponent.player(n)); }); } } 注释创建了一种不同的连接方式:

@Component
public class PlayerComponent {

    @Autowired
    private ShoesComponent shoesComponent;

    public Player player(String name) {
        return new Player(name, shoesComponent.shoes());
    }
}

PlayerComponent类如下所示:

@Configuration
public class BeanConfiguration {

    @Bean
    @Lazy
    public Player player(String name) {
        return new Player(name, shoes());       
    }

    @Bean
    @Lazy
    public Shoes shoes() {
        return new Shoes("Adidas");     
    }

}

ShoesComponent与PlayerComponent类非常相似。

为了维护和TDD的目的,我不确定在这里使用spring框架最合适的方法是什么。

问题

鉴于Player和Shoes bean只需要一行初始化(多个设置,对其他bean的多个依赖等),设计和连接它们的最佳方法是什么?

修改 - 根据建议

添加了一个配置类来捆绑bean:

@Component
@Order(2)
public class PlayingFieldByConfiguration implements CommandLineRunner { 

    @Autowired
    private BeanConfiguration beanConfiguration;

    @Override
    public void run(String... arg0) throws Exception {
        List<String> names = new ArrayList<>();
        names.add("Alex");
        names.add("Benedict");
        names.add("Chloe");

        System.out.println("Printing from component variant: ");
        names.forEach(n -> {
            System.out.println(beanConfiguration.player(n));
        });

    }       
}

匹配的执行类:

Printing from component variant: 
Player name: Alex has shoes of brand: Adidas
Player name: Alex has shoes of brand: Adidas
Player name: Alex has shoes of brand: Adidas

Re使用相同的第一个bean,所以它似乎没有创建一个新的

abstract class AbstractEventFilter {

    private final Logger logger = Logger.getLogger(getClass().getCanonicalName());
    private final String filterName = getClass().getSimpleName();

    protected abstract Predicate<IEvent> isEligible();

    private Predicate<IEvent> internalIsEligible() {
        return iEvent -> {
            boolean res = isEligible().test(iEvent);
            if (!res) {
                logger.info("event " + iEvent.toString() + " filtered by " + filterName);
            }
            return res;
        };
    }

    public List<IEvent> getFilteredEvents(final List<IEvent> events) {
        return events.stream().filter(internalIsEligible()).collect(Collectors.toList());
    }
}

1 个答案:

答案 0 :(得分:1)

如Andriy Slobodyanyk所述,一个解决方案是改变播放器bean的范围(如果我们想创建不同的品牌,可以改用鞋子)

@Configuration
public class BeanConfiguration {

    @Bean
    @Lazy
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public Player player(String name) {
        return new Player(name, shoes());
    }

    @Bean
    @Lazy
    public Shoes shoes() {
        return new Shoes("Adidas");
    }
}

如果上面的内容不够(因为你提到真实情况的场景更加复杂),另一个选择就是使用FactoryBean

public class PlayerFactoryBean implements FactoryBean<Player> {

    private String name;
    private Shoes shoes;

    public void setName(String name) {
        this.name = name;
    }

    public void setShoes(Shoes shoes) {
        this.shoes = shoes;
    }

    @Override
    public Player getObject() throws Exception {
        //initialization logic goes here
        System.out.println("Creating bean using factory");
        return new Player(name, shoes);
    }

    @Override
    public Class<Player> getObjectType() {
        return Player.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
@Configuration
public class BeanConfiguration {

    @Bean
    @Lazy
    public Shoes shoes() {
        return new Shoes("Adidas");
    }

    @Bean
    public PlayerFactoryBean playerFactoryBean(){
        PlayerFactoryBean pfb = new PlayerFactoryBean();
        pfb.setShoes(shoes());
        return pfb;
    }
}
@Component
@Order(2)
public class PlayingFieldByConfiguration implements CommandLineRunner {

    @Autowired
    private PlayerFactoryBean factoryBean;

    @Override
    public void run(String... arg0) throws Exception {
        List<String> names = new ArrayList<>();
        names.add("Alex");
        names.add("Benedict");
        names.add("Chloe");

        System.out.println("Printing from component variant: ");
        names.forEach(n -> {
            try {
                factoryBean.setName(n);
                System.out.println(factoryBean.getObject());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

    }
}