如何创建带有参数的工厂方法?

时间:2018-09-02 11:12:02

标签: java spring spring-annotations factory-method spring-ioc

您能帮我摆脱ApplicationContext吗?

我有一家工厂,所以所有的书本都是弹跳豆。 我认为这是使所有豆子都变豆的好决定。

@Component
public class BookFactoryImpl implements BookFactory {

    private final ApplicationContext applicationContext;

    @Autowired
    public BookFactoryImpl(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public Book createBook(String name) {
        return applicationContext.getBean(Book.class, name);
    }

}

这是带有@Bean方法的配置类,用于实例化Book类的新实例:

@Configuration
@ComponentScan({"factory"})
public class AppConfig {

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Lazy
    public Book book(String name) {
        return Book.builder().name(name).build();
    }

}

这是我的Book实体类:

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@EqualsAndHashCode
@ToString
@Builder
public class Book {

    @Id
    @GeneratedValue
    private int id;

    @Basic(fetch = FetchType.LAZY)
    private String name;

}

我还有一个主意-用BookFactoryImpl注释@Configuration并在其中移动@Bean方法,但是在这种情况下,我的工厂将变成@Configuration类生命周期破裂。

您如何看待?实现工厂的最佳方法是什么?如何减少诸如ApplicationContext之类的外部依赖关系?

或者用@Configuration方法将所有工厂都设为@Bean类也许很好,您如何看待?

2 个答案:

答案 0 :(得分:3)

不,最好不要让Spring管理应用程序中的每个类。

JPA实体通常应由您在Spring托管bean中的代码实例化。

答案 1 :(得分:0)

我通常使用以下方法:

定义将包含对工厂的依赖关系的单例bean:

    public class MyService {
     private final Provider<Book> bookFactory;

     public MyService(Provider<Book> bookFactory) {
         this.bookFactory = bookFactory;
     } 
     public void doSomething() {
        Book book = bookFactory.get();
        book.setNumberOfReaders(numOfReaders); // this is a drawback, book is mutable, if we want to set runtime params (like numberOfReaders)
         ....
      }
    }

现在为book bean定义一个原型:

@Configuration 
public class MyConfiguration {

   @Bean
   @Scope("prototype")
   public Book book(...) {
      return new Book(...);
   }

   @Bean // scope singleton by default
   public MyService myService(Provider<Book> bookFactory) {
       return new MyService(bookFactory);
   }
}

注意,提供者的类型为“ javax.inject.Provider”,以便使用id导入(例如在maven中):

<dependency>
   <groupId>javax.inject</groupId>
   <artifactId>javax.inject</artifactId>
   <version>1</version>
</dependency>

Spring可以从4.x(我猜为4.1)开始处理此问题,而无需任何其他配置

当然,这种方法消除了向工厂注入应用程序上下文以及通常维护工厂的需求

一个缺点是它不允许使用参数构建对象,这些参数必须在运行时指定。

还有另一种方法,与@Lookup批注一起运行时生成子类,其描述为Here,但IMO Provider方法更好。