deprecate closure-taking Props factories, see #3081
- base Props on Deploy, Class and Seq[Any] (i.e. constructor args) - remove deprecated Props usage from akka-docs sample code - rewrite UntypedActorDocTestBase - rewrite Java/Scala doc section on actor creation - add migration guide entry
This commit is contained in:
parent
64f664a706
commit
28aad82b1a
80 changed files with 2268 additions and 1641 deletions
|
|
@ -9,13 +9,16 @@ import akka.japi.Creator
|
|||
import scala.reflect.ClassTag
|
||||
import akka.routing._
|
||||
import akka.util.Reflect
|
||||
import scala.annotation.varargs
|
||||
import Deploy.NoDispatcherGiven
|
||||
import scala.collection.immutable
|
||||
|
||||
/**
|
||||
* Factory for Props instances.
|
||||
*
|
||||
* Props is a ActorRef configuration object, that is immutable, so it is thread safe and fully sharable.
|
||||
*
|
||||
* Used when creating new actors through; <code>ActorSystem.actorOf</code> and <code>ActorContext.actorOf</code>.
|
||||
* Used when creating new actors through <code>ActorSystem.actorOf</code> and <code>ActorContext.actorOf</code>.
|
||||
*/
|
||||
object Props {
|
||||
|
||||
|
|
@ -34,30 +37,32 @@ object Props {
|
|||
*/
|
||||
final val defaultDeploy = Deploy()
|
||||
|
||||
/**
|
||||
* A Props instance whose creator will create an actor that doesn't respond to any message
|
||||
*/
|
||||
final val empty = new Props(() ⇒ new Actor { def receive = Actor.emptyBehavior })
|
||||
|
||||
/**
|
||||
* The default Props instance, uses the settings from the Props object starting with default*.
|
||||
*/
|
||||
final val default = new Props()
|
||||
|
||||
/**
|
||||
* A Props instance whose creator will create an actor that doesn't respond to any message
|
||||
*/
|
||||
final val empty = Props[EmptyActor]
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*
|
||||
* (Not because it is so immensely complicated, only because we might remove it if no longer needed internally)
|
||||
*/
|
||||
private[akka] class EmptyActor extends Actor {
|
||||
def receive = Actor.emptyBehavior
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Props that has default values except for "creator" which will be a function that creates an instance
|
||||
* of the supplied type using the default constructor.
|
||||
*
|
||||
* Scala API.
|
||||
*/
|
||||
def apply[T <: Actor: ClassTag](): Props =
|
||||
default.withCreator(implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[_ <: Actor]])
|
||||
|
||||
/**
|
||||
* Returns a Props that has default values except for "creator" which will be a function that creates an instance
|
||||
* of the supplied class using the default constructor.
|
||||
*/
|
||||
def apply(actorClass: Class[_ <: Actor]): Props = default.withCreator(actorClass)
|
||||
def apply[T <: Actor: ClassTag](): Props = apply(implicitly[ClassTag[T]].runtimeClass)
|
||||
|
||||
/**
|
||||
* Returns a Props that has default values except for "creator" which will be a function that creates an instance
|
||||
|
|
@ -65,116 +70,242 @@ object Props {
|
|||
*
|
||||
* Scala API.
|
||||
*/
|
||||
@deprecated("give class and arguments instead", "2.2")
|
||||
def apply(creator: ⇒ Actor): Props = default.withCreator(creator)
|
||||
|
||||
/**
|
||||
* Returns a Props that has default values except for "creator" which will be a function that creates an instance
|
||||
* using the supplied thunk.
|
||||
*/
|
||||
@deprecated("give class and arguments instead", "2.2")
|
||||
def apply(creator: Creator[_ <: Actor]): Props = default.withCreator(creator.create)
|
||||
|
||||
/**
|
||||
* The deprecated legacy constructor.
|
||||
*/
|
||||
@deprecated("give class and arguments instead", "2.2")
|
||||
def apply(
|
||||
creator: () ⇒ Actor = Props.defaultCreator,
|
||||
dispatcher: String = Dispatchers.DefaultDispatcherId,
|
||||
routerConfig: RouterConfig = Props.defaultRoutedProps,
|
||||
deploy: Deploy = Props.defaultDeploy): Props = {
|
||||
|
||||
val d1 = if (dispatcher != Dispatchers.DefaultDispatcherId) deploy.copy(dispatcher = dispatcher) else deploy
|
||||
val d2 = if (routerConfig != Props.defaultRoutedProps) d1.copy(routerConfig = routerConfig) else d1
|
||||
val p = Props(classOf[CreatorFunctionConsumer], creator)
|
||||
if (d2 != Props.defaultDeploy) p.withDeploy(d2) else p
|
||||
}
|
||||
|
||||
/**
|
||||
* Scala API: create a Props given a class and its constructor arguments.
|
||||
*/
|
||||
def apply(clazz: Class[_], args: Any*): Props = apply(defaultDeploy, clazz, args.toVector)
|
||||
|
||||
/**
|
||||
* Java API: create a Props given a class and its constructor arguments.
|
||||
*/
|
||||
@varargs
|
||||
def create(clazz: Class[_], args: AnyRef*): Props = apply(defaultDeploy, clazz, args.toVector)
|
||||
}
|
||||
|
||||
/**
|
||||
* Props is a ActorRef configuration object, that is immutable, so it is thread safe and fully sharable.
|
||||
* Used when creating new actors through; <code>ActorSystem.actorOf</code> and <code>ActorContext.actorOf</code>.
|
||||
*
|
||||
* In case of providing code which creates the actual Actor instance, that must not return the same instance multiple times.
|
||||
* Props is a configuration object using in creating an [[Actor]]; it is
|
||||
* immutable, so it is thread-safe and fully shareable.
|
||||
*
|
||||
* Examples on Scala API:
|
||||
* {{{
|
||||
* val props = Props.empty
|
||||
* val props = Props[MyActor]
|
||||
* val props = Props(new MyActor)
|
||||
* val props = Props(
|
||||
* creator = ..,
|
||||
* dispatcher = ..,
|
||||
* routerConfig = ..
|
||||
* )
|
||||
* val props = Props().withCreator(new MyActor)
|
||||
* val props = Props[MyActor].withRouter(RoundRobinRouter(..))
|
||||
* val props = Props(classOf[MyActor], arg1, arg2)
|
||||
*
|
||||
* val otherProps = props.withDispatcher("dispatcher-id")
|
||||
* val otherProps = props.withDeploy(<deployment info>)
|
||||
* }}}
|
||||
*
|
||||
* Examples on Java API:
|
||||
* {{{
|
||||
* Props props = new Props();
|
||||
* Props props = new Props(MyActor.class);
|
||||
* Props props = new Props(new UntypedActorFactory() {
|
||||
* public UntypedActor create() {
|
||||
* return new MyActor();
|
||||
* }
|
||||
* });
|
||||
* Props props = new Props().withCreator(new UntypedActorFactory() { ... });
|
||||
* Props props = new Props(MyActor.class).withRouter(new RoundRobinRouter(..));
|
||||
* final Props props = Props.empty();
|
||||
* final Props props = Props.create(MyActor.class, arg1, arg2);
|
||||
*
|
||||
* final Props otherProps = props.withDispatcher("dispatcher-id");
|
||||
* final Props otherProps = props.withDeploy(<deployment info>);
|
||||
* }}}
|
||||
*/
|
||||
@SerialVersionUID(1L)
|
||||
case class Props(
|
||||
creator: () ⇒ Actor = Props.defaultCreator,
|
||||
dispatcher: String = Dispatchers.DefaultDispatcherId,
|
||||
routerConfig: RouterConfig = Props.defaultRoutedProps,
|
||||
deploy: Deploy = Props.defaultDeploy) {
|
||||
@SerialVersionUID(2L)
|
||||
case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any]) {
|
||||
|
||||
// validate constructor signature; throws IllegalArgumentException if invalid
|
||||
Reflect.findConstructor(clazz, args)
|
||||
|
||||
/**
|
||||
* No-args constructor that sets all the default values.
|
||||
*
|
||||
* @deprecated use `Props.create(clazz, args ...)` instead
|
||||
*/
|
||||
def this() = this(
|
||||
creator = Props.defaultCreator,
|
||||
dispatcher = Dispatchers.DefaultDispatcherId)
|
||||
@deprecated("use Props.create()", "2.2")
|
||||
def this() = this(Props.defaultDeploy, classOf[CreatorFunctionConsumer], Vector(Props.defaultCreator))
|
||||
|
||||
/**
|
||||
* Java API: create Props from an [[UntypedActorFactory]]
|
||||
*
|
||||
* @deprecated use `Props.create(clazz, args ...)` instead; this method has been
|
||||
* deprecated because it encourages creating Props which contain
|
||||
* non-serializable inner classes, making them also
|
||||
* non-serializable
|
||||
*/
|
||||
def this(factory: UntypedActorFactory) = this(
|
||||
creator = () ⇒ factory.create(),
|
||||
dispatcher = Dispatchers.DefaultDispatcherId)
|
||||
@deprecated("use constructor which takes the actor class directly", "2.2")
|
||||
def this(factory: UntypedActorFactory) = this(Props.defaultDeploy, classOf[UntypedActorFactoryConsumer], Vector(factory))
|
||||
|
||||
/**
|
||||
* Java API: create Props from a given [[Class]]
|
||||
*
|
||||
* @deprecated use Props.create(clazz) instead; deprecated since it duplicates
|
||||
* another API
|
||||
*/
|
||||
def this(actorClass: Class[_ <: Actor]) = this(
|
||||
creator = FromClassCreator(actorClass),
|
||||
dispatcher = Dispatchers.DefaultDispatcherId,
|
||||
routerConfig = Props.defaultRoutedProps)
|
||||
@deprecated("use Props.create()", "2.2")
|
||||
def this(actorClass: Class[_ <: Actor]) = this(Props.defaultDeploy, actorClass, Vector.empty)
|
||||
|
||||
@deprecated("use newActor()", "2.2")
|
||||
def creator: () ⇒ Actor = newActor
|
||||
|
||||
/**
|
||||
* Convenience method for extracting the dispatcher information from the
|
||||
* contained [[Deploy]] instance.
|
||||
*/
|
||||
def dispatcher: String = deploy.dispatcher match {
|
||||
case NoDispatcherGiven ⇒ Dispatchers.DefaultDispatcherId
|
||||
case x ⇒ x
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for extracting the router configuration from the
|
||||
* contained [[Deploy]] instance.
|
||||
*/
|
||||
def routerConfig: RouterConfig = deploy.routerConfig
|
||||
|
||||
/**
|
||||
* Scala API: Returns a new Props with the specified creator set.
|
||||
*
|
||||
* The creator must not return the same instance multiple times.
|
||||
*/
|
||||
def withCreator(c: ⇒ Actor): Props = copy(creator = () ⇒ c)
|
||||
@deprecated("move actor into named class and use withCreator(clazz)", "2.2")
|
||||
def withCreator(c: ⇒ Actor): Props = copy(clazz = classOf[CreatorFunctionConsumer], args = Vector(() ⇒ c))
|
||||
|
||||
/**
|
||||
* Java API: Returns a new Props with the specified creator set.
|
||||
*
|
||||
* The creator must not return the same instance multiple times.
|
||||
*
|
||||
* @deprecated use `Props.create(clazz, args ...)` instead; this method has been
|
||||
* deprecated because it encourages creating Props which contain
|
||||
* non-serializable inner classes, making them also
|
||||
* non-serializable
|
||||
*/
|
||||
def withCreator(c: Creator[Actor]): Props = copy(creator = () ⇒ c.create)
|
||||
@deprecated("use Props.create(clazz, args ...) instead", "2.2")
|
||||
def withCreator(c: Creator[Actor]): Props = copy(clazz = classOf[CreatorConsumer], args = Vector(c))
|
||||
|
||||
/**
|
||||
* Java API: Returns a new Props with the specified creator set.
|
||||
* Returns a new Props with the specified creator set.
|
||||
*
|
||||
* @deprecated use Props.create(clazz) instead; deprecated since it duplicates
|
||||
* another API
|
||||
*/
|
||||
def withCreator(c: Class[_ <: Actor]): Props = copy(creator = FromClassCreator(c))
|
||||
@deprecated("use Props(clazz, args).withDeploy(other.deploy)", "2.2")
|
||||
def withCreator(c: Class[_ <: Actor]): Props = copy(clazz = c, args = Vector.empty)
|
||||
|
||||
/**
|
||||
* Returns a new Props with the specified dispatcher set.
|
||||
*/
|
||||
def withDispatcher(d: String): Props = copy(dispatcher = d)
|
||||
def withDispatcher(d: String): Props = copy(deploy = deploy.copy(dispatcher = d))
|
||||
|
||||
/**
|
||||
* Returns a new Props with the specified router config set.
|
||||
*/
|
||||
def withRouter(r: RouterConfig): Props = copy(routerConfig = r)
|
||||
def withRouter(r: RouterConfig): Props = copy(deploy = deploy.copy(routerConfig = r))
|
||||
|
||||
/**
|
||||
* Returns a new Props with the specified deployment configuration.
|
||||
*/
|
||||
def withDeploy(d: Deploy): Props = copy(deploy = d)
|
||||
def withDeploy(d: Deploy): Props = copy(deploy = d withFallback deploy)
|
||||
|
||||
/**
|
||||
* Create a new actor instance. This method is only useful when called during
|
||||
* actor creation by the ActorSystem, i.e. for user-level code it can only be
|
||||
* used within the implementation of [[IndirectActorProducer#produce]].
|
||||
*/
|
||||
def newActor(): Actor = {
|
||||
Reflect.instantiate(clazz, args) match {
|
||||
case a: Actor ⇒ a
|
||||
case i: IndirectActorProducer ⇒ i.produce()
|
||||
case _ ⇒ throw new IllegalArgumentException(s"unknown actor creator [$clazz]")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain an upper-bound approximation of the actor class which is going to
|
||||
* be created by these Props. In other words, the [[#newActor]] method will
|
||||
* produce an instance of this class or a subclass thereof. This is used by
|
||||
* the actor system to select special dispatchers or mailboxes in case
|
||||
* dependencies are encoded in the actor type.
|
||||
*/
|
||||
def actorClass(): Class[_ <: Actor] = {
|
||||
if (classOf[IndirectActorProducer].isAssignableFrom(clazz)) {
|
||||
Reflect.instantiate(clazz, args).asInstanceOf[IndirectActorProducer].actorClass
|
||||
} else if (classOf[Actor].isAssignableFrom(clazz)) {
|
||||
clazz.asInstanceOf[Class[_ <: Actor]]
|
||||
} else {
|
||||
throw new IllegalArgumentException("unknown actor creator [$clazz]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when creating an Actor from a class. Special Function0 to be
|
||||
* able to optimize serialization.
|
||||
* This interface defines a class of actor creation strategies deviating from
|
||||
* the usual default of just reflectively instantiating the [[Actor]]
|
||||
* subclass. It can be used to allow a dependency injection framework to
|
||||
* determine the actual actor class and how it shall be instantiated.
|
||||
*/
|
||||
private[akka] case class FromClassCreator(clazz: Class[_ <: Actor]) extends Function0[Actor] {
|
||||
def apply(): Actor = Reflect.instantiate(clazz)
|
||||
trait IndirectActorProducer {
|
||||
|
||||
/**
|
||||
* This factory method must produce a fresh actor instance upon each
|
||||
* invocation. <b>It is not permitted to return the same instance more than
|
||||
* once.</b>
|
||||
*/
|
||||
def produce(): Actor
|
||||
|
||||
/**
|
||||
* This method is used by [[Props]] to determine the type of actor which will
|
||||
* be created. This means that an instance of this `IndirectActorProducer`
|
||||
* will be created in order to call this method during any call to
|
||||
* [[Props#actorClass]]; it should be noted that such calls may
|
||||
* performed during actor set-up before the actual actor’s instantiation, and
|
||||
* that the instance created for calling `actorClass` is not necessarily reused
|
||||
* later to produce the actor.
|
||||
*/
|
||||
def actorClass: Class[_ <: Actor]
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
private[akka] class UntypedActorFactoryConsumer(factory: UntypedActorFactory) extends IndirectActorProducer {
|
||||
override def actorClass = classOf[Actor]
|
||||
override def produce() = factory.create()
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
private[akka] class CreatorFunctionConsumer(creator: () ⇒ Actor) extends IndirectActorProducer {
|
||||
override def actorClass = classOf[Actor]
|
||||
override def produce() = creator()
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
private[akka] class CreatorConsumer(creator: Creator[Actor]) extends IndirectActorProducer {
|
||||
override def actorClass = classOf[Actor]
|
||||
override def produce() = creator.create()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue