如何使用参数创建工厂方法?

问题描述 投票:1回答:2

你能帮我摆脱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);
    }

}

这是一个带有@Beanmethod的配置类,用于实例化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类很好,你觉得怎么样?

java spring spring-annotations factory-method spring-ioc
2个回答
3
投票

不,在Spring管理的应用程序中创建每个类都不是一个好主意。

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


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);
   }
}

注意,Provider的类型为“javax.inject.Provider”,为了使用id,import(例如在maven中):

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

Spring可以处理这个问题,因为4.x(我猜4.1)没有任何额外的配置

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

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

还有另一种方法,子类的运行时生成与@Lookup注释相结合,其描述的Here但IMO Provider方法更好。

© www.soinside.com 2019 - 2024. All rights reserved.