managedproperty - Integración Spring JSF: ¿cómo inyectar un componente/servicio Spring en un bean gestionado JSF?
@managedproperty (3)
@Controller
vs @Controller
En primer lugar, debe elegir un marco para administrar sus granos. Debe elegir JSF o Spring (o CDI) para administrar sus beans. Mientras que el siguiente funciona, es fundamentalmente incorrecto:
@ManagedBean // JSF-managed.
@Controller // Spring-managed.
public class BadBean {}
Usted termina con dos instancias completamente separadas de la misma clase de bean administrado, una administrada por JSF y otra administrada por Spring. No está claro cuál se usará realmente en EL cuando lo referencia como #{someBean}
. Si tiene SpringBeanFacesELResolver
registrado en faces-config.xml
, entonces será el administrado por Spring, no el manejado por JSF. Si no tienes eso, entonces sería el administrado por JSF.
Además, cuando declara un ámbito específico de bean gestionado JSF, como @RequestScoped
, @ViewScoped
, @SessionScoped
o @ApplicationScoped
del paquete javax.faces.*
, Solo será reconocido y utilizado por @ManagedBean
. No será entendido por @Controller
ya que espera su propia anotación @Scope
. Esto está predeterminado en singleton (ámbito de aplicación) cuando está ausente.
@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
@Controller // Spring-managed (without own scope, so actually becomes a singleton).
public class BadBean {}
Cuando hace referencia al bean anterior a través de #{someBean}
, devolverá el bean con ámbito administrado por Spring, no el bean con ámbito de vista administrado por JSF.
@Autowired
vs. @Autowired
La @ManagedProperty específica de JSF solo funciona en beans administrados por JSF, es decir, cuando usa @ManagedBean
. El @Autowired
específico de @Autowired
funciona solo en beans gestionados por Spring, es decir, cuando usa @Controller
. Los enfoques a continuación son menos o más equivalentes y no se pueden combinar:
@ManagedBean // JSF-managed.
@RequestScoped // JSF-managed scope.
public class GoodBean {
@ManagedProperty("#{springBeanName}")
private SpringBeanClass springBeanName; // Setter required.
}
@Component // Spring-managed.
@Scope("request") // Spring-managed scope.
public class GoodBean {
@Autowired
private SpringBeanClass springBeanName; // No setter required.
}
Tenga en cuenta que cuando tiene SpringBeanFacesELResolver
registrado en faces-config.xml
según el SpringBeanFacesELResolver ,
<application>
...
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
y por lo tanto, puede hacer referencia a los beans administrados por Spring en EL a través de #{springBeanName}
, luego también puede hacer referencia a ellos en @ManagedProperty
, ya que básicamente establece el resultado evaluado de la expresión EL dada. A la inversa, inyectar un bean gestionado JSF a través de @Autowired
, de ninguna manera es compatible. Sin embargo, puede utilizar @Autowired
en un bean administrado JSF cuando registra manualmente la instancia de bean administrada JSF en el contexto autowirable de Spring como se muestra a continuación. Vea también Cómo integrar JSF 2 y Spring 3 (o Spring 4) muy bien para el truco.
@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
public class GoodBean implements Serializable {
@Autowired
private SpringBeanClass springBeanName; // No setter required.
@PostConstruct
private void init() {
FacesContextUtils
.getRequiredWebApplicationContext(FacesContext.getCurrentInstance())
.getAutowireCapableBeanFactory().autowireBean(this);
// springBeanName is now available.
}
}
@XxxScoped
vs @Scope
Spring @Scope
tiene soporte limitado para los ámbitos JSF. No hay un equivalente para @ViewScoped
de JSF. Básicamente, harías homegrow tus propios ámbitos, o te apegarías al registro manual de la instancia de bean administrada JSF en el contexto autowirable de Spring, como se muestra arriba.
Y, desde el otro lado, Spring WebFlow fue asumido en JSF 2.2 a través de la nueva anotación @FlowScoped
. Entonces, si ya está en JSF 2.2, no necesariamente necesita usar Spring WebFlow si solo desea el alcance del flujo.
CDI - tratando de unificarlo todo
Desde Java EE 6, CDI se ofrece como alternativa estándar a Spring DI. Tiene anotaciones respectivamente @Named
e @Inject
para esto y también su propio conjunto de ámbitos. No estoy seguro de cómo interactúa con Spring ya que no utilizo Spring, pero @Inject
funciona dentro de @Inject
, y @ManagedProperty
dentro de @ManagedBean
puede hacer referencia a un bean @Named
. Por otro lado, @ManagedProperty
no funciona dentro de un bean @Named
.
El objetivo de CDI es unificar todos los diferentes marcos de gestión de beans en una sola especificación / interfaz. Spring podría haber sido una implementación completa de CDI, pero eligieron implementarlo solo parcialmente (solo se javax.inject.*
JSR-330 javax.inject.*
, Pero JSR-299 javax.enterprise.context.*
No). Ver también ¿Will Spring es compatible con CDI? y este tutorial
JSF se mudará a CDI para la administración de frijoles y depreciará @ManagedBean
y sus amigos en una versión futura.
Ver también:
Entiendo que un bean administrado funciona como un controlador, porque su única tarea es "vincular" la capa de vista con el modelo.
Para usar un bean como un bean administrado, debo declarar la anotación @ManagedBean
, haciendo eso puedo comunicar JSF con bean directamente.
Si quiero inyectar algún componente (desde Spring) en este managedBean, tengo dos formas posibles:
Elija la propiedad en ManagedBean (como "BasicDAO dao") y declare
@ManagedProperty(#{"basicDAO"})
sobre la propiedad. Al hacerlo, inyectaré el bean"basicDAO"
de Spring en ManagedBean.Declarado @Controller en ManagedBean Class, entonces tendré
@Controller
y@Controller
anotaciones, todas juntas. Y en la propiedad"BasicDAO dao"
debo usar@Autowired
de Spring.
Es mi entendimiento correcto?
Hay otra manera de usar beans administrados por Spring en beans administrados por JSF simplemente extendiendo su bean JSF desde SpringBeanAutowiringSupport
y Spring manejará la inyección de dependencia.
@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
public class GoodBean extends SpringBeanAutowiringSupport {
@Autowired
private SpringBeanClass springBeanName; // No setter required.
// springBeanName is now available.
}
La forma más fácil de hacerlo es a través de XML. @Component
en @Component
administrados @Component
ya creados, pero @Autowired
no funcionó porque el bean administrado ya estaba allí en faces-config.xml. Si es obligatorio mantener esa definición de beans administrados junto con su propiedad administrada en el archivo xml, se sugiere agregar el bean de primavera como otra propiedad administrada dentro de la etiqueta de bean administrada. Aquí el bean de primavera está definido allí en spring-config.xml (se puede autoconectar en algún lugar de forma alternativa). Por favor, consulte https://.com/a/19904591/5620851
editado por mí. Sugiero implementarlo completamente a través de la anotación @Managed y @Component o vía xml para ambos.