Introduction to AutoFactory – AutoFactory简介

最后修改: 2018年 5月 4日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In this tutorial, we’ll give a brief introduction to AutoFactory, from by Google.

在本教程中,我们将简要介绍AutoFactory,由Google提供。

This is a source-level code generator that helps generate factories.

这是一个源码级的代码生成器,有助于生成工厂。

2. Maven Setup

2.Maven的设置

Before we begin, let’s add the following dependency to the pom.xml:

在我们开始之前,让我们在pom.xml中添加以下依赖关系:</em

<dependency>
    <groupId>com.google.auto.factory</groupId>
    <artifactId>auto-factory</artifactId>
    <version>1.0-beta5</version>
</dependency>

The latest version can be found here.

最新版本可以在这里找到。

3. Quickstart

3.快速入门

Let’s now take a quick look at what AutoFactory can do and create a simple Phone class.

现在让我们快速浏览一下AutoFactory能做什么,并创建一个简单的Phone类。

So, when we annotate the Phone class with @AutoFactory and its constructor parameter with @Provided, we get:

因此,当我们用@AutoFactory注解Phone类,用@Provided注解其构造参数时,我们得到。

@AutoFactory
public class Phone {

    private final Camera camera;

    private final String otherParts;

    PhoneAssembler(@Provided Camera camera, String otherParts) {
        this.camera = camera;
        this.otherParts = otherParts;
    }

    //...

}

We only used two annotations: @AutoFactory and @Provided. When we need a factory generated for our class, we can annotate it with @AutoFactory, whereas @Provided applies to constructor parameters of this class, and it means that the annotated parameter should be provided by an injected Provider.

我们只用了两个注解。@AutoFactory@Provided。当我们需要为我们的类生成一个工厂时,我们可以用@AutoFactory来注解,@Provided适用于这个类的构造函数参数,它意味着被注解的参数应该由一个注入的Provider提供。

In the snippet above, we expect the Camera to be provided by any camera producer and AutoFactory will help generate the following code:

在上面的片段中,我们希望Camera由任何相机生产商提供,AutoFactory将帮助生成以下代码。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class PhoneFactory {

    private final Provider<Camera> cameraProvider;
    
    @Inject
    PhoneAssemblerFactory(Provider<Camera> cameraProvider) {
        this.cameraProvider = checkNotNull(cameraProvider, 1);
    }
    
    PhoneAssembler create(String otherParts) {
      return new PhoneAssembler(
        checkNotNull(cameraProvider.get(), 1),
        checkNotNull(otherParts, 2));
    }
    
    // ...

}

Now we have a PhoneFactory generated automatically by AutoFactory at compile time, and we can use it to produce phone instances:

现在我们有一个PhoneFactory在编译时由AutoFactory自动生成,我们可以用它来生产电话实例。

PhoneFactory phoneFactory = new PhoneFactory(
  () -> new Camera("Unknown", "XXX"));
Phone simplePhone = phoneFactory.create("other parts");

The @AutoFactory annotation can be applied to constructors as well:

@AutoFactory注解也可以应用于构造函数。

public class ClassicPhone {

    private final String dialpad;
    private final String ringer;
    private String otherParts;

    @AutoFactory
    public ClassicPhone(
      @Provided String dialpad, @Provided String ringer) {
        this.dialpad = dialpad;
        this.ringer = ringer;
    }

    @AutoFactory
    public ClassicPhone(String otherParts) {
        this("defaultDialPad", "defaultRinger");
        this.otherParts = otherParts;
    }

    //...

}

In the snippet above, we applied @AutoFactory to both constructors. AutoFactory will simply generate two creation methods for us accordingly:

在上面的片段中,我们将@AutoFactory应用于两个构造函数。AutoFactory将简单地为我们生成两个相应的创建方法。

@Generated(value = "com.google.auto.factory.processor.AutoFactoryProcessor")
public final class ClassicPhoneFactory {
    private final Provider<String> java_lang_StringProvider;

    @Inject
    public ClassicPhoneFactory(Provider<String> java_lang_StringProvider) {
        this.java_lang_StringProvider =
          checkNotNull(java_lang_StringProvider, 1);
    }

    public ClassicPhone create() {
        return new ClassicPhone(
          checkNotNull(java_lang_StringProvider.get(), 1),
          checkNotNull(java_lang_StringProvider.get(), 2));
    }

    public ClassicPhone create(String otherParts) {
        return new ClassicPhone(checkNotNull(otherParts, 1));
    }

    //...

}

AutoFactory also supports parameters annotated with @Provided, but only for JSR-330 annotations.

AutoFactory也支持用@Provided注释的参数,但仅适用于JSR-330注释。

For example, if we want the cameraProvider to be “Sony”, we can change the Phone class to:

例如,如果我们希望cameraProvider是 “Sony”,我们可以将Phone类改为。

@AutoFactory
public class Phone {

    PhoneAssembler(
      @Provided @Named("Sony") Camera camera, String otherParts) {
        this.camera = camera;
        this.otherParts = otherParts;
    }

    //...

}

AutoFactory will retain the @Named @Qualifier so that we can make use of it, for example, when using Dependency Injection frameworks:

AutoFactory将保留@Named @Qualifier 这样我们就可以利用它,例如在使用依赖注入框架时。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class PhoneFactory {

    private final Provider<Camera> cameraProvider;
    
    @Inject
    PhoneAssemblerFactory(@Named("Sony") Provider<Camera> cameraProvider) {
      this.cameraProvider = checkNotNull(cameraProvider, 1);
    }

    //...

}

4. Customized Code Generation

4.定制的代码生成

There are several attributes we can use with the @AutoFactory annotation to customize the generated code.

我们可以使用@AutoFactory注解的几个属性来定制生成的代码。

4.1. Custom Class Name

4.1.自定义类名称

The name of the generated factory class can be set with className:

生成的工厂类的名称可以用className来设置。

@AutoFactory(className = "SamsungFactory")
public class SmartPhone {

    //...

}

With the configuration above, we’ll create a class named SamsungFactory:

通过上面的配置,我们将创建一个名为SamsungFactory的类。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class SamsungFactory {

    //...

}

4.2. non-final Factories

4.2.非最终的工厂

Note that the generated factory class is marked final by default, so we can alter this behavior by setting the allowSubclasses attribute to false:

请注意,生成的工厂类默认标记为final,因此我们可以通过将allowSubclasses属性设置为false:来改变这一行为。

@AutoFactory(
  className = "SamsungFactory", 
  allowSubclasses = true)
public class SmartPhone {

    //...

}

Now we have:

现在我们有了。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public class SamsungFactory {

    //...

}

4.3. More Capabilities

4.3.更多的能力

Additionally, we can specify a list of interfaces for the generated factory to implement using the implementing” parameter.

此外,我们可以使用implementing”参数,为生成的工厂指定一个接口列表。

Here we need the SamsungFactory to produce smartphones with customizable storage:

在这里,我们需要SamsungFactory来生产可定制存储的智能手机。

public interface CustomStorage {
    SmartPhone customROMInGB(int romSize);
}

Note that methods in the interface should return instances of the base class SmartPhone.

注意,接口中的方法应该返回基类SmartPhone的实例。

Then, to generate a factory class with the interface above implemented, AutoFactory requires relevant constructors in the base class:

那么,为了生成一个实现了上述接口的工厂类,AutoFactory需要基类中的相关构造函数

@AutoFactory(
  className = "SamsungFactory",
  allowSubclasses = true,
  implementing = CustomStorage.class)
public class SmartPhone {

    public SmartPhone(int romSize){
        //...
    }

    //...

}

Thus, AutoFactory will generate the following code:

因此,AutoFactory将生成以下代码。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public class SamsungFactory implements CustomStorage {

    //...

    public SmartPhone create(int romSize) {
        return new SmartPhone(romSize);
    }
  
    @Override
    public SmartPhone customROMInGB(int romSize) {
        return create(romSize);
    }
}

4.4. Factories With Extensions

4.4.有扩展的工厂

Since AutoFactory can generate interface implementations, it’s natural to expect it to be able to extend classes as well and this is possible indeed:

既然AutoFactory可以生成接口实现,我们自然希望它也能扩展类,这的确是可能的。

public abstract class AbstractFactory {
    abstract CustomPhone newInstance(String brand);
}

@AutoFactory(extending = AbstractFactory.class)
public class CustomPhone {

    private final String brand;

    public CustomPhone(String brand) {
        this.brand = brand;
    }
}

Here, we extended the AbstractFactory class using extending. Also, we should note that each abstract method in the base abstract class (AbstractFactory) should have a corresponding constructor in the concrete class (CustomPhone).

在这里,我们使用extending扩展了AbstractFactory类。另外,我们应该注意,基抽象类(AbstractFactory)中的每个抽象方法在具体类(CustomPhone)中应该有一个对应的构造函数

Finally, we can see the following generated code:

最后,我们可以看到以下生成的代码。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class CustomPhoneFactory extends AbstractFactory {
 
    @Inject
    public CustomPhoneFactory() {
    }

    public CustomPhone create(String brand) {
        return new CustomPhone(checkNotNull(brand, 1));
    }

    @Override
    public CustomPhone newInstance(String brand) {
        return create(brand);
    }

    //...

}

We can see that AutoFactory is smart enough to make use of the constructor to implement the corresponding abstract method – great features like this in AutoFactory surely will save us lots of time and code.

我们可以看到,AutoFactory足够聪明,利用构造函数来实现相应的抽象方法–AutoFactory中这样的伟大功能肯定会给我们节省很多时间和代码。

5. AutoFactory With Guice

5.AutoFactoryGuice

As we mentioned earlier in this article, AutoFactory supports JSR-330 annotations, so we can integrate existing dependency injection framework with it.

正如我们在本文前面提到的,AutoFactory支持JSR-330注解,因此我们可以将现有的依赖注入框架与之集成。

First, let’s add Guice to the pom.xml:

首先,让我们把Guice添加到pom.xml

<dependency>
    <groupId>com.google.inject</groupId>
    <artifactId>guice</artifactId>
    <version>4.2.0</version>
</dependency>

The latest version of Guice can be found here.

最新版本的Guice可以在这里找到。

Now, we’ll demonstrate how well AutoFactory integrates with Guice.

现在,我们将展示AutoFactoryGuice的整合情况。

As we expect “Sony” to be the camera provider, we need to inject a SonyCameraProvider to PhoneFactory‘s constructor:

由于我们希望 “Sony “成为相机提供商,我们需要向PhoneFactory的构造函数注入一个SonyCameraProvider

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class PhoneFactory {
 
    private final Provider<Camera> cameraProvider;

    @Inject
    public PhoneFactory(@Named("Sony") Provider<Camera> cameraProvider) {
        this.cameraProvider = checkNotNull(cameraProvider, 1);
    }

    //...

}

Finally, we’ll make the binding in a Guice module:

最后,我们将在一个Guice模块中进行绑定。

public class SonyCameraModule extends AbstractModule {

    private static int SONY_CAMERA_SERIAL = 1;

    @Named("Sony")
    @Provides
    Camera cameraProvider() {
        return new Camera(
          "Sony", String.format("%03d", SONY_CAMERA_SERIAL++));
    }

}

And we set the camera provider annotated with @Named(“Sony”) in SonyCameraModule to match PhoneFactory‘s constructor parameter.

而我们在SonyCameraModule中设置了用@Named(“Sony”)注释的相机提供者,以匹配PhoneFactory的构造函数参数。

Now we can see that Guice is managing dependency injection for our generated factory:

现在我们可以看到,Guice正在为我们生成的工厂管理依赖注入。

Injector injector = Guice.createInjector(new SonyCameraModule());
PhoneFactory injectedFactory = injector.getInstance(PhoneFactory.class);
Phone xperia = injectedFactory.create("Xperia");

6. Under the Hood

6.引擎盖下

All annotations provided by AutoFactory are processed in the compilation stage, as we have explained in detail in the article: how the source-level annotation processing works.

AutoFactory提供的所有注解都在编译阶段进行处理,我们在文章中已经详细解释了。源码级注解处理是如何工作的。

7. Conclusion

7.结论

In this article, we’ve introduced how to use AutoFactory, and how to integrate it with Guice – writing factories can be repetitive and error-prone – code generation tools like AutoFactory and AutoValue can save us lots of time and free us from subtle bugs.

在这篇文章中,我们介绍了如何使用AutoFactory,以及如何将其与Guice整合在一起–编写工厂可能是重复的、容易出错的–像AutoFactoryAutoValue这样的代码生成工具可以为我们节省大量时间,使我们摆脱微妙的错误。

As always, the full implementation of the code samples can be found over on Github.

一如既往,可以在Github上找到完整的实现代码样本over