Как работает лямбда-оператор () ->? - PullRequest
0 голосов
/ 25 января 2019

Я хотел бы понять, как работает приведенный ниже код.

@Bean
public StateHandlerDef handler() {
    return () -> StateOne.class;
}

@Named
@Scope("prototype")
public class StateOne extends AbstractStateActorActor<StatObject> {

    @Inject
    public StateOne(final Props prop, final StatRegistry statRegistry) {
        super("test", transformationConfig, GenericStateObject.class, statRegistry);
    }
}

@FunctionalInterface
public interface StateHandlerDef {
    Class<? extends AbstractUntypedActor> getHandlerClass();
}

Это рабочий код.

Я хотел бы понять, как здесь работает создание компонента.

Ниже код создает компонент.

@Bean
public StateHandlerDef handler() {
    return () -> StateOne.class;
}

Класс StateOne имеет конструктор.Но это создает компонент без передачи аргументов конструктора.Кроме того, тип возвращаемого значения является интерфейсом функции, который не реализован классом фактического состояния и не уверен, как он работает.Это основано на актерской модели Akka.

AbstractStateActorActor extends AbstractUntypedActor

Здесь я хотел бы установить имя компонента программно, а не задавать аннотацию.

@ Bean ("test"))

Если я попробую BeanPostProcessor для программной установки имени компонента, он выдаст ошибку, что экземпляр не может быть создан с использованием new, и его следует создать с помощью actorof.

Caused by: akka.actor.ActorInitializationException: You cannot create an instance of [com.test.Test] explicitly using the constructor (new). You have to use one of the 'actorOf' factory methods to create a new actor. See the documentation.
    at akka.actor.ActorInitializationException$.apply(Actor.scala:181) ~[akka-actor_2.11-2.4.19.jar:na]

Любая помощь поэто? * * 1023

Ответы [ 3 ]

0 голосов
/ 25 января 2019

Чтобы понять это, подумайте об этом.Библиотека, которую вы пытаетесь расширить (в данном случае akka), должна знать класс, который будет обрабатывать состояние.Для этого он получает экземпляр (бин) типа StateHandlerDef.Этот экземпляр создается лямбда-выражением в этом коде:

@Bean
public StateHandlerDef handler() {
    return () -> StateOne.class;
}

, что эквивалентно чему-то вроде:

@Bean
public StateHandlerDef handler() {
    return new StateHanderDefImpl();
}

Библиотека будет использовать это, чтобы получить StateOne.class, для которогоон будет искать бин и получит его из среды внедрения зависимостей.Этот bean-компонент определен здесь:

@Named
@Scope("prototype")
public class StateOne extends AbstractStateActorActor<StatObject> {

    @Inject
    public StateOne(final Props prop, final StatRegistry statRegistry) {
        super("test", transformationConfig, GenericStateObject.class, statRegistry);
    }
}

Инфраструктура DI создаст bean-компонент из этого класса, внедрив зависимости, необходимые для его конструктора.

0 голосов
/ 25 января 2019

@ FunctionInterface - это особый тип интерфейса, который фактически запрещает пользователю не включать более одного SAM (Single Abstraction Method). Для приведенного ниже примера у нас есть один метод, он предоставит любой класс, который расширяет класс Object.

@FunctionalInterface
interface ClassHandleDef {
  Class<? extends Object> getHandlerClass();
}

Теперь мы создаем анонимный класс интерфейса ClassHandleDef и предоставляем тело метода gethandlerClass.

new ClassHandleDef() {
        @Override
        public Class<? extends Object> getHandlerClass() {
            return String.class;
        }
    };

Теперь мы удаляем лишний код, который не требуется. В соответствии с лямбда-выражением удалите весь лишний код и предоставьте аргумент, если существует, и определение тела метода вместе с лямбда-оператором.

() -> String.class;
  • Если существует однострочное определение метода, нет необходимости явно писать оператор возврата.
  • Если есть единственный аргумент, то в скобках нет необходимости. например

    a -> a * 2;

Надеюсь, вы понимаете рабочий процесс лямбда-выражения. Спасибо, что нашли время, чтобы прочитать этот пост.

0 голосов
/ 25 января 2019

Функциональный интерфейс там StateHandlerDef предназначен для представления функции-получателя getHandlerClass(), которая определена в определении класса с помощью лямбда-определения. С декларацией ниже;

@Bean
public StateHandlerDef handler() {
    return () -> StateOne.class; // a supplier, no input, returns value (getter)
}

По сути, мы реализуем интерфейс StateHandlerDef, определив метод getHandlerClass(). Вот почему возвращаемое значение лямбды совпадает с методом получения, StateOne имеет тип Class<? extends AbstractUntypedActor>.

Таким образом, созданный нами компонент был похож на следующий:

public interface StateHandlerDef {
    Class<? extends AbstractUntypedActor> getHandlerClass();
}

public class StateHandlerDefImpl implements StateHandlerDef {

    // explicit way of writing lambda "() -> StateOne.class"
    Class<? extends AbstractUntypedActor> getHandlerClass() {
        return StateOne.class;
    }
}

@Bean
public StateHandlerDef handler() {
    return new StateHandlerDefImpl();  // then we use the getter thru this bean.
}

С помощью @FunctionalInterface мы можем пропустить реализацию интерфейса, как указано выше, и просто использовать сам интерфейс с переданной лямбда (которая является Поставщиком ).

Теперь вы можете просто сделать это;

@Autowire
private StateHandlerDef handler;

public .. someLogic() {
    ...
    handler.getHandlerClass();  // will trigger the lambda, returning `StateOne.class`
    ...
}

Вы можете изменить имя компонента, просто изменив имя метода его создания. @Bean handler() сгенерирует бин с именем handler.

Я попытался упростить, надеюсь, это было понятно, в противном случае, пожалуйста, проверьте это

...