having this generic DAO definition
#Repository
public class GenericService<T> implements IGenericService<T> {
#PersistenceContext(unitName="mgrUnit", name="mgrEMF")
#Qualifier(value = "mgrEMF")
public void setEm(EntityManager em) {
this.em = em;
util = em.getEntityManagerFactory().getPersistenceUnitUtil();
}
}
and having a large number of Entities, i want to automatiqualy instanciate DAO, Back-End Beans for basic tables like ( Region, EmployeSpeciality... )
For the bean registration and instantion it's easy but what about the DAO ?
I must precise that in my case the EntityManager depends on the service, i have a multiple Database connection.
i read this article but honnestly it looks to much complicated
http://doanduyhai.wordpress.com/2011/11/20/spring-transactional-explained/
Is there a simple way to do it ?
OK, using
AutowireCapableBeanFactory beanFactory =
FacesUtils.getWebappContext().getAutowireCapableBeanFactory();
beanFactory.autowireBean(obj);
It solve the half of the problem, the Bean EMF is correctly injected, but the bean is not registred (i must re-instanciate it every time i need), because the beanFactory doesnt contains the Bean Definition, so how to add it?
NB: i know that puting the object in the application MAP can keep the DAO accessible but its not a serious solution
FacesContext.getCurrentInstance().getExternalContext().
getApplicationMap().put( serviceName, service);
IGenericService service = (IGenericService) ContextManager.findBean( serviceName );
if (service==null && !FacesUtils.getWebappContext().getBeanFactory().
containsBeanDefinition(serviceName)){
service = new ErpGenericService(clazz);
AutowireCapableBeanFactory beanFactory = FacesUtils.getWebappContext().
getAutowireCapableBeanFactory();
beanFactory.autowireBean(service);
//Applying transactional proxies
service = (IGenericService) beanFactory.applyBeanPostProcessorsAfterInitialization(service, serviceName);
FacesUtils.getWebappContext().getBeanFactory().
registerSingleton(serviceName, service);
}
Related
please can somebody help me?
I have experience with JPA, but not so with Spring, that hides many aspects, that are visible in JPA (for example Hibernate implementation).
Often I was used to work in JPA in this mode (one global transaction) - I will try to explain on saving header (method_A) and its items (method_B) - with result in posting all or nothing. I would like to reach this effect via Spring persistence. I know, that method with #Transactional annotation gets the session from outside, if this exists. My problem is, that I think, that the nested implemented save() method of default Spring repository interface (CrudRepository for example) will open its own transaction anyway - and this is, what I don't want - simply I need to force this save() method to get it from outside. And so I am not sure, if only #Transactional annotation is enough to force this behavior.
This is my JPA code, that works properly in Hibernate:
root_method() {
Transaction tx = session.beginTransaction();
method_A(session);
tx.commit();
}
method_A(Session session) {
Header header = new Header();
session.save(header);
for (Item item : getJustAllocatedItems()) {
item.setHeader(header);
method_B(session, item);
}
}
method_B(Session session, Item item) {
session.save(item);
}
I am sorry, that this is not pure Java, but for explanation purposes I hope it is enough. I will try to mirror Spring code in brute form:
#Transactional
root_method() {
// ... root_method should make overal transaction frame on background (I suppose, that root_method is not called from another method with #Transactional ann.)
method_A();
}
#Transactional
method_A() {
Header header = new Header();
headerRepository.save(header);
for (Item item : getJustAllocatedItems()) {
item.setHeader(header);
method_B(item);
}
}
#Transactional
method_B(Item item) {
itemRepository.save(item);
}
... so I do not think, that save() methods of repositories (in both A and B method) will receive and use transaction from outside - am I right? - and if it is so, please can somebody interpret my JPA code from first part to appropriate Spring representation. Thanks so much.
If you call repository method without transaction, then repository
will create transaction:
Creating new transaction with name [org...SimpleJpaRepository.save]
Committing JPA transaction on EntityManager
If you use transactional annotation (Note that it should be in separate service), then save will reuse transaction:
Creating new transaction with name [com...HeaderService.createHeader]
Committing JPA transaction on EntityManager
Please note, mathods, annotated with #Transactional, should be in different classes (or you should autowire current class using setter). Then Spring will be able to use proxy. Spring wraps service with #Transactional annoaions into proxy.
Enable jpa logging:
logging.level.org.springframework.orm.jpa=DEBUG
logging.level.org.springframework.transaction=DEBUG
This is example implementation of your classes hierarcy:
#Service
#AllArgsConstructor
public class HeaderService {
HeaderRepository headerRepository;
ItemService itemService;
#Transactional
public void methodA() {
Header header = new Header();
headerRepository.save(header);
for (Item item : getJustAllocatedItems()) {
item.setHeader(header);
itemService.methodB(item);
}
}
}
#Service
#AllArgsConstructor
public class ItemService {
ItemRepository itemRepository;
#Transactional
void methodB(item) {
itemRepository.save(item);
}
}
public interface HeaderRepository extends CrudRepository<Header, Long> { }
public interface ItemRepository extends CrudRepository<Item, Long> { }
My question is :
let's assume that i have a spring bean : a DAO one (it's a singleton of course)
So, when we have lot of users who want to use this bean at the same time : what happens?
or,
for every user, spring instantiate a DAO bean for him?
==> we have a singleton by application Context : did spring create a context for every user?
(it's a singleton of course)
Then it's a singleton. The ApplicationContext will only create one instance and pass that same instance around wherever it's requested.
for every user, spring [instantiate] a DAO bean for him?
No, it will retrieve and give them the same DAO instance.
==> we have a singleton by application Context : did spring create a context for every user?
I'm not exactly sure what you mean for every user. A Java application has no knowledge of users. If you mean in the context of a multithreaded application, it's still irrelevant. The injected DAO bean will still be that single instance.
As stated in the comments, it's your responsibility to handle the state of your DAO, if it's mutable, handle concurrent access. Handle transactions (possibly with #Transactional) with the datasource.
You dont use DAOs as Spring beans. Spring beans (singleton scope) are more like a service.
Lets say you have a Pizza Dao, and a PizzaService, your Service is a spring bean, while pizza isnt.
class Pizza {
Set ingredients = ... ;
public Pizza(Set s) {
...
}
private addIngredient(Object o ) {
set.add...
}
}
#Service
class PizzaService {
private Pizza createPizza(..){
Pizza p = new Pizza();
....
return pizza;
}
private void persistPizza(Pizza pizza){
..save to db..
}
}
Test your service:
class JunitFoo{
#Autowired private PizzaService service;
#Test
someMethod(){
Pizza p = service.createPizza();
p.addIngredient(cheese)
service.persistPizza(p);
}
}
You can also implement Runnable in JunitFoo and launch someMethod a lot of time with differents threads (your User), every user will get its own Pizza. But all users use the same pizzaService.
Due to this reason singleton is default scope of a spring bean. You can also create a Pizza by fetching it from your application context, but in this case, you would need prototype otherwise all users share the same pizza
<bean id="pizza" class="foo.Pizza" scope="prototype" >
<default set of pizza stuff>
</bean>
If you do it that way, your PizzaService could look like this:
#Service
class PizzaService {
#Autowired private ApplicationContext context;
private Pizza createPizza(..){
return (Pizza) context.getBean("pizza");
}
private void persistPizza(Pizza pizza){
..save to db..
}
}
This topic is way to big to cover it in a single post, i hope i could help and improve your understanding. Please also check the spring documantation about bean scopes.
When I define my managed bean as a CDI bean (#Named) it is not shown by the ui:debug popup. If I change the definition to a JSF #ManagedBean it shows up in the scoped variables just fine.
Is there anything extra I need to do to make this work?
I am using Mojarra 2.1.
CDI managed beans are not stored as direct attributes of the request/session/application scope. They're abstracted away behind the CDI context, for which it's in turn implementation dependent (e.g. Weld vs OpenWebBeans vs others) how exactly they're referenced in the scope. The <ui:debug> doesn't offer any builtin facilities to display active CDI managed beans (yet?).
Your best bet is obtaining them manually. You can use the following utility method for that (which will be available in upcoming OmniFaces 1.7's Beans utility class):
public static Map<Object, String> getActiveReferences(BeanManager beanManager, Class<? extends Annotation> scope) {
Map<Object, String> activeReferences = new HashMap<Object, String>();
Set<Bean<?>> beans = beanManager.getBeans(Object.class);
Context context = beanManager.getContext(scope);
for (Bean<?> bean : beans) {
Object reference = context.get(bean);
if (reference != null) {
activeReferences.put(reference, bean.getName());
}
}
return Collections.unmodifiableMap(activeReferences);
}
Here's how you can use it:
#Inject
private BeanManager manager;
public void collect() {
Map<Object, String> requestScopedBeans = Beans.getActiveReferences(manager, RequestScoped.class);
// Map key represents the instance and map value represents the managed bean name, if any.
// ...
}
Keep in mind that this is a relatively expensive job. So really use it for debugging only.
I was wondering which one of the two solutions hereunder is the best practice?
Problem : I have a stateless session bean VehicleBean, I implemented a method with business logic and persistence of a Car with its wheels , their tires, etc.
#Stateless
class VehicleBean{
#PersistenceContext
private EntityManager em;
#EJB
Inspector inspectorBean;
#EJB
DocumentBean documentBean;
public void persistCar(){
Car car = new Car();
car.setMake("Ford");
em.persist(car);
documentBean.persistDocument(new Document(car));
for (int i = 0; i < 4; i++){
createWheel(car);
}
private void createWheel(Car car){
// some business logic
inspectorBean.inspect();
Wheel wheel = new Wheel();
wheel.setCar(car);
em.persist(wheel);
...
}
...
}
I have different private methods that are called after each other (1) create car, 2) create wheels, etc) and I would like to regroup all these methods in one helper class.
Solutions:
1) Make use of a helper class CarBuilder which contains all the private methods from my VehicleBean. As I can't use ejb injection, I want to pass it by reference to the constructor as following :
public void persistCar(){
new CarBuilder(this, document, inspectorBean);
}
class CarBuilder{
private VehiculeBean vehiculeBean;
...
CarBuilder(VehiculeBean,....){
this.vehiculeBean = vehiculeBean;
}
}
2) create CarBuilder as a stateless session bean and inject the bean in the VehiculeBean.
Do you see any advantage using the 2)? So having a lot of different beans like CarBuilder, MotorcyleBuilder, etc managed by the container.
Passing references to container managed objects in constructors will decrease readability of the code (IMO). Code becomes a lot clearer if you create container managed resources with dependency injection.
Let the helper classes work with the entities instead and create a new EJB when you want to break out bussiness logic in another class.
I am having a series of odd errors in testing and deployment. They seem to indicate that some of my beans are not loading into the context, despite them being defined in applicationContext.xml.
Is there any way to check during testing which beans have actually been loaded? Or to find a complete list of beans loaded at run time?
Thanks,
b
At startup, Spring logs at info level the names of all the beans being loaded by a context. Or in code, you can use getBeanDefinitionNames() to get all the bean names.
if there is more than one context say if you are using spring mvc you can use something more powerful like this.
public class SampleContextApplicationListener implements ApplicationListener<ApplicationContextEvent> {
private Map<String,ApplicationContext> contextMap = new Hashtable<String,ApplicationContext>();
#Override
public void onApplicationEvent(ApplicationContextEvent event) {
if( event instanceof ContextStartedEvent || event instanceof ContextRefreshedEvent){
this.getContextMap().put(event.getApplicationContext().getDisplayName(), event.getApplicationContext());
}
}
public Map<String,ApplicationContext> getContextMap() {
return contextMap;
}
}
You can then inject the listener where it is needed, and extract the map of contextens and then interogate it for all its bean, using the getBeanDefinitionNames()
#Autowired
private StatusTestsApplicationListener listener;