2
votes

Comment fonctionne l'opérateur Lambda () ->?

Je voudrais comprendre comment fonctionne le code ci-dessous.

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]

Voici le code de travail.

Je voudrais comprendre, Comment fonctionne la création de bean ici.

Le code ci-dessous crée un bean.

AbstractStateActorActor extends AbstractUntypedActor

La classe StateOne a un constructeur. Mais, cela crée le bean sans passer les arguments du constructeur. En outre, le type de retour est une interface de fonction qui n'est pas implémentée par la classe d'état réelle et ne sait pas comment cela fonctionne. Ceci est basé sur un modèle d'acteur Akka.

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

Ici, je voudrais définir le nom du bean par programme au lieu de le définir via l'annotation.

@Bean ("test")

Si j'essaie BeanPostProcessor pour définir par programme le nom du bean, cela génère une erreur selon laquelle l'instance ne peut pas être créée avec new et doit être créée avec actorof.

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

Avez-vous de l'aide à ce sujet?


0 commentaires

3 Réponses :


1
votes

L'interface fonctionnelle là StateHandlerDef est en quelque sorte de représenter la fonction getter getHandlerClass () qui est définie dans sa définition de classe avec une définition lambda. Avec la déclaration ci-dessous:

@Autowire
private StateHandlerDef handler;

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

Nous implémentons essentiellement l'interface StateHandlerDef en définissant la méthode getHandlerClass () . C'est pourquoi la valeur de retour du lambda est la même que celle de la méthode getter, StateOne est de type Class étend AbstractUntypedActor> .

Donc, d'une certaine manière, le bean que nous avons créé était comme suit;

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.
}

Avec @FunctionalInterface nous pouvons ignorer l'implémentation de l'interface comme indiqué ci-dessus, et simplement utiliser l'interface elle-même avec le lambda passé (qui est un Supplier ).

Maintenant, vous pouvez simplement le faire;

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


3 commentaires

Qu'en est-il des arguments du constructeur?


@ user1578872 quels arguments de constructeur? Le type de retour du getter est Class , pas StateOne , il n'y a pas besoin de constructeur pour un type Class , vous pouvez simplement utiliser StateOne.class . Il est de type Classe .


Je dois passer les arguments public StateOne (final Props prop, final StatRegistry statRegistry) pour instancier la classe.



2
votes

Pour comprendre cela, pensez de cette façon. La bibliothèque que vous essayez d'étendre (dans ce cas akka) doit connaître la classe qui va gérer un état. Pour ce faire, il obtient une instance (bean) de type StateHandlerDef . Cette instance est créée par l'expression lambda dans ce code:

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

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

qui équivaut à quelque chose comme:

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

La bibliothèque utilisera ceci pour obtenir StateOne.class , pour lequel il recherchera un bean et l'obtiendra depuis le framework d'injection de dépendances. Ce bean est défini ici:

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

Le framework DI créera un bean à partir de cette classe en injectant les dépendances dont il a besoin dans son constructeur.


4 commentaires

Comment puis-je changer le nom du bean par programme sans codage en dur comme @Bean ("")


quel nom de haricot devez-vous changer? StateOne ou StateHandlerDef ?


@Bean gestionnaire public StateHandlerDef ()


Pour cela, je suppose que vous devez comprendre le fonctionnement interne de l'akka et comment il relie ces haricots. Je suis désolé de ne pas être familier avec akka pour vous proposer une solution.



1
votes

@FunctionInterface est un type spécial d'interface qui restreint en fait l'utilisateur à ne pas inclure plus d'un SAM (méthode d'abstraction unique). Pour l'exemple ci-dessous, nous avons une méthode, elle fournira toute classe qui étend la classe Object.

() -> String.class;

Nous créons maintenant une classe anonyme de l'interface ClassHandleDef et fournissons le corps de la méthode gethandlerClass.

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

Nous supprimons maintenant le code supplémentaire qui n'est pas nécessaire. Selon l'expression lambda, supprimez tout le code supplémentaire et fournissez un argument s'il existe une définition du corps de la méthode avec l'opérateur lambda.

@FunctionalInterface
interface ClassHandleDef {
  Class<? extends Object> getHandlerClass();
}
  • S'il existe une définition de méthode sur une seule ligne, il n'est pas nécessaire d'écrire explicitement l'instruction return.
  • S'il y a un seul argument, il n'y a pas besoin de crochets. par exemple

    a -> a * 2;

J'espère que vous comprenez le flux de travail de l'expression lambda. Merci d'avoir pris le temps de lire ce message.


0 commentaires