Solución:
Estas son dos preguntas no relacionadas:
¿Son seguros los hilos de los frijoles de primavera?
No.
Spring tiene diferentes alcances de frijol (por ejemplo, Prototype, Singleton, etc.) pero todos estos alcances se aplican cuando se crea el frijol. Por ejemplo, se creará un bean con ámbito “prototipo” cada vez que se “inyecte” este bean, mientras que un bean con ámbito “singleton” se creará una vez y se compartirá dentro del contexto de la aplicación. Hay otros ámbitos, pero solo definen un período de tiempo (por ejemplo, un “ámbito”) de cuando se creará una nueva instancia.
Lo anterior tiene poco, si es que tiene algo que ver con ser seguro para subprocesos, ya que si varios subprocesos tienen acceso a un bean (sin importar el alcance), solo dependería del diseño de ese bean sea o no “seguro para subprocesos”.
La razón por la que dije “poco, si acaso” es porque podría depender del problema que está tratando de resolver. Por ejemplo, si le preocupa si 2 o más solicitudes HTTP pueden crear un problema para el mismo bean, hay un alcance de “solicitud” que creará una nueva instancia de un bean para cada solicitud HTTP, por lo tanto, puede “pensar” en un bean particular como “seguro” en el contexto de múltiples solicitudes HTTP. Pero todavía no es realmente seguro para subprocesos. por primavera ya que si varios subprocesos usan este bean dentro lo mismo Solicitud HTTP, vuelve a un diseño de bean (tu diseño de una clase de respaldo de frijol).
¿Cómo hacer / diseñar un “objeto” seguro para subprocesos?
Hay varias formas, probablemente demasiado largas para enumerarlas aquí, pero aquí hay algunos ejemplos:
-
Diseña tus frijoles inmutable: por ejemplo, no tiene establecedores y solo usa argumentos de constructor para crear un bean. Hay otras formas, como el patrón de constructor, etc.
-
Diseña tus frijoles apátrida: por ejemplo un frijol que lo hace algo puede ser solo una función (o varias). Este frijol en la mayoría de los casos puede y deberían ser apátrida, lo que significa que no tiene ningún estado, solo lo hace cosas con argumentos de función que proporciona cada vez (en cada invocación)
-
Diseña tus frijoles persistente: que es un caso especial de “inmutable”, pero tiene algunas propiedades muy agradables. Por lo general, se usa en programación funcional, donde Spring (al menos todavía) no es tan útil como en el mundo imperativo, pero los he usado con proyectos Scala / Spring.
-
Diseña tus frijoles con candados [last resort]: Recomendaría no hacerlo a menos que esté trabajando en un más bajo biblioteca de nivel. La razón es que nosotros (los humanos) no pensamos bien en términos de cerraduras. De la misma forma en que nos crían y nos crían. Todo sucede en paralelo sin que tengamos que “poner la lluvia en pausa, déjame coger un paraguas”. Sin embargo, las computadoras tienen que ver con bloqueos cuando se habla de “varias cosas al mismo tiempo”, por lo que hay algunos de nosotros (personas excepcionales) que estamos haciendo lo que les corresponde e implementando bibliotecas basadas en estos bloqueos. La mayoría de los demás humanos pueden simplemente usar estas bibliotecas y no se preocupe por la concurrencia.
Spring no garantiza la seguridad del hilo. Pero proporciona pautas al respecto. Si sus frijoles tienen estado, no utilice el alcance del frijol singleton.
Creé una demostración para mostrar la mutabilidad de los frijoles de primavera con alcance Singleton y Prototype
Me concentré en los beans con estado, luego usé los ámbitos Singleton y Prototype para mostrar cómo los beans mutan su estado.
La clase Job se amplía con los beans JobPrototype y JobSingleton que se cargan en función del conjunto de perfiles activos. Tp set profile, establezca la propiedad spring.profiles.active en proto (para el alcance del prototipo) o singleton (para el alcance Singleton)
Los beans de trabajo activos son Autowired
dentro de los beans Runner y Runner1 que tienen métodos programados para mutar el estado del Autowired
frijol periódicamente
public class Job {
protected int count = 0;
void counter() {
this.count++;
}
public int getCount() {
return count;
}
}
@Component
@Profile("proto")
@Scope("prototype")
public class JobPrototype extends Job {
}
@Component
@Profile("singleton")
public class JobSingleton extends Job {
}
@Component
public class Runner {
private Logger Log = LoggerFactory.getLogger(this.getClass().getName());
@Autowired
private Job job;
@Scheduled(fixedDelay = 1500)
void count() {
this.job.counter();
Log.info("### Runner: count: " + this.job.getCount());
}
}
@Component
public class Runner1 {
private Logger Log = LoggerFactory.getLogger(this.getClass().getName());
@Autowired
private Job job;
@Scheduled(fixedDelay = 1000)
void count() {
this.job.counter();
Log.info("### RunnerOne: count: " + this.job.getCount());
}
}
Los resultados son
-
Alcance Singleton Singleton
-
Prototipo Alcance del prototipo
Código completo para esta demostración beans_mutability